feat(catalog): Visual Manager for Builder Club with honest canEdit
Mount BC Visual Manager, thread catalogType through tree/editor actions, and stop hardcoding canEdit=true in items/translate tabs. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
8ccade73cc
commit
7d50b72ade
8 files changed
+457
-151
No files matched your search
@@ -25,6 +25,11 @@ import {
|
||||
reorderTreePage,
|
||||
toggleCatalogPage,
|
||||
} from "@/actions/catalog";
|
||||
import {
|
||||
deleteBcTreePage,
|
||||
reorderBcTreePage,
|
||||
toggleBcPage,
|
||||
} from "@/actions/catalog-bc";
|
||||
import { useConfirmDialog } from "@/components/admin/confirm-dialog";
|
||||
import { CatalogIcon } from "@/components/admin/catalog-tree";
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -36,6 +41,7 @@ import {
|
||||
ContextMenuTrigger,
|
||||
} from "@/components/ui/context-menu";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useCatalogManager } from "./use-catalog-store";
|
||||
|
||||
export type { RootTab } from "@/types/catalog";
|
||||
|
||||
@@ -58,6 +64,7 @@ export function RootTabs({
|
||||
onCreateRoot,
|
||||
loading,
|
||||
}: RootTabsProps) {
|
||||
const { catalogType, canEdit } = useCatalogManager();
|
||||
const { confirm, dialog: confirmDialog } = useConfirmDialog();
|
||||
const [activeDragId, setActiveDragId] = useState<number | null>(null);
|
||||
const sensors = useSensors(
|
||||
@@ -78,13 +85,16 @@ export function RootTabs({
|
||||
const newIndex = tabs.findIndex((t) => t.id === over.id);
|
||||
if (oldIndex === -1 || newIndex === -1) return;
|
||||
|
||||
if (!canEdit) return;
|
||||
const newOrder = arrayMove(tabs, oldIndex, newIndex);
|
||||
|
||||
// Batch reorder
|
||||
try {
|
||||
const reorder =
|
||||
catalogType === "bc" ? reorderBcTreePage : reorderTreePage;
|
||||
const results = await Promise.allSettled(
|
||||
newOrder.map((tab, idx) =>
|
||||
reorderTreePage({ pageId: tab.id, newOrderNum: idx + 1 }),
|
||||
reorder({ pageId: tab.id, newOrderNum: idx + 1 }),
|
||||
),
|
||||
);
|
||||
const failed = results.filter((r) => r.status === "rejected").length;
|
||||
@@ -94,12 +104,17 @@ export function RootTabs({
|
||||
toast.error("Failed to reorder tabs");
|
||||
}
|
||||
},
|
||||
[tabs],
|
||||
[tabs, canEdit, catalogType],
|
||||
);
|
||||
|
||||
const handleToggle = async (tab: RootTab) => {
|
||||
if (!canEdit) return;
|
||||
try {
|
||||
await toggleCatalogPage({ id: tab.id, action: "toggleEnabled" });
|
||||
if (catalogType === "bc") {
|
||||
await toggleBcPage({ id: tab.id, field: "enabled" });
|
||||
} else {
|
||||
await toggleCatalogPage({ id: tab.id, action: "toggleEnabled" });
|
||||
}
|
||||
toast.success(
|
||||
`${tab.caption} ${tab.enabled === "1" ? "disabled" : "enabled"}`,
|
||||
);
|
||||
@@ -109,6 +124,7 @@ export function RootTabs({
|
||||
};
|
||||
|
||||
const handleDelete = async (tab: RootTab) => {
|
||||
if (!canEdit) return;
|
||||
const ok = await confirm({
|
||||
title: "Delete root page",
|
||||
description: `Delete root page "${tab.caption}"? Children will be reparented.`,
|
||||
@@ -116,7 +132,11 @@ export function RootTabs({
|
||||
});
|
||||
if (!ok) return;
|
||||
try {
|
||||
await deleteTreePage({ pageId: tab.id, mode: "reparent" });
|
||||
if (catalogType === "bc") {
|
||||
await deleteBcTreePage({ pageId: tab.id, mode: "reparent" });
|
||||
} else {
|
||||
await deleteTreePage({ pageId: tab.id, mode: "reparent" });
|
||||
}
|
||||
toast.success(`"${tab.caption}" deleted`);
|
||||
} catch {
|
||||
toast.error("Failed to delete");
|
||||
@@ -168,16 +188,18 @@ export function RootTabs({
|
||||
)}
|
||||
</DragOverlay>
|
||||
</DndContext>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-7 w-7 shrink-0 ml-1"
|
||||
title="New root page"
|
||||
onClick={onCreateRoot}
|
||||
>
|
||||
<Plus className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
{canEdit && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-7 w-7 shrink-0 ml-1"
|
||||
title="New root page"
|
||||
onClick={onCreateRoot}
|
||||
>
|
||||
<Plus className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user