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:
SimoandCursor committed 2026-07-18 21:03:07 +02:00
1 parent 8ccade73cc
commit 7d50b72ade
8 files changed
+457 -151

No files matched your search

File diff suppressed because it is too large. Load diff
+15
View File
@@ -208,6 +208,19 @@ export default async function CatalogPagesPage({
</p>
<div className="flex items-center gap-2">
<CatalogViewToggle currentView={viewMode} catalogType="bc" />
{canEdit && (
<CatalogManagerDialog
catalogType="bc"
canEdit={canEdit}
initialRoots={bcRootPages.map((p) => ({
id: p.id,
caption: p.caption,
iconImage: p.iconImage,
enabled: p.enabled,
orderNum: 0,
}))}
/>
)}
{canEdit && <CatalogActions catalogType="bc" />}
</div>
</div>
@@ -383,6 +396,8 @@ export default async function CatalogPagesPage({
<CatalogViewToggle currentView={viewMode} catalogType="normal" />
{canEdit && (
<CatalogManagerDialog
catalogType="normal"
canEdit={canEdit}
initialRoots={rootPages.map((p) => ({
id: p.id,
caption: p.caption,
@@ -5,8 +5,9 @@ import { Fragment, useEffect } from "react";
import { useCatalogManager } from "./use-catalog-store";
export function BreadcrumbBar() {
const { state, dispatch } = useCatalogManager();
const { state, dispatch, catalogType } = useCatalogManager();
const { selectedPageId, ancestors } = state;
const catQs = catalogType === "bc" ? "&catalog=bc" : "";
useEffect(() => {
if (!selectedPageId || selectedPageId <= 0) {
@@ -14,7 +15,7 @@ export function BreadcrumbBar() {
return;
}
const ac = new AbortController();
fetch(`/api/admin/catalog/tree?ancestors=${selectedPageId}`, {
fetch(`/api/admin/catalog/tree?ancestors=${selectedPageId}${catQs}`, {
signal: ac.signal,
})
.then((r) => r.json())
@@ -25,7 +26,7 @@ export function BreadcrumbBar() {
})
.catch(() => {});
return () => ac.abort();
}, [selectedPageId, dispatch]);
}, [selectedPageId, dispatch, catQs]);
if (!selectedPageId || ancestors.length === 0) return null;
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -314,19 +314,33 @@ function reducer(
// ── Context ───────────────────────────────────────────────────
export type CatalogManagerMode = "normal" | "bc";
interface CatalogManagerContextValue {
state: CatalogManagerState;
dispatch: Dispatch<CatalogAction>;
catalogType: CatalogManagerMode;
canEdit: boolean;
}
const CatalogManagerContext = createContext<CatalogManagerContextValue | null>(
null,
);
export function CatalogManagerProvider({ children }: { children: ReactNode }) {
export function CatalogManagerProvider({
children,
catalogType = "normal",
canEdit = false,
}: {
children: ReactNode;
catalogType?: CatalogManagerMode;
canEdit?: boolean;
}) {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<CatalogManagerContext.Provider value={{ state, dispatch }}>
<CatalogManagerContext.Provider
value={{ state, dispatch, catalogType, canEdit }}
>
{children}
</CatalogManagerContext.Provider>
);
@@ -340,3 +354,8 @@ export function useCatalogManager() {
);
return ctx;
}
/** Append to tree API query strings when in Builder Club mode. */
export function catalogTreeQs(catalogType: CatalogManagerMode): string {
return catalogType === "bc" ? "&catalog=bc" : "";
}