diff --git a/app/srv/ws/sync/actions.ts b/app/srv/ws/sync/actions.ts index f95e02fc..ebfa63a0 100644 --- a/app/srv/ws/sync/actions.ts +++ b/app/srv/ws/sync/actions.ts @@ -5,6 +5,7 @@ import { ESite, } from "../../../web/src/render/ed/logic/ed-global"; import { IItem } from "../../../web/src/utils/types/item"; +import { site_group } from "./actions/site_group"; /* WARNING: @@ -19,7 +20,7 @@ export const SyncActions = { site: { list: async () => ({}) as Record, - group: async () => ({}) as Record, + group: async () => ({}) as ReturnType, load: async (id: string) => ({}) as ESite | void, }, comp: { diff --git a/app/srv/ws/sync/actions/site_group.ts b/app/srv/ws/sync/actions/site_group.ts index 6da7936b..c195ade4 100644 --- a/app/srv/ws/sync/actions/site_group.ts +++ b/app/srv/ws/sync/actions/site_group.ts @@ -1,5 +1,23 @@ import { SyncConnection } from "../type"; export const site_group = async function (this: SyncConnection) { - return "gruop"; + const res = db.org.findMany({ + where: { + org_user: { some: { id_user: this.user_id } }, + }, + select: { + id: true, + org_user: { select: { user: { select: { id: true, username: true } } } }, + name: true, + site: { + select: { + id: true, + name: true, + domain: true, + }, + }, + }, + }); + + return res; }; diff --git a/app/web/src/render/ed/logic/ed-global.ts b/app/web/src/render/ed/logic/ed-global.ts index eec7e3e3..28c45389 100644 --- a/app/web/src/render/ed/logic/ed-global.ts +++ b/app/web/src/render/ed/logic/ed-global.ts @@ -62,6 +62,7 @@ export type EdMeta = { }; export const EDGlobal = { + user: { id: "", username: "" }, status: "init" as | "init" | "loading" diff --git a/app/web/src/render/ed/logic/ed-sync.tsx b/app/web/src/render/ed/logic/ed-sync.tsx index dad9bf9b..4988f6d5 100644 --- a/app/web/src/render/ed/logic/ed-sync.tsx +++ b/app/web/src/render/ed/logic/ed-sync.tsx @@ -9,11 +9,13 @@ import { w } from "../../../utils/types/general"; export const edInitSync = (p: PG) => { const session = JSON.parse( localStorage.getItem("prasi-session") || "null" - ) as { data: { user: { id: string } } }; + ) as { data: { user: { id: string; username: string } } }; if (!session) { navigate("/login"); return ; } + p.user.id = session.data.user.id; + p.user.username = session.data.user.username; if (!p.sync) { clientStartSync({ diff --git a/app/web/src/render/ed/panel/popup/site.tsx b/app/web/src/render/ed/panel/popup/site.tsx index f64868ac..77cc6859 100644 --- a/app/web/src/render/ed/panel/popup/site.tsx +++ b/app/web/src/render/ed/panel/popup/site.tsx @@ -1,9 +1,93 @@ -import { useGlobal } from "web-utils"; -import { EDGlobal } from "../../logic/ed-global"; +import { + MultiBackend, + NodeModel, + Tree, + getBackendOptions, +} from "@minoru/react-dnd-treeview"; +import { useEffect } from "react"; +import { DndProvider } from "react-dnd"; +import { useGlobal, useLocal } from "web-utils"; +import { Loading } from "../../../../utils/ui/loading"; import { Modal } from "../../../../utils/ui/modal"; +import { EDGlobal } from "../../logic/ed-global"; + +type GItem = { + id: string; + name: string; +} & ( + | { + type: "group"; + users: { id: string; username: string }[]; + } + | { type: "site"; domain: string } +); export const EdPopSite = () => { const p = useGlobal(EDGlobal, "EDITOR"); + const local = useLocal( + { + status: "init" as "init" | "loading" | "ready", + group: [] as NodeModel[], + }, + () => { + p.ui.popup.site = () => {}; + p.render(); + } + ); + useEffect(() => { + if (p.ui.popup.site && local.status !== "loading") { + (async () => { + local.status = "loading"; + local.render(); + + const res = await p.sync.site.group(); + + const group: NodeModel[] = []; + for (const item of res) { + group.push({ + id: item.id, + parent: "site-root", + text: item.name, + data: { + id: item.id, + type: "group", + name: item.name, + users: item.org_user.map((e) => ({ + id: e.user.id, + username: e.user.username, + })), + }, + }); + + for (const site of item.site) { + group.push({ + id: site.id, + parent: item.id, + text: site.name, + droppable: false, + data: { + id: site.id, + type: "site", + name: site.name, + domain: site.domain, + }, + }); + } + + group.push({ + id: `new-${item.id}`, + parent: item.id, + text: "new", + droppable: false, + }); + } + local.group = group; + + local.status = "ready"; + local.render(); + })(); + } + }, [p.ui.popup.site]); if (!p.ui.popup.site) return null; @@ -17,7 +101,167 @@ export const EdPopSite = () => { } }} > -
Haloha
+
+
+ {local.status === "loading" ? ( + + ) : ( + + )} +
+
); }; + +const SitePicker = ({ group }: { group: NodeModel[] }) => { + const p = useGlobal(EDGlobal, "EDITOR"); + const TypedTree = Tree; + const orglen = group.filter((e) => e.parent === "site-root").length; + return ( +
+
+
+ {orglen} Organization{orglen > 1 ? "s" : ""} +
+
{ + const neworg = prompt("New Organization Name"); + if (neworg) { + const res = await db.org.create({ + data: { + name: neworg, + org_user: { + create: { id_user: p.user.id, role: "owner" }, + }, + }, + }); + console.log(res); + } + }} + > +
`, + }} + >
+
New
+
+
+ + + {}} + initialOpen={true} + canDrag={(node) => { + if (node && node?.data?.type === "site") return true; + return false; + }} + canDrop={(_, { dragSource, dropTarget }) => { + if (dragSource?.parent === dropTarget?.id) return false; + return true; + }} + sort={(a, b) => { + if (a.text === "new") return 1; + if (b.text === "new") return -1; + return a.text > b.text ? 1 : -1; + }} + dragPreviewRender={() => <>} + classes={{ + root: cx( + "flex flex-1 flex-col items-stretch overflow-auto", + css` + flex-wrap: nowrap; + background: white; + ` + ), + container: "flex flex-row flex-wrap pb-2", + }} + render={( + node, + { depth, isOpen, onToggle, isDropTarget, isDragging } + ) => { + const item = node.data; + + if (node.text === "new") { + return ( +
+
+
`, + }} + >
+
New Site
+
+
+ ); + } + + if (!item) return <>; + if (item.type === "group") { + return ( +
+
{node.text}
+
+ Team: {item.users.length} user + {item.users.length > 1 ? "s" : ""} +
+ {isDropTarget && ( +
+ Drop to move here... +
+ )} +
+ ); + } + + return ( +
+
+
{item.name}
+
+ `, + }} + > +
{item.domain}
+
+
+ +
+ EDIT +
+
+ ); + }} + /> +
+
+ ); +}; diff --git a/app/web/src/render/ed/panel/tree/body.tsx b/app/web/src/render/ed/panel/tree/body.tsx index e35bfa6d..5abc2f2c 100644 --- a/app/web/src/render/ed/panel/tree/body.tsx +++ b/app/web/src/render/ed/panel/tree/body.tsx @@ -57,6 +57,7 @@ export const EdTreeBody = () => { render={nodeRender} onDrop={nodeOnDrop} canDrop={(_, args) => { + if (!args.dragSource?.data?.item) return false; return canDrop(p, args); }} dragPreviewRender={DragPreview} diff --git a/app/web/src/render/live/logic/route.ts b/app/web/src/render/live/logic/route.ts index 1e0466fb..bd3b3804 100644 --- a/app/web/src/render/live/logic/route.ts +++ b/app/web/src/render/live/logic/route.ts @@ -6,7 +6,7 @@ import { rebuildTree } from "./tree-logic"; export const routeLive = (p: PG, pathname: string) => { if (p.status !== "loading" && p.status !== "not-found") { - let page_id = params.page_id; + let page_id = w.params.page_id; if (!page_id) { const found = p.route.lookup(pathname);