mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-11-26 23:27:14 +03:00
fix (kind of) app ordering in dock
This commit is contained in:
parent
b5aeac5b1a
commit
6f646712c8
@ -121,6 +121,7 @@ fn init(our: Address) {
|
||||
|
||||
bind_http_path("/apps", true, false).expect("failed to bind /apps");
|
||||
bind_http_path("/favorite", true, false).expect("failed to bind /favorite");
|
||||
bind_http_path("/order", true, false).expect("failed to bind /order");
|
||||
|
||||
loop {
|
||||
let Ok(ref message) = await_message() else {
|
||||
@ -200,8 +201,6 @@ fn init(our: Address) {
|
||||
);
|
||||
continue;
|
||||
};
|
||||
// POST of a list of package names.
|
||||
// go through the list and update each app in app_data to have the index of its name in the list as its order
|
||||
let Some(body) = get_blob() else {
|
||||
send_response(
|
||||
StatusCode::BAD_REQUEST,
|
||||
@ -211,7 +210,7 @@ fn init(our: Address) {
|
||||
continue;
|
||||
};
|
||||
let Ok(favorite_toggle) =
|
||||
serde_json::from_slice::<(String, u32, bool)>(&body.bytes)
|
||||
serde_json::from_slice::<(String, bool)>(&body.bytes)
|
||||
else {
|
||||
send_response(
|
||||
StatusCode::BAD_REQUEST,
|
||||
@ -221,8 +220,7 @@ fn init(our: Address) {
|
||||
continue;
|
||||
};
|
||||
if let Some(app) = app_data.get_mut(&favorite_toggle.0) {
|
||||
app.order = favorite_toggle.1;
|
||||
app.favorite = favorite_toggle.2;
|
||||
app.favorite = favorite_toggle.1;
|
||||
}
|
||||
send_response(
|
||||
StatusCode::OK,
|
||||
@ -233,6 +231,40 @@ fn init(our: Address) {
|
||||
vec![],
|
||||
);
|
||||
}
|
||||
"/order" => {
|
||||
let Ok(Method::POST) = incoming.method() else {
|
||||
send_response(
|
||||
StatusCode::BAD_REQUEST,
|
||||
Some(HashMap::new()),
|
||||
vec![],
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let Some(body) = get_blob() else {
|
||||
send_response(
|
||||
StatusCode::BAD_REQUEST,
|
||||
Some(HashMap::new()),
|
||||
vec![],
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let Ok(order_list) =
|
||||
serde_json::from_slice::<Vec<(String, u32)>>(&body.bytes)
|
||||
else {
|
||||
send_response(
|
||||
StatusCode::BAD_REQUEST,
|
||||
Some(HashMap::new()),
|
||||
vec![],
|
||||
);
|
||||
continue;
|
||||
};
|
||||
for (app_id, order) in order_list {
|
||||
if let Some(app) = app_data.get_mut(&app_id) {
|
||||
app.order = order;
|
||||
}
|
||||
}
|
||||
send_response(StatusCode::OK, Some(HashMap::new()), vec![]);
|
||||
}
|
||||
_ => {
|
||||
send_response(StatusCode::NOT_FOUND, Some(HashMap::new()), vec![]);
|
||||
}
|
||||
|
@ -26,9 +26,9 @@ const AppDisplay: React.FC<AppDisplayProps> = ({ app }) => {
|
||||
{app?.path && isHovered && <button className="app-fave-button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
fetch(`/favorite`, {
|
||||
fetch('/favorite', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify([app?.id, app?.order, !app?.favorite])
|
||||
body: JSON.stringify([app?.id, !app?.favorite])
|
||||
}).then(() => {
|
||||
fetch('/apps', { credentials: 'include' }).then(res => res.json()).catch(() => [])
|
||||
.then(setApps)
|
||||
|
@ -1,56 +1,53 @@
|
||||
import useHomepageStore, { HomepageApp } from "../store/homepageStore"
|
||||
import usePersistentStore from "../store/persistentStore"
|
||||
import AppDisplay from "./AppDisplay"
|
||||
import { useEffect, useState } from "react"
|
||||
import { DragDropContext, Draggable, DropResult, Droppable } from '@hello-pangea/dnd'
|
||||
|
||||
const AppsDock: React.FC = () => {
|
||||
const { apps, setApps } = useHomepageStore()
|
||||
const { apps } = useHomepageStore()
|
||||
const { appOrder, setAppOrder } = usePersistentStore()
|
||||
const [dockedApps, setDockedApps] = useState<HomepageApp[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
const orderedApps = apps
|
||||
.filter(a => a.favorite)
|
||||
.sort((a, b) => (a.order - b.order))
|
||||
// Sort apps based on persisted order
|
||||
const orderedApps = apps.filter(app => app.favorite).sort((a, b) => {
|
||||
return appOrder.indexOf(a.id) - appOrder.indexOf(b.id);
|
||||
});
|
||||
setDockedApps(orderedApps);
|
||||
|
||||
setDockedApps(orderedApps)
|
||||
}, [apps])
|
||||
|
||||
// a little function to help us with reordering the result
|
||||
const reorder = (list: HomepageApp[], startIndex: number, endIndex: number) => {
|
||||
const result = Array.from(list);
|
||||
const [removed] = result.splice(startIndex, 1);
|
||||
result.splice(endIndex, 0, removed);
|
||||
|
||||
removed.order = endIndex
|
||||
|
||||
return removed;
|
||||
};
|
||||
|
||||
const onDragEnd = (result: DropResult) => {
|
||||
// dropped outside the list
|
||||
if (!result.destination) {
|
||||
return;
|
||||
}
|
||||
|
||||
const app = reorder(
|
||||
dockedApps,
|
||||
result.source.index,
|
||||
result.destination.index
|
||||
);
|
||||
|
||||
fetch('/favorite', {
|
||||
// Sync the order with the backend
|
||||
fetch('/order', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify([app.id, app.order, app.favorite])
|
||||
})
|
||||
.catch(e => console.error(e))
|
||||
.then(() => {
|
||||
fetch('/apps', { credentials: 'include' }).then(res => res.json()).catch(() => [])
|
||||
.then(setApps)
|
||||
});
|
||||
body: JSON.stringify(orderedApps.map(app => [app.id, appOrder.indexOf(app.id)]))
|
||||
});
|
||||
}, [apps, appOrder])
|
||||
|
||||
const onDragEnd = (result: DropResult) => {
|
||||
if (!result.destination) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reorderedApps = Array.from(dockedApps);
|
||||
const [reorderedItem] = reorderedApps.splice(result.source.index, 1);
|
||||
reorderedApps.splice(result.destination.index, 0, reorderedItem);
|
||||
|
||||
const newAppOrder = reorderedApps.map(app => app.id);
|
||||
setAppOrder(newAppOrder);
|
||||
setDockedApps(reorderedApps);
|
||||
|
||||
fetch('/order', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(reorderedApps.map((app, index) => [app.id, index]))
|
||||
});
|
||||
}
|
||||
|
||||
return <DragDropContext onDragEnd={onDragEnd}>
|
||||
@ -60,10 +57,10 @@ const AppsDock: React.FC = () => {
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
>
|
||||
{dockedApps.map(app => <Draggable
|
||||
{dockedApps.map((app, index) => <Draggable
|
||||
key={app.id}
|
||||
draggableId={app.id}
|
||||
index={dockedApps.indexOf(app)}
|
||||
index={index}
|
||||
>
|
||||
{(provided, _snapshot) => (
|
||||
<div
|
||||
|
@ -21,10 +21,14 @@ header h1 {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.kino-bird {
|
||||
filter: light-dark(invert(1), invert(0));
|
||||
@media (prefers-color-scheme: light) {
|
||||
.kino-bird {
|
||||
filter: invert(1);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {}
|
||||
|
||||
[data-rfd-droppable-context-id] {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@ -34,7 +38,6 @@ header h1 {
|
||||
background-color: #4f000085;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
width: fit-content;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ export interface PersistentStore {
|
||||
setWidgetSettings: (widgetSettings: PersistentStore['widgetSettings']) => void
|
||||
toggleWidgetVisibility: (package_id: string) => void
|
||||
setWidgetSize: (package_id: string, size: 'small' | 'large') => void,
|
||||
appOrder: string[]
|
||||
setAppOrder: (appOrder: string[]) => void
|
||||
}
|
||||
|
||||
const usePersistentStore = create<PersistentStore>()(
|
||||
@ -46,6 +48,8 @@ const usePersistentStore = create<PersistentStore>()(
|
||||
}
|
||||
})
|
||||
},
|
||||
appOrder: [],
|
||||
setAppOrder: (appOrder: string[]) => set({ appOrder }),
|
||||
}),
|
||||
{
|
||||
name: 'homepage_persistent_store', // unique name for the store
|
||||
|
Loading…
Reference in New Issue
Block a user