@open-mercato/ui 0.5.1-develop.2851.2854b4507f → 0.5.1-develop.2856.35de414092

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -258,7 +258,7 @@ function Chevron({ open }) {
258
258
  function AppShell(props) {
259
259
  return /* @__PURE__ */ jsx(QueryProvider, { children: /* @__PURE__ */ jsx(BackendChromeProvider, { adminNavApi: props.adminNavApi, children: /* @__PURE__ */ jsx(AppShellBody, { ...props }) }) });
260
260
  }
261
- function AppShellBody({ productName, email, groups, rightHeaderSlot, children, sidebarCollapsedDefault = false, currentTitle, breadcrumb, version, settingsSectionTitle, settingsPathPrefixes = [], settingsSections, profileSections, profileSectionTitle, profilePathPrefixes = [], mobileSidebarSlot }) {
261
+ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, children, sidebarCollapsedDefault = false, currentTitle, breadcrumb, version, settingsSectionTitle, settingsPathPrefixes = [], settingsSections, profileSections, profileSectionTitle, profilePathPrefixes = [], mobileSidebarSlot }) {
262
262
  const pathname = usePathname();
263
263
  const searchParams = useSearchParams();
264
264
  const t = useT();
@@ -612,7 +612,7 @@ function AppShellBody({ productName, email, groups, rightHeaderSlot, children, s
612
612
  const lastVisibleIndex = sortedSections.length - 1;
613
613
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-h-full gap-3", children: [
614
614
  !hideHeader && /* @__PURE__ */ jsx("div", { className: `flex items-center ${compact ? "justify-center" : "justify-between"} mb-2`, children: /* @__PURE__ */ jsxs(Link, { href: "/backend", className: "flex items-center gap-2", "aria-label": t("appShell.goToDashboard"), children: [
615
- /* @__PURE__ */ jsx(Image, { src: "/open-mercato.svg", alt: resolvedProductName, width: 32, height: 32, className: "rounded m-4" }),
615
+ /* @__PURE__ */ jsx(Image, { src: logo?.src ?? "/open-mercato.svg", alt: logo?.alt ?? resolvedProductName, width: 32, height: 32, className: "rounded m-4" }),
616
616
  !compact && /* @__PURE__ */ jsx("div", { className: "text-m font-semibold", children: resolvedProductName })
617
617
  ] }) }),
618
618
  /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-3 overflow-y-auto pr-1", children: [
@@ -698,7 +698,7 @@ function AppShellBody({ productName, email, groups, rightHeaderSlot, children, s
698
698
  if (!isChromeReady && isChromeLoading && resolvedGroups.length === 0) {
699
699
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-h-full gap-3", "data-testid": "backend-chrome-loading", children: [
700
700
  !hideHeader ? /* @__PURE__ */ jsx("div", { className: `flex items-center ${compact ? "justify-center" : "justify-between"} mb-2`, children: /* @__PURE__ */ jsxs(Link, { href: "/backend", className: "flex items-center gap-2", "aria-label": t("appShell.goToDashboard"), children: [
701
- /* @__PURE__ */ jsx(Image, { src: "/open-mercato.svg", alt: resolvedProductName, width: 32, height: 32, className: "rounded m-4" }),
701
+ /* @__PURE__ */ jsx(Image, { src: logo?.src ?? "/open-mercato.svg", alt: logo?.alt ?? resolvedProductName, width: 32, height: 32, className: "rounded m-4" }),
702
702
  !compact && /* @__PURE__ */ jsx("div", { className: "text-m font-semibold", children: resolvedProductName })
703
703
  ] }) }) : null,
704
704
  /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-3 pr-1", children: [
@@ -923,7 +923,7 @@ function AppShellBody({ productName, email, groups, rightHeaderSlot, children, s
923
923
  ] }) : /* @__PURE__ */ jsx("div", { className: "rounded border border-dashed bg-muted/20 p-3 text-sm text-muted-foreground", children: t("appShell.sidebarCustomizationLoading") }) : null;
924
924
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-h-full gap-3", children: [
925
925
  !hideHeader && /* @__PURE__ */ jsx("div", { className: `flex items-center ${compact ? "justify-center" : "justify-between"} mb-2`, children: /* @__PURE__ */ jsxs(Link, { href: "/backend", className: "flex items-center gap-2", "aria-label": t("appShell.goToDashboard"), children: [
926
- /* @__PURE__ */ jsx(Image, { src: "/open-mercato.svg", alt: resolvedProductName, width: 32, height: 32, className: "rounded m-4" }),
926
+ /* @__PURE__ */ jsx(Image, { src: logo?.src ?? "/open-mercato.svg", alt: logo?.alt ?? resolvedProductName, width: 32, height: 32, className: "rounded m-4" }),
927
927
  !compact && /* @__PURE__ */ jsx("div", { className: "text-m font-semibold", children: resolvedProductName })
928
928
  ] }) }),
929
929
  shouldRenderSidebarInjectionSpots ? /* @__PURE__ */ jsx(
@@ -1249,7 +1249,7 @@ function AppShellBody({ productName, email, groups, rightHeaderSlot, children, s
1249
1249
  /* @__PURE__ */ jsxs("aside", { className: "absolute left-0 top-0 flex h-full w-[260px] flex-col bg-background border-r overflow-hidden", children: [
1250
1250
  /* @__PURE__ */ jsxs("div", { className: "shrink-0 p-3 pb-2 flex items-center justify-between border-b", children: [
1251
1251
  /* @__PURE__ */ jsxs(Link, { href: "/backend", className: "flex items-center gap-2 text-sm font-semibold", onClick: () => setMobileOpen(false), "aria-label": t("appShell.goToDashboard"), children: [
1252
- /* @__PURE__ */ jsx(Image, { src: "/open-mercato.svg", alt: resolvedProductName, width: 28, height: 28, className: "rounded" }),
1252
+ /* @__PURE__ */ jsx(Image, { src: logo?.src ?? "/open-mercato.svg", alt: logo?.alt ?? resolvedProductName, width: 28, height: 28, className: "rounded" }),
1253
1253
  resolvedProductName
1254
1254
  ] }),
1255
1255
  /* @__PURE__ */ jsx(IconButton, { variant: "outline", size: "sm", onClick: () => setMobileOpen(false), "aria-label": t("appShell.closeMenu"), children: "\u2715" })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/backend/AppShell.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { createContext, useContext } from 'react'\nimport Link from 'next/link'\nimport Image from 'next/image'\nimport { ChevronUp, ChevronDown } from 'lucide-react'\nimport { Button } from '../primitives/button'\nimport { IconButton } from '../primitives/icon-button'\nimport { Separator } from '../primitives/separator'\nimport { FlashMessages } from './FlashMessages'\nimport { QueryProvider } from '../theme/QueryProvider'\nimport { usePathname, useSearchParams } from 'next/navigation'\nimport { apiCall } from './utils/apiCall'\nimport { LastOperationBanner } from './operations/LastOperationBanner'\nimport { ProgressTopBar } from './progress/ProgressTopBar'\nimport { UpgradeActionBanner } from './upgrades/UpgradeActionBanner'\nimport { PartialIndexBanner } from './indexes/PartialIndexBanner'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { slugifySidebarId } from '@open-mercato/shared/modules/navigation/sidebarPreferences'\nimport type { SectionNavGroup } from './section-page/types'\nimport { InjectionSpot } from './injection/InjectionSpot'\nimport type { InjectionMenuItem } from '@open-mercato/shared/modules/widgets/injection'\nimport { LEGACY_GLOBAL_MUTATION_INJECTION_SPOT_ID } from './injection/mutationEvents'\nimport { mergeMenuItems } from './injection/mergeMenuItems'\nimport { useInjectedMenuItems } from './injection/useInjectedMenuItems'\nimport { resolveInjectedIcon } from './injection/resolveInjectedIcon'\nimport { useEventBridge } from './injection/eventBridge'\nimport { StatusBadgeInjectionSpot } from './injection/StatusBadgeInjectionSpot'\nimport { UmesDevToolsPanel } from './devtools'\nimport { BackendChromeProvider, useBackendChrome } from './BackendChromeProvider'\nimport {\n BACKEND_LAYOUT_FOOTER_INJECTION_SPOT_ID,\n BACKEND_LAYOUT_TOP_INJECTION_SPOT_ID,\n BACKEND_RECORD_CURRENT_INJECTION_SPOT_ID,\n BACKEND_SIDEBAR_FOOTER_INJECTION_SPOT_ID,\n BACKEND_SIDEBAR_TOP_INJECTION_SPOT_ID,\n BACKEND_SIDEBAR_NAV_FOOTER_INJECTION_SPOT_ID,\n BACKEND_SIDEBAR_NAV_INJECTION_SPOT_ID,\n BACKEND_TOPBAR_ACTIONS_INJECTION_SPOT_ID,\n GLOBAL_HEADER_STATUS_INDICATORS_INJECTION_SPOT_ID,\n GLOBAL_SIDEBAR_STATUS_BADGES_INJECTION_SPOT_ID,\n} from './injection/spotIds'\n\nexport type AppShellProps = {\n productName?: string\n email?: string\n groups: {\n id?: string\n name: string\n defaultName?: string\n items: {\n id?: string\n href: string\n title: string\n defaultTitle?: string\n icon?: React.ReactNode\n iconName?: string\n iconMarkup?: string\n enabled?: boolean\n hidden?: boolean\n pageContext?: 'main' | 'admin' | 'settings' | 'profile'\n children?: {\n id?: string\n href: string\n title: string\n defaultTitle?: string\n icon?: React.ReactNode\n iconName?: string\n iconMarkup?: string\n enabled?: boolean\n hidden?: boolean\n pageContext?: 'main' | 'admin' | 'settings' | 'profile'\n }[]\n }[]\n }[]\n children: React.ReactNode\n rightHeaderSlot?: React.ReactNode\n sidebarCollapsedDefault?: boolean\n currentTitle?: string\n breadcrumb?: Array<{ label: string; href?: string }>\n // Optional: full admin nav API to refresh sidebar client-side\n adminNavApi?: string\n version?: string\n settingsSectionTitle?: string\n settingsPathPrefixes?: string[]\n settingsSections?: SectionNavGroup[]\n profileSections?: SectionNavGroup[]\n profileSectionTitle?: string\n profilePathPrefixes?: string[]\n mobileSidebarSlot?: React.ReactNode\n}\n\ntype Breadcrumb = Array<{ label: string; href?: string }>\n\ntype SidebarCustomizationDraft = {\n order: string[]\n groupLabels: Record<string, string>\n itemLabels: Record<string, string>\n hiddenItemIds: Record<string, boolean>\n}\n\ntype SidebarGroup = AppShellProps['groups'][number]\ntype SidebarItem = SidebarGroup['items'][number]\ntype SidebarRoleTarget = { id: string; name: string; hasPreference: boolean }\n\nfunction convertInjectedMenuItemToSidebarItem(item: InjectionMenuItem, title: string): SidebarItem | null {\n if (!item.href) return null\n return {\n id: item.id,\n href: item.href,\n title,\n defaultTitle: title,\n icon: resolveInjectedIcon(item.icon) ?? undefined,\n iconName: item.icon,\n enabled: true,\n hidden: false,\n pageContext: 'main',\n }\n}\n\nfunction resolveInjectedMenuLabel(\n item: { id: string; label?: string; labelKey?: string },\n t: (key: string, fallback?: string) => string,\n): string {\n if (item.labelKey && item.label) return t(item.labelKey, item.label)\n if (item.labelKey) return t(item.labelKey, item.id)\n if (item.label && item.label.includes('.')) return t(item.label, item.id)\n return item.label ?? item.id\n}\n\nfunction mergeSidebarItemsWithInjected(\n items: SidebarItem[],\n injectedItems: InjectionMenuItem[],\n t: (key: string, fallback?: string) => string,\n): SidebarItem[] {\n if (injectedItems.length === 0) return items\n\n const builtInById = new Map<string, SidebarItem>()\n for (const item of items) {\n builtInById.set(item.id ?? item.href, item)\n }\n\n const merged = mergeMenuItems(\n items.map((item) => ({\n id: item.id ?? item.href,\n })),\n injectedItems,\n )\n\n const result: SidebarItem[] = []\n for (const entry of merged) {\n if (entry.source === 'built-in') {\n const original = builtInById.get(entry.id)\n if (original) result.push(original)\n continue\n }\n const translatedLabel = resolveInjectedMenuLabel(\n { id: entry.id, label: entry.label, labelKey: entry.labelKey },\n t,\n )\n const converted = convertInjectedMenuItemToSidebarItem(\n {\n id: entry.id,\n label: translatedLabel,\n icon: entry.icon,\n href: entry.href,\n },\n translatedLabel,\n )\n if (converted) result.push(converted)\n }\n\n return result\n}\n\nfunction mergeSidebarGroupsWithInjected(\n groups: SidebarGroup[],\n injectedItems: InjectionMenuItem[],\n t: (key: string, fallback?: string) => string,\n): SidebarGroup[] {\n if (injectedItems.length === 0) return groups\n\n const injectedByGroup = new Map<string, InjectionMenuItem[]>()\n const ungrouped: InjectionMenuItem[] = []\n\n for (const item of injectedItems) {\n if (item.groupId && item.groupId.trim().length > 0) {\n const groupItems = injectedByGroup.get(item.groupId) ?? []\n groupItems.push(item)\n injectedByGroup.set(item.groupId, groupItems)\n continue\n }\n ungrouped.push(item)\n }\n\n const nextGroups = groups.map((group, index) => {\n const groupId = group.id || resolveGroupKey(group)\n const groupInjected = [\n ...(injectedByGroup.get(groupId) ?? []),\n ...(index === 0 ? ungrouped : []),\n ]\n return {\n ...group,\n items: mergeSidebarItemsWithInjected(group.items, groupInjected, t),\n }\n })\n\n const existingIds = new Set(nextGroups.map((group) => group.id || resolveGroupKey(group)))\n for (const [groupId, items] of injectedByGroup.entries()) {\n if (existingIds.has(groupId)) continue\n const first = items[0]\n const label = first.groupLabelKey\n ? t(first.groupLabelKey, first.groupLabel ?? groupId)\n : (first.groupLabel ?? groupId)\n const groupItems = mergeSidebarItemsWithInjected([], items, t)\n if (groupItems.length === 0) continue\n nextGroups.push({\n id: groupId,\n name: label,\n defaultName: label,\n items: groupItems,\n })\n }\n\n return nextGroups\n}\n\nfunction mergeSectionGroupsWithInjected(\n sections: SectionNavGroup[],\n injectedItems: InjectionMenuItem[],\n t: (key: string, fallback?: string) => string,\n): SectionNavGroup[] {\n if (injectedItems.length === 0) return sections\n const byGroup = new Map<string, InjectionMenuItem[]>()\n for (const item of injectedItems) {\n const groupId = item.groupId && item.groupId.trim().length > 0 ? item.groupId : 'injected'\n const bucket = byGroup.get(groupId) ?? []\n bucket.push(item)\n byGroup.set(groupId, bucket)\n }\n\n const nextSections = sections.map((section) => {\n const sectionItems = byGroup.get(section.id) ?? []\n if (sectionItems.length === 0) return section\n const mergedItems = mergeMenuItems(\n section.items.map((item) => ({ id: item.id, item })),\n sectionItems,\n ).flatMap((item) => {\n if (item.source === 'built-in') {\n const original = section.items.find((entry) => entry.id === item.id)\n return original ? [original] : []\n }\n if (!item.href) return []\n const label = resolveInjectedMenuLabel(item, t)\n return [{\n id: item.id,\n label,\n href: item.href,\n icon: resolveInjectedIcon(item.icon) ?? undefined,\n }]\n })\n return {\n ...section,\n items: mergedItems,\n }\n })\n\n for (const [sectionId, sectionItems] of byGroup.entries()) {\n const exists = nextSections.some((section) => section.id === sectionId)\n if (exists) continue\n const first = sectionItems[0]\n const label = first.groupLabelKey\n ? t(first.groupLabelKey, first.groupLabel ?? sectionId)\n : (first.groupLabel ?? sectionId)\n const items = sectionItems.flatMap((item) => {\n if (!item.href) return []\n const itemLabel = resolveInjectedMenuLabel(item, t)\n return [{\n id: item.id,\n label: itemLabel,\n href: item.href,\n icon: resolveInjectedIcon(item.icon) ?? undefined,\n }]\n })\n if (items.length === 0) continue\n nextSections.push({ id: sectionId, label, items })\n }\n\n return nextSections\n}\n\nfunction resolveGroupKey(group: SidebarGroup): string {\n if (group.id && group.id.length) return group.id\n if (group.defaultName && group.defaultName.length) return slugifySidebarId(group.defaultName)\n return slugifySidebarId(group.name)\n}\n\nfunction resolveItemKey(item: { id?: string; href: string }): string {\n const candidate = item.id?.trim()\n if (candidate && candidate.length > 0) return candidate\n return item.href\n}\n\nfunction SerializedIcon({ markup }: { markup: string }) {\n return <span aria-hidden=\"true\" dangerouslySetInnerHTML={{ __html: markup }} />\n}\n\nfunction renderIcon(\n icon: React.ReactNode | undefined,\n iconName: string | undefined,\n iconMarkup: string | undefined,\n fallback: React.ReactNode,\n) {\n if (icon) return icon\n if (iconName) {\n const resolved = resolveInjectedIcon(iconName)\n if (resolved) return resolved\n }\n if (iconMarkup) return <SerializedIcon markup={iconMarkup} />\n return fallback\n}\n\nconst HeaderContext = createContext<{\n setBreadcrumb: (b?: Breadcrumb) => void\n setTitle: (t?: string) => void\n} | null>(null)\n\nexport function ApplyBreadcrumb({ breadcrumb, title, titleKey }: { breadcrumb?: Array<{ label: string; href?: string; labelKey?: string }>; title?: string; titleKey?: string }) {\n const ctx = useContext(HeaderContext)\n const t = useT()\n const resolvedBreadcrumb = React.useMemo<Breadcrumb | undefined>(() => {\n if (!breadcrumb) return undefined\n return breadcrumb.map(({ label, labelKey, href }) => {\n const translated = labelKey ? t(labelKey) : undefined\n const finalLabel = translated && translated !== labelKey ? translated : label\n return {\n href,\n label: finalLabel,\n }\n })\n }, [breadcrumb, t])\n const resolvedTitle = React.useMemo(() => {\n if (!titleKey) return title\n const translated = t(titleKey)\n if (translated && translated !== titleKey) return translated\n return title\n }, [titleKey, title, t])\n React.useEffect(() => {\n ctx?.setBreadcrumb(resolvedBreadcrumb)\n if (resolvedTitle !== undefined) ctx?.setTitle(resolvedTitle)\n }, [ctx, resolvedBreadcrumb, resolvedTitle])\n return null\n}\n\nconst DefaultIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M8 6h13M8 12h13M8 18h13\"/>\n <path d=\"M3 6h.01M3 12h.01M3 18h.01\"/>\n </svg>\n)\n\n// DataTable icon used for dynamic custom entity records links\nconst DataTableIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\" ry=\"2\"/>\n <line x1=\"3\" y1=\"8\" x2=\"21\" y2=\"8\"/>\n <line x1=\"9\" y1=\"8\" x2=\"9\" y2=\"20\"/>\n <line x1=\"15\" y1=\"8\" x2=\"15\" y2=\"20\"/>\n </svg>\n)\n\nconst CustomizeIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.05.05a2 2 0 1 1-2.83 2.83l-.05-.05A1.65 1.65 0 0 0 15 19.4a1.65 1.65 0 0 0-1 .6 1.65 1.65 0 0 0-.33 1.82l-.05.05a2 2 0 1 1-2.83-2.83l.05-.05A1.65 1.65 0 0 0 9 15a1.65 1.65 0 0 0-1-.6 1.65 1.65 0 0 0-1.82.33l-.05.05a2 2 0 1 1-2.83-2.83l.05-.05A1.65 1.65 0 0 0 4.6 9 1.65 1.65 0 0 0 4 8a1.65 1.65 0 0 0-.6-1.82l-.05-.05a2 2 0 1 1 2.83-2.83l.05.05A1.65 1.65 0 0 0 9 4.6a1.65 1.65 0 0 0 1-.6 1.65 1.65 0 0 0 .33-1.82l.05-.05a2 2 0 1 1 2.83 2.83l-.05.05A1.65 1.65 0 0 0 15 9a1.65 1.65 0 0 0 1 .6 1.65 1.65 0 0 0 1.82-.33l.05-.05a2 2 0 1 1 2.83 2.83l-.05.05A1.65 1.65 0 0 0 19.4 15z\" />\n </svg>\n)\n\nconst BackArrowIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M19 12H5M12 19l-7-7 7-7\" />\n </svg>\n)\n\nfunction Chevron({ open }: { open: boolean }) {\n return (\n <svg className={`transition-transform ${open ? 'rotate-180' : ''}`} width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><path d=\"M6 9l6 6 6-6\"/></svg>\n )\n}\n\nexport function AppShell(props: AppShellProps) {\n return (\n <QueryProvider>\n <BackendChromeProvider adminNavApi={props.adminNavApi}>\n <AppShellBody {...props} />\n </BackendChromeProvider>\n </QueryProvider>\n )\n}\n\nfunction AppShellBody({ productName, email, groups, rightHeaderSlot, children, sidebarCollapsedDefault = false, currentTitle, breadcrumb, version, settingsSectionTitle, settingsPathPrefixes = [], settingsSections, profileSections, profileSectionTitle, profilePathPrefixes = [], mobileSidebarSlot }: AppShellProps) {\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const t = useT()\n const locale = useLocale()\n const { payload: chromePayload, isReady: isChromeReady, isLoading: isChromeLoading } = useBackendChrome()\n const resolvedGroups = React.useMemo(\n () => AppShell.cloneGroups(chromePayload?.groups ?? groups),\n [chromePayload?.groups, groups],\n )\n const resolvedSettingsSections = chromePayload?.settingsSections ?? settingsSections\n const resolvedSettingsPathPrefixes = chromePayload?.settingsPathPrefixes ?? settingsPathPrefixes\n const resolvedProfileSections = chromePayload?.profileSections ?? profileSections\n const resolvedProfilePathPrefixes = chromePayload?.profilePathPrefixes ?? profilePathPrefixes\n const { items: mainSidebarInjectedMenuItems } = useInjectedMenuItems('menu:sidebar:main')\n const { items: settingsSidebarInjectedMenuItems } = useInjectedMenuItems('menu:sidebar:settings')\n const { items: profileSidebarInjectedMenuItems } = useInjectedMenuItems('menu:sidebar:profile')\n const { items: topbarInjectedMenuItems } = useInjectedMenuItems('menu:topbar:actions')\n useEventBridge() // SSE DOM Event Bridge \u2014 singleton SSE connection for real-time server events\n const resolvedProductName = productName ?? t('appShell.productName')\n const [mobileOpen, setMobileOpen] = React.useState(false)\n // Initialize from server-provided prop only to avoid hydration flicker\n const [collapsed, setCollapsed] = React.useState(sidebarCollapsedDefault)\n // Maintain internal nav state so we can augment it client-side\n const [navGroups, setNavGroups] = React.useState(resolvedGroups)\n const [openGroups, setOpenGroups] = React.useState<Record<string, boolean>>(() =>\n Object.fromEntries(resolvedGroups.map((g) => [resolveGroupKey(g), true])) as Record<string, boolean>\n )\n const [customizing, setCustomizing] = React.useState(false)\n const [customDraft, setCustomDraft] = React.useState<SidebarCustomizationDraft | null>(null)\n const [loadingPreferences, setLoadingPreferences] = React.useState(false)\n const [savingPreferences, setSavingPreferences] = React.useState(false)\n const [customizationError, setCustomizationError] = React.useState<string | null>(null)\n const [availableRoleTargets, setAvailableRoleTargets] = React.useState<SidebarRoleTarget[]>([])\n const [selectedRoleIds, setSelectedRoleIds] = React.useState<string[]>([])\n const [canApplyToRoles, setCanApplyToRoles] = React.useState(false)\n const originalNavRef = React.useRef<SidebarGroup[] | null>(null)\n const [headerTitle, setHeaderTitle] = React.useState<string | undefined>(currentTitle)\n const [headerBreadcrumb, setHeaderBreadcrumb] = React.useState<Breadcrumb | undefined>(breadcrumb)\n const effectiveCollapsed = customizing ? false : collapsed\n const expandedSidebarWidth = customizing ? '320px' : '240px'\n const injectionContext = React.useMemo(\n () => ({\n path: pathname ?? '',\n query: searchParams?.toString() ?? '',\n }),\n [pathname, searchParams],\n )\n\n const isOnSettingsPath = React.useMemo(() => {\n if (!pathname) return false\n if (pathname === '/backend/settings') return true\n return resolvedSettingsPathPrefixes.some((prefix) => pathname.startsWith(prefix))\n }, [pathname, resolvedSettingsPathPrefixes])\n\n const isOnProfilePath = React.useMemo(() => {\n if (!pathname) return false\n if (pathname === '/backend/profile') return true\n return resolvedProfilePathPrefixes.some((prefix) => pathname.startsWith(prefix))\n }, [pathname, resolvedProfilePathPrefixes])\n\n const sidebarMode: 'main' | 'settings' | 'profile' =\n isOnSettingsPath ? 'settings' :\n isOnProfilePath ? 'profile' :\n 'main'\n\n const mainNavGroupsWithInjected = React.useMemo(\n () => mergeSidebarGroupsWithInjected(navGroups, mainSidebarInjectedMenuItems, t),\n [mainSidebarInjectedMenuItems, navGroups, t],\n )\n\n // Lock body scroll when mobile drawer is open so touch scroll stays in the drawer\n React.useEffect(() => {\n if (!mobileOpen || typeof document === 'undefined') return\n const prev = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n return () => {\n document.body.style.overflow = prev\n }\n }, [mobileOpen])\n\n React.useEffect(() => {\n try {\n const savedOpen = typeof window !== 'undefined' ? localStorage.getItem('om:sidebarOpenGroups') : null\n if (!savedOpen) return\n const parsed = JSON.parse(savedOpen) as Record<string, boolean>\n setOpenGroups((prev) => {\n const next = { ...prev }\n for (const group of resolvedGroups) {\n const key = resolveGroupKey(group)\n if (key in parsed) next[key] = !!parsed[key]\n else if (group.name in parsed) next[key] = !!parsed[group.name]\n }\n return next\n })\n } catch {\n // ignore localStorage errors to avoid breaking hydration\n }\n }, [resolvedGroups])\n\n const toggleGroup = (groupId: string) => setOpenGroups((prev) => ({ ...prev, [groupId]: prev[groupId] === false }))\n\n const updateDraft = React.useCallback((updater: (draft: SidebarCustomizationDraft) => SidebarCustomizationDraft) => {\n setCustomDraft((prev) => {\n if (!prev) return prev\n const next = updater(prev)\n if (originalNavRef.current) {\n setNavGroups(applyCustomizationDraft(originalNavRef.current, next))\n }\n return next\n })\n }, [])\n\n const startCustomization = React.useCallback(async () => {\n if (customizing || loadingPreferences) return\n setCustomizationError(null)\n setLoadingPreferences(true)\n try {\n const baseSnapshot = filterMainSidebarGroups(AppShell.cloneGroups(navGroups))\n const call = await apiCall<{\n settings?: Record<string, unknown>\n canApplyToRoles?: boolean\n roles?: Array<{ id?: string; name?: string; hasPreference?: boolean }>\n }>('/api/auth/sidebar/preferences')\n const data = call.ok ? (call.result ?? null) : null\n const rawSettings = data?.settings\n const responseOrder = Array.isArray(rawSettings?.groupOrder)\n ? rawSettings.groupOrder\n .map((id: unknown) => (typeof id === 'string' ? id.trim() : ''))\n .filter((id: string) => id.length > 0)\n : []\n const responseGroupLabels: Record<string, string> = {}\n if (rawSettings?.groupLabels && typeof rawSettings.groupLabels === 'object') {\n for (const [key, value] of Object.entries(rawSettings.groupLabels as Record<string, unknown>)) {\n if (typeof value !== 'string') continue\n const trimmedKey = key.trim()\n if (!trimmedKey) continue\n responseGroupLabels[trimmedKey] = value\n }\n }\n const responseItemLabels: Record<string, string> = {}\n if (rawSettings?.itemLabels && typeof rawSettings.itemLabels === 'object') {\n for (const [key, value] of Object.entries(rawSettings.itemLabels as Record<string, unknown>)) {\n if (typeof value !== 'string') continue\n const trimmedKey = key.trim()\n if (!trimmedKey) continue\n responseItemLabels[trimmedKey] = value\n }\n }\n const responseHiddenItems = Array.isArray(rawSettings?.hiddenItems)\n ? rawSettings.hiddenItems\n .map((itemId: unknown) => (typeof itemId === 'string' ? itemId.trim() : ''))\n .filter((itemId: string) => itemId.length > 0)\n : []\n const canManageRoles = data?.canApplyToRoles === true\n setCanApplyToRoles(canManageRoles)\n if (canManageRoles) {\n const roles = Array.isArray(data?.roles)\n ? (data.roles as Array<{ id?: string; name?: string; hasPreference?: boolean }>).filter((role) => typeof role?.id === 'string' && typeof role?.name === 'string')\n : []\n const mappedRoles: SidebarRoleTarget[] = roles.map((role) => ({\n id: role.id as string,\n name: role.name as string,\n hasPreference: role.hasPreference === true,\n }))\n setAvailableRoleTargets(mappedRoles)\n setSelectedRoleIds(mappedRoles.filter((role) => role.hasPreference).map((role) => role.id))\n } else {\n setAvailableRoleTargets([])\n setSelectedRoleIds([])\n }\n const currentIds = baseSnapshot.map((group) => resolveGroupKey(group))\n const order = mergeGroupOrder(responseOrder, currentIds)\n const { itemDefaults } = collectSidebarDefaults(baseSnapshot)\n const hiddenItemIds: Record<string, boolean> = {}\n for (const itemId of responseHiddenItems) {\n if (!itemDefaults.has(itemId)) continue\n hiddenItemIds[itemId] = true\n }\n const draft: SidebarCustomizationDraft = {\n order,\n groupLabels: { ...responseGroupLabels },\n itemLabels: { ...responseItemLabels },\n hiddenItemIds,\n }\n originalNavRef.current = baseSnapshot\n setCustomDraft(draft)\n setNavGroups(applyCustomizationDraft(baseSnapshot, draft))\n setCustomizing(true)\n } catch (error) {\n console.error('Failed to load sidebar preferences', error)\n setCustomizationError(t('appShell.sidebarCustomizationLoadError'))\n } finally {\n setLoadingPreferences(false)\n }\n }, [customizing, loadingPreferences, navGroups, t])\n\n const cancelCustomization = React.useCallback(() => {\n setCustomizing(false)\n setCustomDraft(null)\n setCustomizationError(null)\n setAvailableRoleTargets([])\n setSelectedRoleIds([])\n setCanApplyToRoles(false)\n if (originalNavRef.current) {\n setNavGroups(AppShell.cloneGroups(originalNavRef.current))\n }\n originalNavRef.current = null\n }, [])\n\n const resetCustomization = React.useCallback(() => {\n if (!originalNavRef.current) return\n const base = AppShell.cloneGroups(originalNavRef.current)\n const order = base.map((group) => resolveGroupKey(group))\n const draft: SidebarCustomizationDraft = { order, groupLabels: {}, itemLabels: {}, hiddenItemIds: {} }\n originalNavRef.current = base\n setCustomDraft(draft)\n setNavGroups(applyCustomizationDraft(base, draft))\n if (canApplyToRoles) {\n setSelectedRoleIds(availableRoleTargets.filter((role) => role.hasPreference).map((role) => role.id))\n }\n }, [availableRoleTargets, canApplyToRoles])\n\n const saveCustomization = React.useCallback(async () => {\n if (!customDraft) return\n setSavingPreferences(true)\n setCustomizationError(null)\n try {\n const baseGroups = originalNavRef.current ?? filterMainSidebarGroups(AppShell.cloneGroups(navGroups))\n const { groupDefaults, itemDefaults } = collectSidebarDefaults(baseGroups)\n const sanitizedGroupLabels: Record<string, string> = {}\n for (const [key, value] of Object.entries(customDraft.groupLabels)) {\n const trimmed = value.trim()\n const base = groupDefaults.get(key)\n if (!trimmed || !base) continue\n if (trimmed !== base) sanitizedGroupLabels[key] = trimmed\n }\n const sanitizedItemLabels: Record<string, string> = {}\n for (const [itemId, value] of Object.entries(customDraft.itemLabels)) {\n const trimmed = value.trim()\n const base = itemDefaults.get(itemId)\n if (!trimmed || !base) continue\n if (trimmed !== base) sanitizedItemLabels[itemId] = trimmed\n }\n const sanitizedHiddenItems: string[] = []\n for (const [itemId, hidden] of Object.entries(customDraft.hiddenItemIds)) {\n if (!hidden) continue\n if (!itemDefaults.has(itemId)) continue\n sanitizedHiddenItems.push(itemId)\n }\n const applyToRolesPayload = canApplyToRoles ? [...selectedRoleIds] : []\n const clearRoleIdsPayload = canApplyToRoles\n ? availableRoleTargets\n .filter((role) => role.hasPreference && !selectedRoleIds.includes(role.id))\n .map((role) => role.id)\n : []\n const payload: Record<string, unknown> = {\n groupOrder: customDraft.order,\n groupLabels: sanitizedGroupLabels,\n itemLabels: sanitizedItemLabels,\n hiddenItems: sanitizedHiddenItems,\n }\n if (canApplyToRoles) {\n payload.applyToRoles = applyToRolesPayload\n payload.clearRoleIds = clearRoleIdsPayload\n }\n const call = await apiCall<{\n canApplyToRoles?: boolean\n roles?: Array<{ id?: string; name?: string; hasPreference?: boolean }>\n }>('/api/auth/sidebar/preferences', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!call.ok) {\n setCustomizationError(t('appShell.sidebarCustomizationSaveError'))\n return\n }\n const data = call.result ?? null\n if (data?.canApplyToRoles !== undefined) {\n setCanApplyToRoles(data.canApplyToRoles === true)\n }\n if (Array.isArray(data?.roles)) {\n const mappedRoles: SidebarRoleTarget[] = (data.roles as Array<{ id?: string; name?: string; hasPreference?: boolean }>).filter((role) => typeof role?.id === 'string' && typeof role?.name === 'string').map((role) => ({\n id: role.id as string,\n name: role.name as string,\n hasPreference: role.hasPreference === true,\n }))\n setAvailableRoleTargets(mappedRoles)\n setSelectedRoleIds(mappedRoles.filter((role) => role.hasPreference).map((role) => role.id))\n }\n originalNavRef.current = applyCustomizationDraft(baseGroups, customDraft)\n setNavGroups(AppShell.cloneGroups(originalNavRef.current))\n setCustomizing(false)\n setCustomDraft(null)\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n } catch (error) {\n console.error('Failed to save sidebar preferences', error)\n setCustomizationError(t('appShell.sidebarCustomizationSaveError'))\n } finally {\n setSavingPreferences(false)\n }\n }, [customDraft, navGroups, t])\n\n const moveGroup = React.useCallback((groupId: string, offset: number) => {\n updateDraft((draft) => {\n const order = [...draft.order]\n const index = order.indexOf(groupId)\n if (index === -1) return draft\n const nextIndex = Math.max(0, Math.min(order.length - 1, index + offset))\n if (nextIndex === index) return draft\n order.splice(index, 1)\n order.splice(nextIndex, 0, groupId)\n return { ...draft, order }\n })\n }, [updateDraft])\n\n const setGroupLabel = React.useCallback((groupId: string, value: string) => {\n updateDraft((draft) => {\n const next = { ...draft.groupLabels }\n if (value.trim().length === 0) delete next[groupId]\n else next[groupId] = value\n return { ...draft, groupLabels: next }\n })\n }, [updateDraft])\n\n const setItemLabel = React.useCallback((itemId: string, value: string) => {\n updateDraft((draft) => {\n const next = { ...draft.itemLabels }\n if (value.trim().length === 0) delete next[itemId]\n else next[itemId] = value\n return { ...draft, itemLabels: next }\n })\n }, [updateDraft])\n const setItemHidden = React.useCallback((itemId: string, hidden: boolean) => {\n updateDraft((draft) => {\n const next = { ...draft.hiddenItemIds }\n if (hidden) next[itemId] = true\n else delete next[itemId]\n return { ...draft, hiddenItemIds: next }\n })\n }, [updateDraft])\n\n const toggleRoleSelection = React.useCallback((roleId: string) => {\n setSelectedRoleIds((prev) => (prev.includes(roleId) ? prev.filter((id) => id !== roleId) : [...prev, roleId]))\n }, [])\n\n const asideWidth = effectiveCollapsed ? '72px' : expandedSidebarWidth\n // Use min-h-svh so the border extends with tall content; no overflow so sticky bottom works\n const asideClassesBase = `border-r bg-background/60 py-4 min-h-svh`;\n\n // Persist collapse state to localStorage and cookie\n React.useEffect(() => {\n try { localStorage.setItem('om:sidebarCollapsed', collapsed ? '1' : '0') } catch {}\n try {\n document.cookie = `om_sidebar_collapsed=${collapsed ? '1' : '0'}; path=/; max-age=31536000; samesite=lax`\n } catch {}\n }, [collapsed])\n React.useEffect(() => {\n try { localStorage.setItem('om:sidebarOpenGroups', JSON.stringify(openGroups)) } catch {}\n }, [openGroups])\n\n // Ensure current route's group is expanded on load\n React.useEffect(() => {\n const activeGroup = navGroups.find((g) => g.items.some((i) => pathname?.startsWith(i.href)))\n if (!activeGroup) return\n const key = resolveGroupKey(activeGroup)\n setOpenGroups((prev) => (prev[key] === false ? { ...prev, [key]: true } : prev))\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pathname, navGroups])\n // Keep header state in sync with props (server-side updates)\n React.useEffect(() => {\n setHeaderTitle(currentTitle)\n setHeaderBreadcrumb(breadcrumb)\n }, [currentTitle, breadcrumb])\n // Clear breadcrumb on client-side navigation so stale state doesn't persist;\n // the new page's ApplyBreadcrumb (if any) will set the correct values\n const prevPathname = React.useRef(pathname)\n React.useEffect(() => {\n if (pathname !== prevPathname.current) {\n prevPathname.current = pathname\n setHeaderTitle(undefined)\n setHeaderBreadcrumb(undefined)\n }\n }, [pathname])\n\n // Keep navGroups in sync when server-provided groups change\n React.useEffect(() => {\n if (customizing && customDraft && originalNavRef.current) {\n originalNavRef.current = filterMainSidebarGroups(AppShell.cloneGroups(resolvedGroups))\n setNavGroups(applyCustomizationDraft(originalNavRef.current, customDraft))\n return\n }\n setNavGroups(AppShell.cloneGroups(resolvedGroups))\n }, [resolvedGroups, customizing, customDraft])\n\n function renderSectionSidebar(\n sections: SectionNavGroup[],\n title: string,\n compact: boolean,\n hideHeader?: boolean\n ) {\n const sortedSections = [...sections].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))\n const lastVisibleIndex = sortedSections.length - 1\n\n return (\n <div className=\"flex flex-col min-h-full gap-3\">\n {!hideHeader && (\n <div className={`flex items-center ${compact ? 'justify-center' : 'justify-between'} mb-2`}>\n <Link href=\"/backend\" className=\"flex items-center gap-2\" aria-label={t('appShell.goToDashboard')}>\n <Image src=\"/open-mercato.svg\" alt={resolvedProductName} width={32} height={32} className=\"rounded m-4\" />\n {!compact && <div className=\"text-m font-semibold\">{resolvedProductName}</div>}\n </Link>\n </div>\n )}\n <div className=\"flex flex-1 flex-col gap-3 overflow-y-auto pr-1\">\n <Link\n href=\"/backend\"\n className={`flex items-center gap-2 ${compact ? 'justify-center px-2' : 'px-2'} py-1 text-sm text-muted-foreground hover:text-foreground transition-colors`}\n aria-label={t('backend.nav.backToMain', 'Back')}\n >\n <span className=\"flex items-center justify-center shrink-0\">{BackArrowIcon}</span>\n {!compact && <span>{title}</span>}\n </Link>\n <nav className=\"flex flex-col gap-2\">\n {sortedSections.map((section, sectionIndex) => {\n const visibleItems = section.items\n if (visibleItems.length === 0) return null\n const sortedItems = [...visibleItems].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))\n const sectionLabel = section.labelKey ? t(section.labelKey, section.label) : section.label\n const sectionKey = `settings:${section.id}`\n const open = openGroups[sectionKey] !== false\n const sortSectionItems = (items: typeof section.items = []) =>\n [...items].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))\n\n const renderSectionItem = (item: (typeof section.items)[number], depth = 0): React.ReactNode => {\n const label = item.labelKey ? t(item.labelKey, item.label) : item.label\n const childItems = sortSectionItems(item.children)\n const isOnItemBranch = !!pathname && (\n pathname === item.href ||\n pathname.startsWith(`${item.href}/`)\n )\n const hasActiveChild = !!(pathname && childItems.some((child) => (\n pathname === child.href ||\n pathname.startsWith(`${child.href}/`)\n )))\n const showChildren = childItems.length > 0 && isOnItemBranch\n const isActive = isOnItemBranch || hasActiveChild\n const base = compact ? 'w-10 h-10 justify-center' : 'py-1 gap-2'\n const spacingStyle = !compact\n ? {\n paddingLeft: `${8 + depth * 16}px`,\n paddingRight: '8px',\n }\n : undefined\n\n return (\n <React.Fragment key={item.id}>\n <Link\n href={item.href}\n className={`relative text-sm rounded inline-flex items-center ${base} ${\n isActive\n ? 'bg-background border shadow-sm'\n : 'hover:bg-accent hover:text-accent-foreground'\n }`}\n style={spacingStyle}\n title={compact ? label : undefined}\n data-menu-item-id={item.id}\n onClick={() => setMobileOpen(false)}\n >\n {isActive && (\n <span className=\"absolute left-0 top-1 bottom-1 w-0.5 rounded bg-foreground\" />\n )}\n <span className={`flex items-center justify-center shrink-0 ${compact ? '' : 'text-muted-foreground'}`}>\n {renderIcon(\n item.icon,\n item.iconName,\n item.iconMarkup,\n item.href.includes('/backend/entities/user/') && item.href.endsWith('/records') ? DataTableIcon : DefaultIcon,\n )}\n </span>\n {!compact && <span className=\"truncate\">{label}</span>}\n </Link>\n {showChildren ? childItems.map((child) => renderSectionItem(child, depth + 1)) : null}\n </React.Fragment>\n )\n }\n\n return (\n <div key={section.id}>\n <Button\n variant=\"muted\"\n onClick={() => toggleGroup(sectionKey)}\n className={`w-full ${compact ? 'px-0 justify-center' : 'px-2 justify-between'} flex text-xs uppercase text-muted-foreground/90 py-2`}\n aria-expanded={open}\n >\n {!compact && <span>{sectionLabel}</span>}\n {!compact && <Chevron open={open} />}\n </Button>\n {open && (\n <div className={`flex flex-col ${compact ? 'items-center' : ''} gap-1 ${!compact ? 'pl-1' : ''}`}>\n {sortedItems.map((item) => renderSectionItem(item))}\n </div>\n )}\n {sectionIndex !== lastVisibleIndex && <div className=\"my-2 border-t border-dotted\" />}\n </div>\n )\n })}\n </nav>\n </div>\n </div>\n )\n }\n\n function renderSidebar(compact: boolean, hideHeader?: boolean) {\n if (!isChromeReady && isChromeLoading && resolvedGroups.length === 0) {\n return (\n <div className=\"flex flex-col min-h-full gap-3\" data-testid=\"backend-chrome-loading\">\n {!hideHeader ? (\n <div className={`flex items-center ${compact ? 'justify-center' : 'justify-between'} mb-2`}>\n <Link href=\"/backend\" className=\"flex items-center gap-2\" aria-label={t('appShell.goToDashboard')}>\n <Image src=\"/open-mercato.svg\" alt={resolvedProductName} width={32} height={32} className=\"rounded m-4\" />\n {!compact && <div className=\"text-m font-semibold\">{resolvedProductName}</div>}\n </Link>\n </div>\n ) : null}\n <div className=\"flex flex-1 flex-col gap-3 pr-1\">\n <div className=\"space-y-3\">\n <div className=\"h-8 rounded bg-muted/60\" />\n <div className=\"space-y-2 pl-1\">\n <div className=\"h-8 rounded bg-muted/50\" />\n <div className=\"h-8 rounded bg-muted/40\" />\n <div className=\"h-8 rounded bg-muted/40\" />\n </div>\n </div>\n <div className=\"space-y-3\">\n <div className=\"h-8 rounded bg-muted/60\" />\n <div className=\"space-y-2 pl-1\">\n <div className=\"h-8 rounded bg-muted/40\" />\n <div className=\"h-8 rounded bg-muted/40\" />\n </div>\n </div>\n </div>\n </div>\n )\n }\n\n if (sidebarMode === 'settings' && resolvedSettingsSections && resolvedSettingsSections.length > 0) {\n const mergedSettingsSections = mergeSectionGroupsWithInjected(\n resolvedSettingsSections,\n settingsSidebarInjectedMenuItems,\n t,\n )\n return renderSectionSidebar(\n mergedSettingsSections,\n settingsSectionTitle ?? t('backend.nav.settings', 'Settings'),\n compact,\n hideHeader\n )\n }\n\n if (sidebarMode === 'profile' && resolvedProfileSections && resolvedProfileSections.length > 0) {\n const mergedProfileSections = mergeSectionGroupsWithInjected(\n resolvedProfileSections,\n profileSidebarInjectedMenuItems,\n t,\n )\n return renderSectionSidebar(\n mergedProfileSections,\n profileSectionTitle ?? t('backend.nav.profile', 'Profile'),\n compact,\n hideHeader\n )\n }\n\n const isMobileVariant = !!hideHeader\n const shouldRenderSidebarInjectionSpots = !isMobileVariant\n const baseGroupsForDefaults = originalNavRef.current ?? mainNavGroupsWithInjected\n const baseGroupMap = new Map<string, SidebarGroup>()\n for (const group of baseGroupsForDefaults) {\n baseGroupMap.set(resolveGroupKey(group), group)\n }\n const localeLabel = (locale || '').toUpperCase()\n\n const orderedGroupIds = customDraft\n ? mergeGroupOrder(customDraft.order, Array.from(baseGroupMap.keys()))\n : mainNavGroupsWithInjected.map((group) => resolveGroupKey(group))\n\n const lastVisibleGroupIndex = (() => {\n for (let idx = navGroups.length - 1; idx >= 0; idx -= 1) {\n if (navGroups[idx].items.some((item) => item.hidden !== true)) return idx\n }\n return -1\n })()\n\n const renderEditableItems = (baseItems: SidebarItem[], currentItems: SidebarItem[], depth = 0): React.ReactNode => {\n if (!customDraft) return null\n return baseItems.map((baseItem) => {\n const itemKey = resolveItemKey(baseItem)\n const current = currentItems.find((item) => item.href === baseItem.href) ?? baseItem\n const placeholder = baseItem.defaultTitle ?? baseItem.title\n const value = customDraft.itemLabels[itemKey] ?? ''\n const hidden = customDraft.hiddenItemIds[itemKey] === true\n return (\n <div\n key={itemKey}\n className={`flex flex-col gap-1 ${hidden ? 'opacity-60' : ''}`}\n style={depth ? { marginLeft: depth * 16 } : undefined}\n >\n <span className=\"text-xs font-medium text-muted-foreground\">{placeholder}</span>\n <div className=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 accent-foreground\"\n checked={!hidden}\n onChange={(event) => setItemHidden(itemKey, !event.target.checked)}\n disabled={savingPreferences}\n aria-label={t('appShell.sidebarCustomizationShowItem')}\n title={t('appShell.sidebarCustomizationShowItem')}\n />\n <input\n value={value}\n onChange={(event) => setItemLabel(itemKey, event.target.value)}\n placeholder={placeholder}\n disabled={savingPreferences}\n className=\"h-8 flex-1 rounded border bg-background px-2 text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-60\"\n />\n </div>\n {baseItem.children && baseItem.children.length > 0 ? (\n <div className=\"flex flex-col gap-1\">\n {renderEditableItems(baseItem.children, current.children ?? [], depth + 1)}\n </div>\n ) : null}\n </div>\n )\n })\n }\n\n const customizationEditor = customizing ? (\n customDraft ? (\n <div className=\"flex flex-col gap-3 rounded border border-dashed bg-muted/20 p-3\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <div className=\"text-sm font-semibold\">{t('appShell.sidebarCustomizationHeading')}</div>\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={resetCustomization}\n disabled={savingPreferences}\n >\n {t('appShell.sidebarCustomizationReset')}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={cancelCustomization}\n disabled={savingPreferences}\n >\n {t('appShell.sidebarCustomizationCancel')}\n </Button>\n <Button\n size=\"sm\"\n className=\"bg-foreground text-background hover:bg-foreground/90\"\n onClick={saveCustomization}\n disabled={savingPreferences}\n >\n {savingPreferences ? t('appShell.sidebarCustomizationSaving') : t('appShell.sidebarCustomizationSave')}\n </Button>\n </div>\n </div>\n <p className=\"text-xs text-muted-foreground\">{t('appShell.sidebarCustomizationHint', { locale: localeLabel })}</p>\n {canApplyToRoles ? (\n <div className=\"flex flex-col gap-2 rounded border bg-background/70 p-3 shadow-sm\">\n <div>\n <div className=\"text-sm font-semibold\">{t('appShell.sidebarApplyToRolesTitle')}</div>\n <p className=\"text-xs text-muted-foreground\">{t('appShell.sidebarApplyToRolesDescription')}</p>\n </div>\n {availableRoleTargets.length > 0 ? (\n <div className=\"flex flex-col gap-2\">\n {availableRoleTargets.map((role) => {\n const checked = selectedRoleIds.includes(role.id)\n const willClear = role.hasPreference && !checked\n return (\n <label key={role.id} className=\"flex items-center gap-2 rounded border bg-background px-2 py-1 text-sm shadow-sm\">\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 accent-foreground\"\n checked={checked}\n onChange={() => toggleRoleSelection(role.id)}\n disabled={savingPreferences}\n />\n <span className=\"flex-1 truncate\">{role.name}</span>\n {role.hasPreference ? (\n <span className={`text-xs ${willClear ? 'text-destructive' : 'text-muted-foreground'}`}>\n {willClear ? t('appShell.sidebarRoleWillClear') : t('appShell.sidebarRoleHasPreset')}\n </span>\n ) : null}\n </label>\n )\n })}\n </div>\n ) : (\n <p className=\"text-xs text-muted-foreground\">{t('appShell.sidebarApplyToRolesEmpty')}</p>\n )}\n </div>\n ) : null}\n {customizationError ? <p className=\"text-xs text-destructive\">{customizationError}</p> : null}\n <div className=\"flex flex-col gap-3\">\n {orderedGroupIds.map((groupId, index) => {\n const baseGroup = baseGroupMap.get(groupId)\n if (!baseGroup) return null\n const currentGroup = navGroups.find((group) => resolveGroupKey(group) === groupId) ?? baseGroup\n const placeholder = baseGroup.defaultName ?? baseGroup.name\n const value = customDraft.groupLabels[groupId] ?? ''\n return (\n <div key={groupId} className=\"flex flex-col gap-3 rounded border bg-background p-3 shadow-sm\">\n <div className={`flex ${compact ? 'flex-col gap-2' : 'items-center gap-2'}`}>\n <div className=\"flex-1\">\n <span className=\"text-xs font-medium text-muted-foreground\">{t('appShell.sidebarCustomizationGroupLabel')}</span>\n <input\n value={value}\n onChange={(event) => setGroupLabel(groupId, event.target.value)}\n placeholder={placeholder}\n disabled={savingPreferences}\n className=\"mt-1 h-8 w-full rounded border bg-background px-2 text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-60\"\n />\n </div>\n <div className=\"flex items-center gap-1 self-start\">\n <IconButton\n variant=\"outline\"\n size=\"sm\"\n className=\"text-muted-foreground hover:text-foreground\"\n onClick={() => moveGroup(groupId, -1)}\n disabled={index === 0 || savingPreferences}\n aria-label={t('appShell.sidebarCustomizationMoveUp')}\n >\n <ChevronUp className=\"size-4\" />\n </IconButton>\n <IconButton\n variant=\"outline\"\n size=\"sm\"\n className=\"text-muted-foreground hover:text-foreground\"\n onClick={() => moveGroup(groupId, 1)}\n disabled={index === orderedGroupIds.length - 1 || savingPreferences}\n aria-label={t('appShell.sidebarCustomizationMoveDown')}\n >\n <ChevronDown className=\"size-4\" />\n </IconButton>\n </div>\n </div>\n <div className=\"flex flex-col gap-2\">\n {renderEditableItems(baseGroup.items, currentGroup.items)}\n </div>\n </div>\n )\n })}\n </div>\n </div>\n ) : (\n <div className=\"rounded border border-dashed bg-muted/20 p-3 text-sm text-muted-foreground\">\n {t('appShell.sidebarCustomizationLoading')}\n </div>\n )\n ) : null\n\n return (\n <div className=\"flex flex-col min-h-full gap-3\">\n {!hideHeader && (\n <div className={`flex items-center ${compact ? 'justify-center' : 'justify-between'} mb-2`}>\n <Link href=\"/backend\" className=\"flex items-center gap-2\" aria-label={t('appShell.goToDashboard')}>\n <Image src=\"/open-mercato.svg\" alt={resolvedProductName} width={32} height={32} className=\"rounded m-4\" />\n {!compact && <div className=\"text-m font-semibold\">{resolvedProductName}</div>}\n </Link>\n </div>\n )}\n {shouldRenderSidebarInjectionSpots ? (\n <InjectionSpot\n spotId={BACKEND_SIDEBAR_TOP_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n <div className=\"flex flex-1 flex-col gap-3 pr-1\">\n {customizing ? (\n customizationEditor\n ) : (\n (() => {\n const isSettingsPath = (href: string) => {\n if (href === '/backend/settings') return true\n return resolvedSettingsPathPrefixes.some((prefix) => href.startsWith(prefix))\n }\n\n const isMainItem = (item: SidebarItem) => {\n if (item.pageContext && item.pageContext !== 'main') return false\n if (isSettingsPath(item.href)) return false\n return true\n }\n\n const mainGroups = mainNavGroupsWithInjected.map((g) => ({\n ...g,\n items: g.items.filter((item) => isMainItem(item) && item.hidden !== true),\n })).filter((g) => g.items.length > 0)\n\n const mainLastVisibleGroupIndex = (() => {\n for (let idx = mainGroups.length - 1; idx >= 0; idx -= 1) {\n if (mainGroups[idx].items.some((item) => item.hidden !== true)) return idx\n }\n return -1\n })()\n\n return (\n <>\n <nav className=\"flex flex-col gap-2\" data-testid=\"sidebar\">\n {shouldRenderSidebarInjectionSpots ? (\n <InjectionSpot\n spotId={BACKEND_SIDEBAR_NAV_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n {mainGroups.map((g, gi) => {\n const groupId = resolveGroupKey(g)\n const open = openGroups[groupId] !== false\n const visibleItems = g.items.filter((item) => item.hidden !== true)\n if (visibleItems.length === 0) return null\n return (\n <div key={groupId}>\n <Button\n variant=\"muted\"\n onClick={() => toggleGroup(groupId)}\n className={`w-full ${compact ? 'px-0 justify-center' : 'px-2 justify-between'} flex text-xs uppercase text-muted-foreground/90 py-2`}\n aria-expanded={open}\n >\n {!compact && <span>{g.name}</span>}\n {!compact && <Chevron open={open} />}\n </Button>\n {open && (\n <div className={`flex flex-col ${compact ? 'items-center' : ''} gap-1 ${!compact ? 'pl-1' : ''}`}>\n {visibleItems.map((i) => {\n const childItems = (i.children ?? []).filter((child) => child.hidden !== true)\n const showChildren = !!pathname && childItems.length > 0 && pathname.startsWith(i.href)\n const hasActiveChild = !!(pathname && childItems.some((c) => pathname.startsWith(c.href)))\n const isParentActive = (pathname === i.href) || (showChildren && !hasActiveChild)\n const base = compact ? 'w-10 h-10 justify-center' : 'px-2 py-1 gap-2'\n return (\n <React.Fragment key={i.href}>\n <Link\n href={i.href}\n className={`relative text-sm rounded inline-flex items-center ${base} ${\n isParentActive ? 'bg-background border shadow-sm' : 'hover:bg-accent hover:text-accent-foreground'\n } ${i.enabled === false ? 'pointer-events-none opacity-50' : ''}`}\n aria-disabled={i.enabled === false}\n title={compact ? i.title : undefined}\n data-menu-item-id={i.id ?? i.href}\n onClick={() => setMobileOpen(false)}\n >\n {isParentActive ? (\n <span className=\"absolute left-0 top-1 bottom-1 w-0.5 rounded bg-foreground\" />\n ) : null}\n <span className={`flex items-center justify-center shrink-0 ${compact ? '' : 'text-muted-foreground'}`}>\n {renderIcon(\n i.icon,\n i.iconName,\n i.iconMarkup,\n DefaultIcon,\n )}\n </span>\n {!compact && <span>{i.title}</span>}\n </Link>\n {showChildren ? (\n <div className={`flex flex-col ${compact ? 'items-center' : ''} gap-1 ${!compact ? 'pl-4' : ''}`}>\n {childItems.map((c) => {\n const childActive = pathname?.startsWith(c.href)\n const childBase = compact ? 'w-10 h-8 justify-center' : 'px-2 py-1 gap-2'\n return (\n <Link\n key={c.href}\n href={c.href}\n className={`relative text-sm rounded inline-flex items-center ${childBase} ${\n childActive ? 'bg-background border shadow-sm' : 'hover:bg-accent hover:text-accent-foreground'\n } ${c.enabled === false ? 'pointer-events-none opacity-50' : ''}`}\n aria-disabled={c.enabled === false}\n title={compact ? c.title : undefined}\n data-menu-item-id={c.id ?? c.href}\n onClick={() => setMobileOpen(false)}\n >\n {childActive ? (\n <span className=\"absolute left-0 top-1 bottom-1 w-0.5 rounded bg-foreground\" />\n ) : null}\n <span className={`flex items-center justify-center shrink-0 ${compact ? '' : 'text-muted-foreground'}`}>\n {renderIcon(\n c.icon,\n c.iconName,\n c.iconMarkup,\n c.href.includes('/backend/entities/user/') && c.href.endsWith('/records') ? DataTableIcon : DefaultIcon,\n )}\n </span>\n {!compact && <span>{c.title}</span>}\n </Link>\n )\n })}\n </div>\n ) : null}\n </React.Fragment>\n )\n })}\n </div>\n )}\n {gi !== mainLastVisibleGroupIndex && <div className=\"my-2 border-t border-dotted\" />}\n </div>\n )\n })}\n </nav>\n </>\n )\n })()\n )}\n </div>\n <div className=\"sticky bottom-0 pt-4 border-t bg-background/60 backdrop-blur-sm pb-1\">\n {shouldRenderSidebarInjectionSpots ? (\n <InjectionSpot\n spotId={BACKEND_SIDEBAR_NAV_FOOTER_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n <Link\n href=\"/backend/settings\"\n className={`relative text-sm rounded inline-flex items-center w-full ${\n compact ? 'w-10 h-10 justify-center' : 'px-2 py-1 gap-2'\n } ${\n pathname?.startsWith('/backend/settings') || pathname?.startsWith('/backend/config') || pathname?.startsWith('/backend/users') || pathname?.startsWith('/backend/roles') || pathname?.startsWith('/backend/api-keys') || pathname?.startsWith('/backend/entities') || pathname?.startsWith('/backend/query-indexes') || pathname?.startsWith('/backend/definitions') || pathname?.startsWith('/backend/instances') || pathname?.startsWith('/backend/tasks') || pathname?.startsWith('/backend/events') || pathname?.startsWith('/backend/rules') || pathname?.startsWith('/backend/sets') || pathname?.startsWith('/backend/logs') || pathname?.startsWith('/backend/directory') || pathname?.startsWith('/backend/feature-toggles')\n ? 'bg-background border shadow-sm font-medium'\n : 'hover:bg-accent hover:text-accent-foreground'\n }`}\n title={compact ? t('backend.nav.settings', 'Settings') : undefined}\n onClick={() => setMobileOpen(false)}\n >\n {(pathname?.startsWith('/backend/settings') || pathname?.startsWith('/backend/config') || pathname?.startsWith('/backend/users') || pathname?.startsWith('/backend/roles') || pathname?.startsWith('/backend/api-keys') || pathname?.startsWith('/backend/entities') || pathname?.startsWith('/backend/query-indexes') || pathname?.startsWith('/backend/definitions') || pathname?.startsWith('/backend/instances') || pathname?.startsWith('/backend/tasks') || pathname?.startsWith('/backend/events') || pathname?.startsWith('/backend/rules') || pathname?.startsWith('/backend/sets') || pathname?.startsWith('/backend/logs') || pathname?.startsWith('/backend/directory') || pathname?.startsWith('/backend/feature-toggles')) && (\n <span className=\"absolute left-0 top-1 bottom-1 w-0.5 rounded bg-foreground\" />\n )}\n <span className={`flex items-center justify-center shrink-0 ${compact ? '' : 'text-muted-foreground'}`}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\" />\n </svg>\n </span>\n {!compact && <span>{t('backend.nav.settings', 'Settings')}</span>}\n </Link>\n {!customizing && (\n <div className=\"mt-2\">\n {shouldRenderSidebarInjectionSpots ? (\n <StatusBadgeInjectionSpot\n spotId={GLOBAL_SIDEBAR_STATUS_BADGES_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n {compact || isMobileVariant ? (\n <IconButton\n variant=\"outline\"\n size=\"lg\"\n onClick={startCustomization}\n disabled={loadingPreferences}\n aria-label={t('appShell.customizeSidebar')}\n >\n {CustomizeIcon}\n </IconButton>\n ) : (\n <Button\n variant=\"outline\"\n size=\"default\"\n onClick={startCustomization}\n disabled={loadingPreferences}\n aria-label={t('appShell.customizeSidebar')}\n >\n {CustomizeIcon}\n {loadingPreferences ? t('appShell.sidebarCustomizationLoading') : t('appShell.customizeSidebar')}\n </Button>\n )}\n </div>\n )}\n {shouldRenderSidebarInjectionSpots ? (\n <InjectionSpot\n spotId={BACKEND_SIDEBAR_FOOTER_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n </div>\n </div>\n )\n }\n\n const gridColsClass = customizing\n ? 'lg:grid-cols-[320px_1fr]'\n : (effectiveCollapsed ? 'lg:grid-cols-[72px_1fr]' : 'lg:grid-cols-[240px_1fr]')\n const headerCtxValue = React.useMemo(() => ({\n setBreadcrumb: setHeaderBreadcrumb,\n setTitle: setHeaderTitle,\n }), [])\n const renderedTopbarInjectedActions = React.useMemo(\n () =>\n topbarInjectedMenuItems.map((item) => {\n const label = resolveInjectedMenuLabel(item, t)\n if (item.href) {\n return (\n <Link\n key={item.id}\n href={item.href}\n className=\"inline-flex items-center rounded border px-2 py-1 text-xs hover:bg-accent hover:text-accent-foreground\"\n data-menu-item-id={item.id}\n >\n {label}\n </Link>\n )\n }\n return (\n <Button\n key={item.id}\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-7 text-xs\"\n data-menu-item-id={item.id}\n onClick={() => item.onClick?.()}\n >\n {label}\n </Button>\n )\n }),\n [t, topbarInjectedMenuItems],\n )\n\n return (\n <HeaderContext.Provider value={headerCtxValue}>\n <div className={`min-h-svh lg:grid ${gridColsClass}`}>\n {/* Desktop sidebar */}\n <aside className={`${asideClassesBase} ${effectiveCollapsed ? 'px-2' : 'px-3'} hidden lg:block`} style={{ width: asideWidth }}>{renderSidebar(effectiveCollapsed)}</aside>\n\n <div className=\"flex min-h-svh flex-col min-w-0\">\n <header className=\"border-b bg-background/60 px-3 lg:px-4 py-2 lg:py-3 flex items-center justify-between gap-2\">\n <div\n data-testid=\"backend-chrome-ready\"\n data-ready={isChromeReady ? 'true' : 'false'}\n className=\"hidden\"\n />\n <div className=\"flex items-center gap-2 min-w-0\">\n {/* Mobile menu button */}\n <IconButton variant=\"outline\" size=\"sm\" className=\"lg:hidden\" aria-label={t('appShell.openMenu')} onClick={() => setMobileOpen(true)}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><path d=\"M3 6h18M3 12h18M3 18h18\"/></svg>\n </IconButton>\n {/* Desktop collapse toggle */}\n <IconButton\n variant=\"outline\"\n size=\"sm\"\n className=\"hidden lg:inline-flex\"\n aria-label={t('appShell.toggleSidebar')}\n onClick={() => setCollapsed((c) => !c)}\n disabled={customizing}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\"/>\n <path d=\"M9 4v16\"/>\n </svg>\n </IconButton>\n {/* Header breadcrumb: always starts with Dashboard */}\n {(() => {\n const dashboardLabel = t('dashboard.title')\n const root: Breadcrumb = [{ label: dashboardLabel, href: '/backend' }]\n let rest: Breadcrumb = []\n if (headerBreadcrumb && headerBreadcrumb.length) {\n const first = headerBreadcrumb[0]\n const dup = first && (first.href === '/backend' || first.label === dashboardLabel || first.label?.toLowerCase() === 'dashboard')\n rest = dup ? headerBreadcrumb.slice(1) : headerBreadcrumb\n } else if (headerTitle) {\n rest = [{ label: headerTitle }]\n }\n const items = [...root, ...rest]\n const lastIndex = items.length - 1\n return (\n <nav className=\"flex items-center gap-2 text-sm min-w-0\">\n {items.map((b, i) => {\n const isLast = i === lastIndex\n const hiddenOnMobile = !isLast ? 'hidden md:inline' : ''\n return (\n <React.Fragment key={i}>\n {i > 0 && <span className={`text-muted-foreground hidden md:inline`}>/</span>}\n {b.href ? (\n <Link href={b.href} className={`text-muted-foreground hover:text-foreground ${hiddenOnMobile}`}>\n {b.label}\n </Link>\n ) : (\n <span className={`font-medium truncate max-w-[45vw] md:max-w-[60vw]`}>{b.label}</span>\n )}\n </React.Fragment>\n )\n })}\n </nav>\n )\n })()}\n </div>\n <div className=\"flex items-center gap-1 md:gap-2 text-sm shrink-0\">\n <StatusBadgeInjectionSpot\n spotId={GLOBAL_HEADER_STATUS_INDICATORS_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n <InjectionSpot\n spotId={BACKEND_TOPBAR_ACTIONS_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n {renderedTopbarInjectedActions}\n {rightHeaderSlot ? (\n rightHeaderSlot\n ) : (\n <span className=\"opacity-80\">{email || t('appShell.userFallback')}</span>\n )}\n </div>\n </header>\n <ProgressTopBar t={t} className=\"sticky top-0 z-10\" />\n <main className=\"flex-1 p-4 lg:p-6\">\n <InjectionSpot spotId={BACKEND_LAYOUT_TOP_INJECTION_SPOT_ID} context={injectionContext} />\n <FlashMessages />\n <PartialIndexBanner />\n <UpgradeActionBanner />\n <LastOperationBanner />\n <InjectionSpot spotId={BACKEND_RECORD_CURRENT_INJECTION_SPOT_ID} context={injectionContext} />\n <InjectionSpot\n spotId={LEGACY_GLOBAL_MUTATION_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n <div id=\"om-top-banners\" className=\"mb-3 space-y-2\" />\n {children}\n <InjectionSpot spotId={BACKEND_LAYOUT_FOOTER_INJECTION_SPOT_ID} context={injectionContext} />\n </main>\n <footer className=\"border-t bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/50 px-4 py-3 flex flex-wrap items-center justify-end gap-4\">\n {version ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('appShell.version', { version })}\n </span>\n ) : null}\n <nav className=\"flex items-center gap-3 text-xs text-muted-foreground\">\n <Link href=\"/terms\" className=\"transition hover:text-foreground\">\n {t('common.terms')}\n </Link>\n <Link href=\"/privacy\" className=\"transition hover:text-foreground\">\n {t('common.privacy')}\n </Link>\n </nav>\n </footer>\n </div>\n\n {/* Mobile drawer */}\n {mobileOpen && (\n <div className=\"lg:hidden fixed inset-0 z-50\">\n <div className=\"absolute inset-0 bg-black/40\" onClick={() => setMobileOpen(false)} aria-hidden=\"true\" />\n <aside className=\"absolute left-0 top-0 flex h-full w-[260px] flex-col bg-background border-r overflow-hidden\">\n <div className=\"shrink-0 p-3 pb-2 flex items-center justify-between border-b\">\n <Link href=\"/backend\" className=\"flex items-center gap-2 text-sm font-semibold\" onClick={() => setMobileOpen(false)} aria-label={t('appShell.goToDashboard')}>\n <Image src=\"/open-mercato.svg\" alt={resolvedProductName} width={28} height={28} className=\"rounded\" />\n {resolvedProductName}\n </Link>\n <IconButton variant=\"outline\" size=\"sm\" onClick={() => setMobileOpen(false)} aria-label={t('appShell.closeMenu')}>\u2715</IconButton>\n </div>\n {mobileSidebarSlot && (\n <div className=\"shrink-0 border-b px-3 py-2\">\n {mobileSidebarSlot}\n </div>\n )}\n <div className=\"min-h-0 flex-1 overflow-y-auto overflow-x-hidden p-3\">\n {/* Force expanded sidebar in mobile drawer, hide its header and collapse toggle */}\n {renderSidebar(false, true)}\n </div>\n </aside>\n </div>\n )}\n </div>\n <UmesDevToolsPanel />\n </HeaderContext.Provider>\n )\n}\n\n// Helper: deep-clone minimal shape we mutate (children arrays)\nAppShell.cloneGroups = function cloneGroups(groups: AppShellProps['groups']): AppShellProps['groups'] {\n const cloneItem = (item: SidebarItem): SidebarItem => ({\n id: item.id,\n href: item.href,\n title: item.title,\n defaultTitle: item.defaultTitle,\n icon: item.icon,\n iconName: item.iconName,\n iconMarkup: item.iconMarkup,\n enabled: item.enabled,\n hidden: item.hidden,\n pageContext: item.pageContext,\n children: item.children ? item.children.map((child) => cloneItem(child)) : undefined,\n })\n return groups.map((group) => ({\n id: group.id,\n name: group.name,\n defaultName: group.defaultName,\n items: group.items.map((item) => cloneItem(item)),\n }))\n}\n\nfunction applyCustomizationDraft(baseGroups: SidebarGroup[], draft: SidebarCustomizationDraft): SidebarGroup[] {\n const clones = AppShell.cloneGroups(baseGroups)\n const byId = new Map<string, SidebarGroup>()\n for (const group of clones) {\n byId.set(resolveGroupKey(group), group)\n }\n const orderedIds = mergeGroupOrder(draft.order, Array.from(byId.keys()))\n const seen = new Set<string>()\n const result: SidebarGroup[] = []\n for (const id of orderedIds) {\n if (seen.has(id)) continue\n const group = byId.get(id)\n if (!group) continue\n seen.add(id)\n const baseName = group.defaultName ?? group.name\n const override = draft.groupLabels[id]?.trim()\n result.push({\n ...group,\n name: override && override.length > 0 ? override : baseName,\n items: group.items.map((item) => applyItemDraft(item, draft)),\n })\n }\n return result\n}\n\nfunction applyItemDraft(item: SidebarItem, draft: SidebarCustomizationDraft): SidebarItem {\n const itemKey = resolveItemKey(item)\n const baseTitle = item.defaultTitle ?? item.title\n const override = draft.itemLabels[itemKey]?.trim()\n const children = item.children\n ? item.children\n .map((child) => applyItemDraft(child, draft))\n : undefined\n const hidden = draft.hiddenItemIds[itemKey] === true\n return {\n ...item,\n title: override && override.length > 0 ? override : baseTitle,\n hidden,\n children,\n }\n}\n\nfunction mergeGroupOrder(preferred: string[], current: string[]): string[] {\n const seen = new Set<string>()\n const merged: string[] = []\n for (const id of preferred) {\n const trimmed = id.trim()\n if (!trimmed || seen.has(trimmed) || !current.includes(trimmed)) continue\n seen.add(trimmed)\n merged.push(trimmed)\n }\n for (const id of current) {\n if (seen.has(id)) continue\n seen.add(id)\n merged.push(id)\n }\n return merged\n}\n\nfunction collectSidebarDefaults(groups: SidebarGroup[]) {\n const groupDefaults = new Map<string, string>()\n const itemDefaults = new Map<string, string>()\n\n const visitItems = (items: SidebarItem[]) => {\n for (const item of items) {\n const key = resolveItemKey(item)\n const baseTitle = item.defaultTitle ?? item.title\n itemDefaults.set(key, baseTitle)\n // Backward-compatible alias for legacy stored href-based preferences.\n itemDefaults.set(item.href, baseTitle)\n if (item.children && item.children.length > 0) visitItems(item.children)\n }\n }\n\n for (const group of groups) {\n const key = resolveGroupKey(group)\n groupDefaults.set(key, group.defaultName ?? group.name)\n visitItems(group.items)\n }\n\n return { groupDefaults, itemDefaults }\n}\n\n/**\n * Filters groups to include only main sidebar items.\n * Excludes items with pageContext 'settings' or 'profile' from customization.\n * Per SPEC-007: Sidebar customization applies only to the main sidebar.\n */\nfunction filterMainSidebarGroups(groups: SidebarGroup[]): SidebarGroup[] {\n const isMainItem = (item: SidebarItem): boolean => {\n if (item.pageContext && item.pageContext !== 'main') return false\n return true\n }\n\n return groups\n .map((group) => ({\n ...group,\n items: group.items.filter(isMainItem).map((item) => ({\n ...item,\n children: item.children?.filter(isMainItem),\n })),\n }))\n .filter((group) => group.items.length > 0)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { createContext, useContext } from 'react'\nimport Link from 'next/link'\nimport Image from 'next/image'\nimport { ChevronUp, ChevronDown } from 'lucide-react'\nimport { Button } from '../primitives/button'\nimport { IconButton } from '../primitives/icon-button'\nimport { Separator } from '../primitives/separator'\nimport { FlashMessages } from './FlashMessages'\nimport { QueryProvider } from '../theme/QueryProvider'\nimport { usePathname, useSearchParams } from 'next/navigation'\nimport { apiCall } from './utils/apiCall'\nimport { LastOperationBanner } from './operations/LastOperationBanner'\nimport { ProgressTopBar } from './progress/ProgressTopBar'\nimport { UpgradeActionBanner } from './upgrades/UpgradeActionBanner'\nimport { PartialIndexBanner } from './indexes/PartialIndexBanner'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { slugifySidebarId } from '@open-mercato/shared/modules/navigation/sidebarPreferences'\nimport type { SectionNavGroup } from './section-page/types'\nimport { InjectionSpot } from './injection/InjectionSpot'\nimport type { InjectionMenuItem } from '@open-mercato/shared/modules/widgets/injection'\nimport { LEGACY_GLOBAL_MUTATION_INJECTION_SPOT_ID } from './injection/mutationEvents'\nimport { mergeMenuItems } from './injection/mergeMenuItems'\nimport { useInjectedMenuItems } from './injection/useInjectedMenuItems'\nimport { resolveInjectedIcon } from './injection/resolveInjectedIcon'\nimport { useEventBridge } from './injection/eventBridge'\nimport { StatusBadgeInjectionSpot } from './injection/StatusBadgeInjectionSpot'\nimport { UmesDevToolsPanel } from './devtools'\nimport { BackendChromeProvider, useBackendChrome } from './BackendChromeProvider'\nimport {\n BACKEND_LAYOUT_FOOTER_INJECTION_SPOT_ID,\n BACKEND_LAYOUT_TOP_INJECTION_SPOT_ID,\n BACKEND_RECORD_CURRENT_INJECTION_SPOT_ID,\n BACKEND_SIDEBAR_FOOTER_INJECTION_SPOT_ID,\n BACKEND_SIDEBAR_TOP_INJECTION_SPOT_ID,\n BACKEND_SIDEBAR_NAV_FOOTER_INJECTION_SPOT_ID,\n BACKEND_SIDEBAR_NAV_INJECTION_SPOT_ID,\n BACKEND_TOPBAR_ACTIONS_INJECTION_SPOT_ID,\n GLOBAL_HEADER_STATUS_INDICATORS_INJECTION_SPOT_ID,\n GLOBAL_SIDEBAR_STATUS_BADGES_INJECTION_SPOT_ID,\n} from './injection/spotIds'\n\nexport type ShellLogo = {\n src: string\n alt?: string\n}\n\nexport type AppShellProps = {\n productName?: string\n logo?: ShellLogo\n email?: string\n groups: {\n id?: string\n name: string\n defaultName?: string\n items: {\n id?: string\n href: string\n title: string\n defaultTitle?: string\n icon?: React.ReactNode\n iconName?: string\n iconMarkup?: string\n enabled?: boolean\n hidden?: boolean\n pageContext?: 'main' | 'admin' | 'settings' | 'profile'\n children?: {\n id?: string\n href: string\n title: string\n defaultTitle?: string\n icon?: React.ReactNode\n iconName?: string\n iconMarkup?: string\n enabled?: boolean\n hidden?: boolean\n pageContext?: 'main' | 'admin' | 'settings' | 'profile'\n }[]\n }[]\n }[]\n children: React.ReactNode\n rightHeaderSlot?: React.ReactNode\n sidebarCollapsedDefault?: boolean\n currentTitle?: string\n breadcrumb?: Array<{ label: string; href?: string }>\n // Optional: full admin nav API to refresh sidebar client-side\n adminNavApi?: string\n version?: string\n settingsSectionTitle?: string\n settingsPathPrefixes?: string[]\n settingsSections?: SectionNavGroup[]\n profileSections?: SectionNavGroup[]\n profileSectionTitle?: string\n profilePathPrefixes?: string[]\n mobileSidebarSlot?: React.ReactNode\n}\n\ntype Breadcrumb = Array<{ label: string; href?: string }>\n\ntype SidebarCustomizationDraft = {\n order: string[]\n groupLabels: Record<string, string>\n itemLabels: Record<string, string>\n hiddenItemIds: Record<string, boolean>\n}\n\ntype SidebarGroup = AppShellProps['groups'][number]\ntype SidebarItem = SidebarGroup['items'][number]\ntype SidebarRoleTarget = { id: string; name: string; hasPreference: boolean }\n\nfunction convertInjectedMenuItemToSidebarItem(item: InjectionMenuItem, title: string): SidebarItem | null {\n if (!item.href) return null\n return {\n id: item.id,\n href: item.href,\n title,\n defaultTitle: title,\n icon: resolveInjectedIcon(item.icon) ?? undefined,\n iconName: item.icon,\n enabled: true,\n hidden: false,\n pageContext: 'main',\n }\n}\n\nfunction resolveInjectedMenuLabel(\n item: { id: string; label?: string; labelKey?: string },\n t: (key: string, fallback?: string) => string,\n): string {\n if (item.labelKey && item.label) return t(item.labelKey, item.label)\n if (item.labelKey) return t(item.labelKey, item.id)\n if (item.label && item.label.includes('.')) return t(item.label, item.id)\n return item.label ?? item.id\n}\n\nfunction mergeSidebarItemsWithInjected(\n items: SidebarItem[],\n injectedItems: InjectionMenuItem[],\n t: (key: string, fallback?: string) => string,\n): SidebarItem[] {\n if (injectedItems.length === 0) return items\n\n const builtInById = new Map<string, SidebarItem>()\n for (const item of items) {\n builtInById.set(item.id ?? item.href, item)\n }\n\n const merged = mergeMenuItems(\n items.map((item) => ({\n id: item.id ?? item.href,\n })),\n injectedItems,\n )\n\n const result: SidebarItem[] = []\n for (const entry of merged) {\n if (entry.source === 'built-in') {\n const original = builtInById.get(entry.id)\n if (original) result.push(original)\n continue\n }\n const translatedLabel = resolveInjectedMenuLabel(\n { id: entry.id, label: entry.label, labelKey: entry.labelKey },\n t,\n )\n const converted = convertInjectedMenuItemToSidebarItem(\n {\n id: entry.id,\n label: translatedLabel,\n icon: entry.icon,\n href: entry.href,\n },\n translatedLabel,\n )\n if (converted) result.push(converted)\n }\n\n return result\n}\n\nfunction mergeSidebarGroupsWithInjected(\n groups: SidebarGroup[],\n injectedItems: InjectionMenuItem[],\n t: (key: string, fallback?: string) => string,\n): SidebarGroup[] {\n if (injectedItems.length === 0) return groups\n\n const injectedByGroup = new Map<string, InjectionMenuItem[]>()\n const ungrouped: InjectionMenuItem[] = []\n\n for (const item of injectedItems) {\n if (item.groupId && item.groupId.trim().length > 0) {\n const groupItems = injectedByGroup.get(item.groupId) ?? []\n groupItems.push(item)\n injectedByGroup.set(item.groupId, groupItems)\n continue\n }\n ungrouped.push(item)\n }\n\n const nextGroups = groups.map((group, index) => {\n const groupId = group.id || resolveGroupKey(group)\n const groupInjected = [\n ...(injectedByGroup.get(groupId) ?? []),\n ...(index === 0 ? ungrouped : []),\n ]\n return {\n ...group,\n items: mergeSidebarItemsWithInjected(group.items, groupInjected, t),\n }\n })\n\n const existingIds = new Set(nextGroups.map((group) => group.id || resolveGroupKey(group)))\n for (const [groupId, items] of injectedByGroup.entries()) {\n if (existingIds.has(groupId)) continue\n const first = items[0]\n const label = first.groupLabelKey\n ? t(first.groupLabelKey, first.groupLabel ?? groupId)\n : (first.groupLabel ?? groupId)\n const groupItems = mergeSidebarItemsWithInjected([], items, t)\n if (groupItems.length === 0) continue\n nextGroups.push({\n id: groupId,\n name: label,\n defaultName: label,\n items: groupItems,\n })\n }\n\n return nextGroups\n}\n\nfunction mergeSectionGroupsWithInjected(\n sections: SectionNavGroup[],\n injectedItems: InjectionMenuItem[],\n t: (key: string, fallback?: string) => string,\n): SectionNavGroup[] {\n if (injectedItems.length === 0) return sections\n const byGroup = new Map<string, InjectionMenuItem[]>()\n for (const item of injectedItems) {\n const groupId = item.groupId && item.groupId.trim().length > 0 ? item.groupId : 'injected'\n const bucket = byGroup.get(groupId) ?? []\n bucket.push(item)\n byGroup.set(groupId, bucket)\n }\n\n const nextSections = sections.map((section) => {\n const sectionItems = byGroup.get(section.id) ?? []\n if (sectionItems.length === 0) return section\n const mergedItems = mergeMenuItems(\n section.items.map((item) => ({ id: item.id, item })),\n sectionItems,\n ).flatMap((item) => {\n if (item.source === 'built-in') {\n const original = section.items.find((entry) => entry.id === item.id)\n return original ? [original] : []\n }\n if (!item.href) return []\n const label = resolveInjectedMenuLabel(item, t)\n return [{\n id: item.id,\n label,\n href: item.href,\n icon: resolveInjectedIcon(item.icon) ?? undefined,\n }]\n })\n return {\n ...section,\n items: mergedItems,\n }\n })\n\n for (const [sectionId, sectionItems] of byGroup.entries()) {\n const exists = nextSections.some((section) => section.id === sectionId)\n if (exists) continue\n const first = sectionItems[0]\n const label = first.groupLabelKey\n ? t(first.groupLabelKey, first.groupLabel ?? sectionId)\n : (first.groupLabel ?? sectionId)\n const items = sectionItems.flatMap((item) => {\n if (!item.href) return []\n const itemLabel = resolveInjectedMenuLabel(item, t)\n return [{\n id: item.id,\n label: itemLabel,\n href: item.href,\n icon: resolveInjectedIcon(item.icon) ?? undefined,\n }]\n })\n if (items.length === 0) continue\n nextSections.push({ id: sectionId, label, items })\n }\n\n return nextSections\n}\n\nfunction resolveGroupKey(group: SidebarGroup): string {\n if (group.id && group.id.length) return group.id\n if (group.defaultName && group.defaultName.length) return slugifySidebarId(group.defaultName)\n return slugifySidebarId(group.name)\n}\n\nfunction resolveItemKey(item: { id?: string; href: string }): string {\n const candidate = item.id?.trim()\n if (candidate && candidate.length > 0) return candidate\n return item.href\n}\n\nfunction SerializedIcon({ markup }: { markup: string }) {\n return <span aria-hidden=\"true\" dangerouslySetInnerHTML={{ __html: markup }} />\n}\n\nfunction renderIcon(\n icon: React.ReactNode | undefined,\n iconName: string | undefined,\n iconMarkup: string | undefined,\n fallback: React.ReactNode,\n) {\n if (icon) return icon\n if (iconName) {\n const resolved = resolveInjectedIcon(iconName)\n if (resolved) return resolved\n }\n if (iconMarkup) return <SerializedIcon markup={iconMarkup} />\n return fallback\n}\n\nconst HeaderContext = createContext<{\n setBreadcrumb: (b?: Breadcrumb) => void\n setTitle: (t?: string) => void\n} | null>(null)\n\nexport function ApplyBreadcrumb({ breadcrumb, title, titleKey }: { breadcrumb?: Array<{ label: string; href?: string; labelKey?: string }>; title?: string; titleKey?: string }) {\n const ctx = useContext(HeaderContext)\n const t = useT()\n const resolvedBreadcrumb = React.useMemo<Breadcrumb | undefined>(() => {\n if (!breadcrumb) return undefined\n return breadcrumb.map(({ label, labelKey, href }) => {\n const translated = labelKey ? t(labelKey) : undefined\n const finalLabel = translated && translated !== labelKey ? translated : label\n return {\n href,\n label: finalLabel,\n }\n })\n }, [breadcrumb, t])\n const resolvedTitle = React.useMemo(() => {\n if (!titleKey) return title\n const translated = t(titleKey)\n if (translated && translated !== titleKey) return translated\n return title\n }, [titleKey, title, t])\n React.useEffect(() => {\n ctx?.setBreadcrumb(resolvedBreadcrumb)\n if (resolvedTitle !== undefined) ctx?.setTitle(resolvedTitle)\n }, [ctx, resolvedBreadcrumb, resolvedTitle])\n return null\n}\n\nconst DefaultIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M8 6h13M8 12h13M8 18h13\"/>\n <path d=\"M3 6h.01M3 12h.01M3 18h.01\"/>\n </svg>\n)\n\n// DataTable icon used for dynamic custom entity records links\nconst DataTableIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\" ry=\"2\"/>\n <line x1=\"3\" y1=\"8\" x2=\"21\" y2=\"8\"/>\n <line x1=\"9\" y1=\"8\" x2=\"9\" y2=\"20\"/>\n <line x1=\"15\" y1=\"8\" x2=\"15\" y2=\"20\"/>\n </svg>\n)\n\nconst CustomizeIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.05.05a2 2 0 1 1-2.83 2.83l-.05-.05A1.65 1.65 0 0 0 15 19.4a1.65 1.65 0 0 0-1 .6 1.65 1.65 0 0 0-.33 1.82l-.05.05a2 2 0 1 1-2.83-2.83l.05-.05A1.65 1.65 0 0 0 9 15a1.65 1.65 0 0 0-1-.6 1.65 1.65 0 0 0-1.82.33l-.05.05a2 2 0 1 1-2.83-2.83l.05-.05A1.65 1.65 0 0 0 4.6 9 1.65 1.65 0 0 0 4 8a1.65 1.65 0 0 0-.6-1.82l-.05-.05a2 2 0 1 1 2.83-2.83l.05.05A1.65 1.65 0 0 0 9 4.6a1.65 1.65 0 0 0 1-.6 1.65 1.65 0 0 0 .33-1.82l.05-.05a2 2 0 1 1 2.83 2.83l-.05.05A1.65 1.65 0 0 0 15 9a1.65 1.65 0 0 0 1 .6 1.65 1.65 0 0 0 1.82-.33l.05-.05a2 2 0 1 1 2.83 2.83l-.05.05A1.65 1.65 0 0 0 19.4 15z\" />\n </svg>\n)\n\nconst BackArrowIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M19 12H5M12 19l-7-7 7-7\" />\n </svg>\n)\n\nfunction Chevron({ open }: { open: boolean }) {\n return (\n <svg className={`transition-transform ${open ? 'rotate-180' : ''}`} width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><path d=\"M6 9l6 6 6-6\"/></svg>\n )\n}\n\nexport function AppShell(props: AppShellProps) {\n return (\n <QueryProvider>\n <BackendChromeProvider adminNavApi={props.adminNavApi}>\n <AppShellBody {...props} />\n </BackendChromeProvider>\n </QueryProvider>\n )\n}\n\nfunction AppShellBody({ productName, logo, email, groups, rightHeaderSlot, children, sidebarCollapsedDefault = false, currentTitle, breadcrumb, version, settingsSectionTitle, settingsPathPrefixes = [], settingsSections, profileSections, profileSectionTitle, profilePathPrefixes = [], mobileSidebarSlot }: AppShellProps) {\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const t = useT()\n const locale = useLocale()\n const { payload: chromePayload, isReady: isChromeReady, isLoading: isChromeLoading } = useBackendChrome()\n const resolvedGroups = React.useMemo(\n () => AppShell.cloneGroups(chromePayload?.groups ?? groups),\n [chromePayload?.groups, groups],\n )\n const resolvedSettingsSections = chromePayload?.settingsSections ?? settingsSections\n const resolvedSettingsPathPrefixes = chromePayload?.settingsPathPrefixes ?? settingsPathPrefixes\n const resolvedProfileSections = chromePayload?.profileSections ?? profileSections\n const resolvedProfilePathPrefixes = chromePayload?.profilePathPrefixes ?? profilePathPrefixes\n const { items: mainSidebarInjectedMenuItems } = useInjectedMenuItems('menu:sidebar:main')\n const { items: settingsSidebarInjectedMenuItems } = useInjectedMenuItems('menu:sidebar:settings')\n const { items: profileSidebarInjectedMenuItems } = useInjectedMenuItems('menu:sidebar:profile')\n const { items: topbarInjectedMenuItems } = useInjectedMenuItems('menu:topbar:actions')\n useEventBridge() // SSE DOM Event Bridge \u2014 singleton SSE connection for real-time server events\n const resolvedProductName = productName ?? t('appShell.productName')\n const [mobileOpen, setMobileOpen] = React.useState(false)\n // Initialize from server-provided prop only to avoid hydration flicker\n const [collapsed, setCollapsed] = React.useState(sidebarCollapsedDefault)\n // Maintain internal nav state so we can augment it client-side\n const [navGroups, setNavGroups] = React.useState(resolvedGroups)\n const [openGroups, setOpenGroups] = React.useState<Record<string, boolean>>(() =>\n Object.fromEntries(resolvedGroups.map((g) => [resolveGroupKey(g), true])) as Record<string, boolean>\n )\n const [customizing, setCustomizing] = React.useState(false)\n const [customDraft, setCustomDraft] = React.useState<SidebarCustomizationDraft | null>(null)\n const [loadingPreferences, setLoadingPreferences] = React.useState(false)\n const [savingPreferences, setSavingPreferences] = React.useState(false)\n const [customizationError, setCustomizationError] = React.useState<string | null>(null)\n const [availableRoleTargets, setAvailableRoleTargets] = React.useState<SidebarRoleTarget[]>([])\n const [selectedRoleIds, setSelectedRoleIds] = React.useState<string[]>([])\n const [canApplyToRoles, setCanApplyToRoles] = React.useState(false)\n const originalNavRef = React.useRef<SidebarGroup[] | null>(null)\n const [headerTitle, setHeaderTitle] = React.useState<string | undefined>(currentTitle)\n const [headerBreadcrumb, setHeaderBreadcrumb] = React.useState<Breadcrumb | undefined>(breadcrumb)\n const effectiveCollapsed = customizing ? false : collapsed\n const expandedSidebarWidth = customizing ? '320px' : '240px'\n const injectionContext = React.useMemo(\n () => ({\n path: pathname ?? '',\n query: searchParams?.toString() ?? '',\n }),\n [pathname, searchParams],\n )\n\n const isOnSettingsPath = React.useMemo(() => {\n if (!pathname) return false\n if (pathname === '/backend/settings') return true\n return resolvedSettingsPathPrefixes.some((prefix) => pathname.startsWith(prefix))\n }, [pathname, resolvedSettingsPathPrefixes])\n\n const isOnProfilePath = React.useMemo(() => {\n if (!pathname) return false\n if (pathname === '/backend/profile') return true\n return resolvedProfilePathPrefixes.some((prefix) => pathname.startsWith(prefix))\n }, [pathname, resolvedProfilePathPrefixes])\n\n const sidebarMode: 'main' | 'settings' | 'profile' =\n isOnSettingsPath ? 'settings' :\n isOnProfilePath ? 'profile' :\n 'main'\n\n const mainNavGroupsWithInjected = React.useMemo(\n () => mergeSidebarGroupsWithInjected(navGroups, mainSidebarInjectedMenuItems, t),\n [mainSidebarInjectedMenuItems, navGroups, t],\n )\n\n // Lock body scroll when mobile drawer is open so touch scroll stays in the drawer\n React.useEffect(() => {\n if (!mobileOpen || typeof document === 'undefined') return\n const prev = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n return () => {\n document.body.style.overflow = prev\n }\n }, [mobileOpen])\n\n React.useEffect(() => {\n try {\n const savedOpen = typeof window !== 'undefined' ? localStorage.getItem('om:sidebarOpenGroups') : null\n if (!savedOpen) return\n const parsed = JSON.parse(savedOpen) as Record<string, boolean>\n setOpenGroups((prev) => {\n const next = { ...prev }\n for (const group of resolvedGroups) {\n const key = resolveGroupKey(group)\n if (key in parsed) next[key] = !!parsed[key]\n else if (group.name in parsed) next[key] = !!parsed[group.name]\n }\n return next\n })\n } catch {\n // ignore localStorage errors to avoid breaking hydration\n }\n }, [resolvedGroups])\n\n const toggleGroup = (groupId: string) => setOpenGroups((prev) => ({ ...prev, [groupId]: prev[groupId] === false }))\n\n const updateDraft = React.useCallback((updater: (draft: SidebarCustomizationDraft) => SidebarCustomizationDraft) => {\n setCustomDraft((prev) => {\n if (!prev) return prev\n const next = updater(prev)\n if (originalNavRef.current) {\n setNavGroups(applyCustomizationDraft(originalNavRef.current, next))\n }\n return next\n })\n }, [])\n\n const startCustomization = React.useCallback(async () => {\n if (customizing || loadingPreferences) return\n setCustomizationError(null)\n setLoadingPreferences(true)\n try {\n const baseSnapshot = filterMainSidebarGroups(AppShell.cloneGroups(navGroups))\n const call = await apiCall<{\n settings?: Record<string, unknown>\n canApplyToRoles?: boolean\n roles?: Array<{ id?: string; name?: string; hasPreference?: boolean }>\n }>('/api/auth/sidebar/preferences')\n const data = call.ok ? (call.result ?? null) : null\n const rawSettings = data?.settings\n const responseOrder = Array.isArray(rawSettings?.groupOrder)\n ? rawSettings.groupOrder\n .map((id: unknown) => (typeof id === 'string' ? id.trim() : ''))\n .filter((id: string) => id.length > 0)\n : []\n const responseGroupLabels: Record<string, string> = {}\n if (rawSettings?.groupLabels && typeof rawSettings.groupLabels === 'object') {\n for (const [key, value] of Object.entries(rawSettings.groupLabels as Record<string, unknown>)) {\n if (typeof value !== 'string') continue\n const trimmedKey = key.trim()\n if (!trimmedKey) continue\n responseGroupLabels[trimmedKey] = value\n }\n }\n const responseItemLabels: Record<string, string> = {}\n if (rawSettings?.itemLabels && typeof rawSettings.itemLabels === 'object') {\n for (const [key, value] of Object.entries(rawSettings.itemLabels as Record<string, unknown>)) {\n if (typeof value !== 'string') continue\n const trimmedKey = key.trim()\n if (!trimmedKey) continue\n responseItemLabels[trimmedKey] = value\n }\n }\n const responseHiddenItems = Array.isArray(rawSettings?.hiddenItems)\n ? rawSettings.hiddenItems\n .map((itemId: unknown) => (typeof itemId === 'string' ? itemId.trim() : ''))\n .filter((itemId: string) => itemId.length > 0)\n : []\n const canManageRoles = data?.canApplyToRoles === true\n setCanApplyToRoles(canManageRoles)\n if (canManageRoles) {\n const roles = Array.isArray(data?.roles)\n ? (data.roles as Array<{ id?: string; name?: string; hasPreference?: boolean }>).filter((role) => typeof role?.id === 'string' && typeof role?.name === 'string')\n : []\n const mappedRoles: SidebarRoleTarget[] = roles.map((role) => ({\n id: role.id as string,\n name: role.name as string,\n hasPreference: role.hasPreference === true,\n }))\n setAvailableRoleTargets(mappedRoles)\n setSelectedRoleIds(mappedRoles.filter((role) => role.hasPreference).map((role) => role.id))\n } else {\n setAvailableRoleTargets([])\n setSelectedRoleIds([])\n }\n const currentIds = baseSnapshot.map((group) => resolveGroupKey(group))\n const order = mergeGroupOrder(responseOrder, currentIds)\n const { itemDefaults } = collectSidebarDefaults(baseSnapshot)\n const hiddenItemIds: Record<string, boolean> = {}\n for (const itemId of responseHiddenItems) {\n if (!itemDefaults.has(itemId)) continue\n hiddenItemIds[itemId] = true\n }\n const draft: SidebarCustomizationDraft = {\n order,\n groupLabels: { ...responseGroupLabels },\n itemLabels: { ...responseItemLabels },\n hiddenItemIds,\n }\n originalNavRef.current = baseSnapshot\n setCustomDraft(draft)\n setNavGroups(applyCustomizationDraft(baseSnapshot, draft))\n setCustomizing(true)\n } catch (error) {\n console.error('Failed to load sidebar preferences', error)\n setCustomizationError(t('appShell.sidebarCustomizationLoadError'))\n } finally {\n setLoadingPreferences(false)\n }\n }, [customizing, loadingPreferences, navGroups, t])\n\n const cancelCustomization = React.useCallback(() => {\n setCustomizing(false)\n setCustomDraft(null)\n setCustomizationError(null)\n setAvailableRoleTargets([])\n setSelectedRoleIds([])\n setCanApplyToRoles(false)\n if (originalNavRef.current) {\n setNavGroups(AppShell.cloneGroups(originalNavRef.current))\n }\n originalNavRef.current = null\n }, [])\n\n const resetCustomization = React.useCallback(() => {\n if (!originalNavRef.current) return\n const base = AppShell.cloneGroups(originalNavRef.current)\n const order = base.map((group) => resolveGroupKey(group))\n const draft: SidebarCustomizationDraft = { order, groupLabels: {}, itemLabels: {}, hiddenItemIds: {} }\n originalNavRef.current = base\n setCustomDraft(draft)\n setNavGroups(applyCustomizationDraft(base, draft))\n if (canApplyToRoles) {\n setSelectedRoleIds(availableRoleTargets.filter((role) => role.hasPreference).map((role) => role.id))\n }\n }, [availableRoleTargets, canApplyToRoles])\n\n const saveCustomization = React.useCallback(async () => {\n if (!customDraft) return\n setSavingPreferences(true)\n setCustomizationError(null)\n try {\n const baseGroups = originalNavRef.current ?? filterMainSidebarGroups(AppShell.cloneGroups(navGroups))\n const { groupDefaults, itemDefaults } = collectSidebarDefaults(baseGroups)\n const sanitizedGroupLabels: Record<string, string> = {}\n for (const [key, value] of Object.entries(customDraft.groupLabels)) {\n const trimmed = value.trim()\n const base = groupDefaults.get(key)\n if (!trimmed || !base) continue\n if (trimmed !== base) sanitizedGroupLabels[key] = trimmed\n }\n const sanitizedItemLabels: Record<string, string> = {}\n for (const [itemId, value] of Object.entries(customDraft.itemLabels)) {\n const trimmed = value.trim()\n const base = itemDefaults.get(itemId)\n if (!trimmed || !base) continue\n if (trimmed !== base) sanitizedItemLabels[itemId] = trimmed\n }\n const sanitizedHiddenItems: string[] = []\n for (const [itemId, hidden] of Object.entries(customDraft.hiddenItemIds)) {\n if (!hidden) continue\n if (!itemDefaults.has(itemId)) continue\n sanitizedHiddenItems.push(itemId)\n }\n const applyToRolesPayload = canApplyToRoles ? [...selectedRoleIds] : []\n const clearRoleIdsPayload = canApplyToRoles\n ? availableRoleTargets\n .filter((role) => role.hasPreference && !selectedRoleIds.includes(role.id))\n .map((role) => role.id)\n : []\n const payload: Record<string, unknown> = {\n groupOrder: customDraft.order,\n groupLabels: sanitizedGroupLabels,\n itemLabels: sanitizedItemLabels,\n hiddenItems: sanitizedHiddenItems,\n }\n if (canApplyToRoles) {\n payload.applyToRoles = applyToRolesPayload\n payload.clearRoleIds = clearRoleIdsPayload\n }\n const call = await apiCall<{\n canApplyToRoles?: boolean\n roles?: Array<{ id?: string; name?: string; hasPreference?: boolean }>\n }>('/api/auth/sidebar/preferences', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!call.ok) {\n setCustomizationError(t('appShell.sidebarCustomizationSaveError'))\n return\n }\n const data = call.result ?? null\n if (data?.canApplyToRoles !== undefined) {\n setCanApplyToRoles(data.canApplyToRoles === true)\n }\n if (Array.isArray(data?.roles)) {\n const mappedRoles: SidebarRoleTarget[] = (data.roles as Array<{ id?: string; name?: string; hasPreference?: boolean }>).filter((role) => typeof role?.id === 'string' && typeof role?.name === 'string').map((role) => ({\n id: role.id as string,\n name: role.name as string,\n hasPreference: role.hasPreference === true,\n }))\n setAvailableRoleTargets(mappedRoles)\n setSelectedRoleIds(mappedRoles.filter((role) => role.hasPreference).map((role) => role.id))\n }\n originalNavRef.current = applyCustomizationDraft(baseGroups, customDraft)\n setNavGroups(AppShell.cloneGroups(originalNavRef.current))\n setCustomizing(false)\n setCustomDraft(null)\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n } catch (error) {\n console.error('Failed to save sidebar preferences', error)\n setCustomizationError(t('appShell.sidebarCustomizationSaveError'))\n } finally {\n setSavingPreferences(false)\n }\n }, [customDraft, navGroups, t])\n\n const moveGroup = React.useCallback((groupId: string, offset: number) => {\n updateDraft((draft) => {\n const order = [...draft.order]\n const index = order.indexOf(groupId)\n if (index === -1) return draft\n const nextIndex = Math.max(0, Math.min(order.length - 1, index + offset))\n if (nextIndex === index) return draft\n order.splice(index, 1)\n order.splice(nextIndex, 0, groupId)\n return { ...draft, order }\n })\n }, [updateDraft])\n\n const setGroupLabel = React.useCallback((groupId: string, value: string) => {\n updateDraft((draft) => {\n const next = { ...draft.groupLabels }\n if (value.trim().length === 0) delete next[groupId]\n else next[groupId] = value\n return { ...draft, groupLabels: next }\n })\n }, [updateDraft])\n\n const setItemLabel = React.useCallback((itemId: string, value: string) => {\n updateDraft((draft) => {\n const next = { ...draft.itemLabels }\n if (value.trim().length === 0) delete next[itemId]\n else next[itemId] = value\n return { ...draft, itemLabels: next }\n })\n }, [updateDraft])\n const setItemHidden = React.useCallback((itemId: string, hidden: boolean) => {\n updateDraft((draft) => {\n const next = { ...draft.hiddenItemIds }\n if (hidden) next[itemId] = true\n else delete next[itemId]\n return { ...draft, hiddenItemIds: next }\n })\n }, [updateDraft])\n\n const toggleRoleSelection = React.useCallback((roleId: string) => {\n setSelectedRoleIds((prev) => (prev.includes(roleId) ? prev.filter((id) => id !== roleId) : [...prev, roleId]))\n }, [])\n\n const asideWidth = effectiveCollapsed ? '72px' : expandedSidebarWidth\n // Use min-h-svh so the border extends with tall content; no overflow so sticky bottom works\n const asideClassesBase = `border-r bg-background/60 py-4 min-h-svh`;\n\n // Persist collapse state to localStorage and cookie\n React.useEffect(() => {\n try { localStorage.setItem('om:sidebarCollapsed', collapsed ? '1' : '0') } catch {}\n try {\n document.cookie = `om_sidebar_collapsed=${collapsed ? '1' : '0'}; path=/; max-age=31536000; samesite=lax`\n } catch {}\n }, [collapsed])\n React.useEffect(() => {\n try { localStorage.setItem('om:sidebarOpenGroups', JSON.stringify(openGroups)) } catch {}\n }, [openGroups])\n\n // Ensure current route's group is expanded on load\n React.useEffect(() => {\n const activeGroup = navGroups.find((g) => g.items.some((i) => pathname?.startsWith(i.href)))\n if (!activeGroup) return\n const key = resolveGroupKey(activeGroup)\n setOpenGroups((prev) => (prev[key] === false ? { ...prev, [key]: true } : prev))\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pathname, navGroups])\n // Keep header state in sync with props (server-side updates)\n React.useEffect(() => {\n setHeaderTitle(currentTitle)\n setHeaderBreadcrumb(breadcrumb)\n }, [currentTitle, breadcrumb])\n // Clear breadcrumb on client-side navigation so stale state doesn't persist;\n // the new page's ApplyBreadcrumb (if any) will set the correct values\n const prevPathname = React.useRef(pathname)\n React.useEffect(() => {\n if (pathname !== prevPathname.current) {\n prevPathname.current = pathname\n setHeaderTitle(undefined)\n setHeaderBreadcrumb(undefined)\n }\n }, [pathname])\n\n // Keep navGroups in sync when server-provided groups change\n React.useEffect(() => {\n if (customizing && customDraft && originalNavRef.current) {\n originalNavRef.current = filterMainSidebarGroups(AppShell.cloneGroups(resolvedGroups))\n setNavGroups(applyCustomizationDraft(originalNavRef.current, customDraft))\n return\n }\n setNavGroups(AppShell.cloneGroups(resolvedGroups))\n }, [resolvedGroups, customizing, customDraft])\n\n function renderSectionSidebar(\n sections: SectionNavGroup[],\n title: string,\n compact: boolean,\n hideHeader?: boolean\n ) {\n const sortedSections = [...sections].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))\n const lastVisibleIndex = sortedSections.length - 1\n\n return (\n <div className=\"flex flex-col min-h-full gap-3\">\n {!hideHeader && (\n <div className={`flex items-center ${compact ? 'justify-center' : 'justify-between'} mb-2`}>\n <Link href=\"/backend\" className=\"flex items-center gap-2\" aria-label={t('appShell.goToDashboard')}>\n <Image src={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? resolvedProductName} width={32} height={32} className=\"rounded m-4\" />\n {!compact && <div className=\"text-m font-semibold\">{resolvedProductName}</div>}\n </Link>\n </div>\n )}\n <div className=\"flex flex-1 flex-col gap-3 overflow-y-auto pr-1\">\n <Link\n href=\"/backend\"\n className={`flex items-center gap-2 ${compact ? 'justify-center px-2' : 'px-2'} py-1 text-sm text-muted-foreground hover:text-foreground transition-colors`}\n aria-label={t('backend.nav.backToMain', 'Back')}\n >\n <span className=\"flex items-center justify-center shrink-0\">{BackArrowIcon}</span>\n {!compact && <span>{title}</span>}\n </Link>\n <nav className=\"flex flex-col gap-2\">\n {sortedSections.map((section, sectionIndex) => {\n const visibleItems = section.items\n if (visibleItems.length === 0) return null\n const sortedItems = [...visibleItems].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))\n const sectionLabel = section.labelKey ? t(section.labelKey, section.label) : section.label\n const sectionKey = `settings:${section.id}`\n const open = openGroups[sectionKey] !== false\n const sortSectionItems = (items: typeof section.items = []) =>\n [...items].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))\n\n const renderSectionItem = (item: (typeof section.items)[number], depth = 0): React.ReactNode => {\n const label = item.labelKey ? t(item.labelKey, item.label) : item.label\n const childItems = sortSectionItems(item.children)\n const isOnItemBranch = !!pathname && (\n pathname === item.href ||\n pathname.startsWith(`${item.href}/`)\n )\n const hasActiveChild = !!(pathname && childItems.some((child) => (\n pathname === child.href ||\n pathname.startsWith(`${child.href}/`)\n )))\n const showChildren = childItems.length > 0 && isOnItemBranch\n const isActive = isOnItemBranch || hasActiveChild\n const base = compact ? 'w-10 h-10 justify-center' : 'py-1 gap-2'\n const spacingStyle = !compact\n ? {\n paddingLeft: `${8 + depth * 16}px`,\n paddingRight: '8px',\n }\n : undefined\n\n return (\n <React.Fragment key={item.id}>\n <Link\n href={item.href}\n className={`relative text-sm rounded inline-flex items-center ${base} ${\n isActive\n ? 'bg-background border shadow-sm'\n : 'hover:bg-accent hover:text-accent-foreground'\n }`}\n style={spacingStyle}\n title={compact ? label : undefined}\n data-menu-item-id={item.id}\n onClick={() => setMobileOpen(false)}\n >\n {isActive && (\n <span className=\"absolute left-0 top-1 bottom-1 w-0.5 rounded bg-foreground\" />\n )}\n <span className={`flex items-center justify-center shrink-0 ${compact ? '' : 'text-muted-foreground'}`}>\n {renderIcon(\n item.icon,\n item.iconName,\n item.iconMarkup,\n item.href.includes('/backend/entities/user/') && item.href.endsWith('/records') ? DataTableIcon : DefaultIcon,\n )}\n </span>\n {!compact && <span className=\"truncate\">{label}</span>}\n </Link>\n {showChildren ? childItems.map((child) => renderSectionItem(child, depth + 1)) : null}\n </React.Fragment>\n )\n }\n\n return (\n <div key={section.id}>\n <Button\n variant=\"muted\"\n onClick={() => toggleGroup(sectionKey)}\n className={`w-full ${compact ? 'px-0 justify-center' : 'px-2 justify-between'} flex text-xs uppercase text-muted-foreground/90 py-2`}\n aria-expanded={open}\n >\n {!compact && <span>{sectionLabel}</span>}\n {!compact && <Chevron open={open} />}\n </Button>\n {open && (\n <div className={`flex flex-col ${compact ? 'items-center' : ''} gap-1 ${!compact ? 'pl-1' : ''}`}>\n {sortedItems.map((item) => renderSectionItem(item))}\n </div>\n )}\n {sectionIndex !== lastVisibleIndex && <div className=\"my-2 border-t border-dotted\" />}\n </div>\n )\n })}\n </nav>\n </div>\n </div>\n )\n }\n\n function renderSidebar(compact: boolean, hideHeader?: boolean) {\n if (!isChromeReady && isChromeLoading && resolvedGroups.length === 0) {\n return (\n <div className=\"flex flex-col min-h-full gap-3\" data-testid=\"backend-chrome-loading\">\n {!hideHeader ? (\n <div className={`flex items-center ${compact ? 'justify-center' : 'justify-between'} mb-2`}>\n <Link href=\"/backend\" className=\"flex items-center gap-2\" aria-label={t('appShell.goToDashboard')}>\n <Image src={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? resolvedProductName} width={32} height={32} className=\"rounded m-4\" />\n {!compact && <div className=\"text-m font-semibold\">{resolvedProductName}</div>}\n </Link>\n </div>\n ) : null}\n <div className=\"flex flex-1 flex-col gap-3 pr-1\">\n <div className=\"space-y-3\">\n <div className=\"h-8 rounded bg-muted/60\" />\n <div className=\"space-y-2 pl-1\">\n <div className=\"h-8 rounded bg-muted/50\" />\n <div className=\"h-8 rounded bg-muted/40\" />\n <div className=\"h-8 rounded bg-muted/40\" />\n </div>\n </div>\n <div className=\"space-y-3\">\n <div className=\"h-8 rounded bg-muted/60\" />\n <div className=\"space-y-2 pl-1\">\n <div className=\"h-8 rounded bg-muted/40\" />\n <div className=\"h-8 rounded bg-muted/40\" />\n </div>\n </div>\n </div>\n </div>\n )\n }\n\n if (sidebarMode === 'settings' && resolvedSettingsSections && resolvedSettingsSections.length > 0) {\n const mergedSettingsSections = mergeSectionGroupsWithInjected(\n resolvedSettingsSections,\n settingsSidebarInjectedMenuItems,\n t,\n )\n return renderSectionSidebar(\n mergedSettingsSections,\n settingsSectionTitle ?? t('backend.nav.settings', 'Settings'),\n compact,\n hideHeader\n )\n }\n\n if (sidebarMode === 'profile' && resolvedProfileSections && resolvedProfileSections.length > 0) {\n const mergedProfileSections = mergeSectionGroupsWithInjected(\n resolvedProfileSections,\n profileSidebarInjectedMenuItems,\n t,\n )\n return renderSectionSidebar(\n mergedProfileSections,\n profileSectionTitle ?? t('backend.nav.profile', 'Profile'),\n compact,\n hideHeader\n )\n }\n\n const isMobileVariant = !!hideHeader\n const shouldRenderSidebarInjectionSpots = !isMobileVariant\n const baseGroupsForDefaults = originalNavRef.current ?? mainNavGroupsWithInjected\n const baseGroupMap = new Map<string, SidebarGroup>()\n for (const group of baseGroupsForDefaults) {\n baseGroupMap.set(resolveGroupKey(group), group)\n }\n const localeLabel = (locale || '').toUpperCase()\n\n const orderedGroupIds = customDraft\n ? mergeGroupOrder(customDraft.order, Array.from(baseGroupMap.keys()))\n : mainNavGroupsWithInjected.map((group) => resolveGroupKey(group))\n\n const lastVisibleGroupIndex = (() => {\n for (let idx = navGroups.length - 1; idx >= 0; idx -= 1) {\n if (navGroups[idx].items.some((item) => item.hidden !== true)) return idx\n }\n return -1\n })()\n\n const renderEditableItems = (baseItems: SidebarItem[], currentItems: SidebarItem[], depth = 0): React.ReactNode => {\n if (!customDraft) return null\n return baseItems.map((baseItem) => {\n const itemKey = resolveItemKey(baseItem)\n const current = currentItems.find((item) => item.href === baseItem.href) ?? baseItem\n const placeholder = baseItem.defaultTitle ?? baseItem.title\n const value = customDraft.itemLabels[itemKey] ?? ''\n const hidden = customDraft.hiddenItemIds[itemKey] === true\n return (\n <div\n key={itemKey}\n className={`flex flex-col gap-1 ${hidden ? 'opacity-60' : ''}`}\n style={depth ? { marginLeft: depth * 16 } : undefined}\n >\n <span className=\"text-xs font-medium text-muted-foreground\">{placeholder}</span>\n <div className=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 accent-foreground\"\n checked={!hidden}\n onChange={(event) => setItemHidden(itemKey, !event.target.checked)}\n disabled={savingPreferences}\n aria-label={t('appShell.sidebarCustomizationShowItem')}\n title={t('appShell.sidebarCustomizationShowItem')}\n />\n <input\n value={value}\n onChange={(event) => setItemLabel(itemKey, event.target.value)}\n placeholder={placeholder}\n disabled={savingPreferences}\n className=\"h-8 flex-1 rounded border bg-background px-2 text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-60\"\n />\n </div>\n {baseItem.children && baseItem.children.length > 0 ? (\n <div className=\"flex flex-col gap-1\">\n {renderEditableItems(baseItem.children, current.children ?? [], depth + 1)}\n </div>\n ) : null}\n </div>\n )\n })\n }\n\n const customizationEditor = customizing ? (\n customDraft ? (\n <div className=\"flex flex-col gap-3 rounded border border-dashed bg-muted/20 p-3\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <div className=\"text-sm font-semibold\">{t('appShell.sidebarCustomizationHeading')}</div>\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={resetCustomization}\n disabled={savingPreferences}\n >\n {t('appShell.sidebarCustomizationReset')}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={cancelCustomization}\n disabled={savingPreferences}\n >\n {t('appShell.sidebarCustomizationCancel')}\n </Button>\n <Button\n size=\"sm\"\n className=\"bg-foreground text-background hover:bg-foreground/90\"\n onClick={saveCustomization}\n disabled={savingPreferences}\n >\n {savingPreferences ? t('appShell.sidebarCustomizationSaving') : t('appShell.sidebarCustomizationSave')}\n </Button>\n </div>\n </div>\n <p className=\"text-xs text-muted-foreground\">{t('appShell.sidebarCustomizationHint', { locale: localeLabel })}</p>\n {canApplyToRoles ? (\n <div className=\"flex flex-col gap-2 rounded border bg-background/70 p-3 shadow-sm\">\n <div>\n <div className=\"text-sm font-semibold\">{t('appShell.sidebarApplyToRolesTitle')}</div>\n <p className=\"text-xs text-muted-foreground\">{t('appShell.sidebarApplyToRolesDescription')}</p>\n </div>\n {availableRoleTargets.length > 0 ? (\n <div className=\"flex flex-col gap-2\">\n {availableRoleTargets.map((role) => {\n const checked = selectedRoleIds.includes(role.id)\n const willClear = role.hasPreference && !checked\n return (\n <label key={role.id} className=\"flex items-center gap-2 rounded border bg-background px-2 py-1 text-sm shadow-sm\">\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 accent-foreground\"\n checked={checked}\n onChange={() => toggleRoleSelection(role.id)}\n disabled={savingPreferences}\n />\n <span className=\"flex-1 truncate\">{role.name}</span>\n {role.hasPreference ? (\n <span className={`text-xs ${willClear ? 'text-destructive' : 'text-muted-foreground'}`}>\n {willClear ? t('appShell.sidebarRoleWillClear') : t('appShell.sidebarRoleHasPreset')}\n </span>\n ) : null}\n </label>\n )\n })}\n </div>\n ) : (\n <p className=\"text-xs text-muted-foreground\">{t('appShell.sidebarApplyToRolesEmpty')}</p>\n )}\n </div>\n ) : null}\n {customizationError ? <p className=\"text-xs text-destructive\">{customizationError}</p> : null}\n <div className=\"flex flex-col gap-3\">\n {orderedGroupIds.map((groupId, index) => {\n const baseGroup = baseGroupMap.get(groupId)\n if (!baseGroup) return null\n const currentGroup = navGroups.find((group) => resolveGroupKey(group) === groupId) ?? baseGroup\n const placeholder = baseGroup.defaultName ?? baseGroup.name\n const value = customDraft.groupLabels[groupId] ?? ''\n return (\n <div key={groupId} className=\"flex flex-col gap-3 rounded border bg-background p-3 shadow-sm\">\n <div className={`flex ${compact ? 'flex-col gap-2' : 'items-center gap-2'}`}>\n <div className=\"flex-1\">\n <span className=\"text-xs font-medium text-muted-foreground\">{t('appShell.sidebarCustomizationGroupLabel')}</span>\n <input\n value={value}\n onChange={(event) => setGroupLabel(groupId, event.target.value)}\n placeholder={placeholder}\n disabled={savingPreferences}\n className=\"mt-1 h-8 w-full rounded border bg-background px-2 text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-60\"\n />\n </div>\n <div className=\"flex items-center gap-1 self-start\">\n <IconButton\n variant=\"outline\"\n size=\"sm\"\n className=\"text-muted-foreground hover:text-foreground\"\n onClick={() => moveGroup(groupId, -1)}\n disabled={index === 0 || savingPreferences}\n aria-label={t('appShell.sidebarCustomizationMoveUp')}\n >\n <ChevronUp className=\"size-4\" />\n </IconButton>\n <IconButton\n variant=\"outline\"\n size=\"sm\"\n className=\"text-muted-foreground hover:text-foreground\"\n onClick={() => moveGroup(groupId, 1)}\n disabled={index === orderedGroupIds.length - 1 || savingPreferences}\n aria-label={t('appShell.sidebarCustomizationMoveDown')}\n >\n <ChevronDown className=\"size-4\" />\n </IconButton>\n </div>\n </div>\n <div className=\"flex flex-col gap-2\">\n {renderEditableItems(baseGroup.items, currentGroup.items)}\n </div>\n </div>\n )\n })}\n </div>\n </div>\n ) : (\n <div className=\"rounded border border-dashed bg-muted/20 p-3 text-sm text-muted-foreground\">\n {t('appShell.sidebarCustomizationLoading')}\n </div>\n )\n ) : null\n\n return (\n <div className=\"flex flex-col min-h-full gap-3\">\n {!hideHeader && (\n <div className={`flex items-center ${compact ? 'justify-center' : 'justify-between'} mb-2`}>\n <Link href=\"/backend\" className=\"flex items-center gap-2\" aria-label={t('appShell.goToDashboard')}>\n <Image src={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? resolvedProductName} width={32} height={32} className=\"rounded m-4\" />\n {!compact && <div className=\"text-m font-semibold\">{resolvedProductName}</div>}\n </Link>\n </div>\n )}\n {shouldRenderSidebarInjectionSpots ? (\n <InjectionSpot\n spotId={BACKEND_SIDEBAR_TOP_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n <div className=\"flex flex-1 flex-col gap-3 pr-1\">\n {customizing ? (\n customizationEditor\n ) : (\n (() => {\n const isSettingsPath = (href: string) => {\n if (href === '/backend/settings') return true\n return resolvedSettingsPathPrefixes.some((prefix) => href.startsWith(prefix))\n }\n\n const isMainItem = (item: SidebarItem) => {\n if (item.pageContext && item.pageContext !== 'main') return false\n if (isSettingsPath(item.href)) return false\n return true\n }\n\n const mainGroups = mainNavGroupsWithInjected.map((g) => ({\n ...g,\n items: g.items.filter((item) => isMainItem(item) && item.hidden !== true),\n })).filter((g) => g.items.length > 0)\n\n const mainLastVisibleGroupIndex = (() => {\n for (let idx = mainGroups.length - 1; idx >= 0; idx -= 1) {\n if (mainGroups[idx].items.some((item) => item.hidden !== true)) return idx\n }\n return -1\n })()\n\n return (\n <>\n <nav className=\"flex flex-col gap-2\" data-testid=\"sidebar\">\n {shouldRenderSidebarInjectionSpots ? (\n <InjectionSpot\n spotId={BACKEND_SIDEBAR_NAV_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n {mainGroups.map((g, gi) => {\n const groupId = resolveGroupKey(g)\n const open = openGroups[groupId] !== false\n const visibleItems = g.items.filter((item) => item.hidden !== true)\n if (visibleItems.length === 0) return null\n return (\n <div key={groupId}>\n <Button\n variant=\"muted\"\n onClick={() => toggleGroup(groupId)}\n className={`w-full ${compact ? 'px-0 justify-center' : 'px-2 justify-between'} flex text-xs uppercase text-muted-foreground/90 py-2`}\n aria-expanded={open}\n >\n {!compact && <span>{g.name}</span>}\n {!compact && <Chevron open={open} />}\n </Button>\n {open && (\n <div className={`flex flex-col ${compact ? 'items-center' : ''} gap-1 ${!compact ? 'pl-1' : ''}`}>\n {visibleItems.map((i) => {\n const childItems = (i.children ?? []).filter((child) => child.hidden !== true)\n const showChildren = !!pathname && childItems.length > 0 && pathname.startsWith(i.href)\n const hasActiveChild = !!(pathname && childItems.some((c) => pathname.startsWith(c.href)))\n const isParentActive = (pathname === i.href) || (showChildren && !hasActiveChild)\n const base = compact ? 'w-10 h-10 justify-center' : 'px-2 py-1 gap-2'\n return (\n <React.Fragment key={i.href}>\n <Link\n href={i.href}\n className={`relative text-sm rounded inline-flex items-center ${base} ${\n isParentActive ? 'bg-background border shadow-sm' : 'hover:bg-accent hover:text-accent-foreground'\n } ${i.enabled === false ? 'pointer-events-none opacity-50' : ''}`}\n aria-disabled={i.enabled === false}\n title={compact ? i.title : undefined}\n data-menu-item-id={i.id ?? i.href}\n onClick={() => setMobileOpen(false)}\n >\n {isParentActive ? (\n <span className=\"absolute left-0 top-1 bottom-1 w-0.5 rounded bg-foreground\" />\n ) : null}\n <span className={`flex items-center justify-center shrink-0 ${compact ? '' : 'text-muted-foreground'}`}>\n {renderIcon(\n i.icon,\n i.iconName,\n i.iconMarkup,\n DefaultIcon,\n )}\n </span>\n {!compact && <span>{i.title}</span>}\n </Link>\n {showChildren ? (\n <div className={`flex flex-col ${compact ? 'items-center' : ''} gap-1 ${!compact ? 'pl-4' : ''}`}>\n {childItems.map((c) => {\n const childActive = pathname?.startsWith(c.href)\n const childBase = compact ? 'w-10 h-8 justify-center' : 'px-2 py-1 gap-2'\n return (\n <Link\n key={c.href}\n href={c.href}\n className={`relative text-sm rounded inline-flex items-center ${childBase} ${\n childActive ? 'bg-background border shadow-sm' : 'hover:bg-accent hover:text-accent-foreground'\n } ${c.enabled === false ? 'pointer-events-none opacity-50' : ''}`}\n aria-disabled={c.enabled === false}\n title={compact ? c.title : undefined}\n data-menu-item-id={c.id ?? c.href}\n onClick={() => setMobileOpen(false)}\n >\n {childActive ? (\n <span className=\"absolute left-0 top-1 bottom-1 w-0.5 rounded bg-foreground\" />\n ) : null}\n <span className={`flex items-center justify-center shrink-0 ${compact ? '' : 'text-muted-foreground'}`}>\n {renderIcon(\n c.icon,\n c.iconName,\n c.iconMarkup,\n c.href.includes('/backend/entities/user/') && c.href.endsWith('/records') ? DataTableIcon : DefaultIcon,\n )}\n </span>\n {!compact && <span>{c.title}</span>}\n </Link>\n )\n })}\n </div>\n ) : null}\n </React.Fragment>\n )\n })}\n </div>\n )}\n {gi !== mainLastVisibleGroupIndex && <div className=\"my-2 border-t border-dotted\" />}\n </div>\n )\n })}\n </nav>\n </>\n )\n })()\n )}\n </div>\n <div className=\"sticky bottom-0 pt-4 border-t bg-background/60 backdrop-blur-sm pb-1\">\n {shouldRenderSidebarInjectionSpots ? (\n <InjectionSpot\n spotId={BACKEND_SIDEBAR_NAV_FOOTER_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n <Link\n href=\"/backend/settings\"\n className={`relative text-sm rounded inline-flex items-center w-full ${\n compact ? 'w-10 h-10 justify-center' : 'px-2 py-1 gap-2'\n } ${\n pathname?.startsWith('/backend/settings') || pathname?.startsWith('/backend/config') || pathname?.startsWith('/backend/users') || pathname?.startsWith('/backend/roles') || pathname?.startsWith('/backend/api-keys') || pathname?.startsWith('/backend/entities') || pathname?.startsWith('/backend/query-indexes') || pathname?.startsWith('/backend/definitions') || pathname?.startsWith('/backend/instances') || pathname?.startsWith('/backend/tasks') || pathname?.startsWith('/backend/events') || pathname?.startsWith('/backend/rules') || pathname?.startsWith('/backend/sets') || pathname?.startsWith('/backend/logs') || pathname?.startsWith('/backend/directory') || pathname?.startsWith('/backend/feature-toggles')\n ? 'bg-background border shadow-sm font-medium'\n : 'hover:bg-accent hover:text-accent-foreground'\n }`}\n title={compact ? t('backend.nav.settings', 'Settings') : undefined}\n onClick={() => setMobileOpen(false)}\n >\n {(pathname?.startsWith('/backend/settings') || pathname?.startsWith('/backend/config') || pathname?.startsWith('/backend/users') || pathname?.startsWith('/backend/roles') || pathname?.startsWith('/backend/api-keys') || pathname?.startsWith('/backend/entities') || pathname?.startsWith('/backend/query-indexes') || pathname?.startsWith('/backend/definitions') || pathname?.startsWith('/backend/instances') || pathname?.startsWith('/backend/tasks') || pathname?.startsWith('/backend/events') || pathname?.startsWith('/backend/rules') || pathname?.startsWith('/backend/sets') || pathname?.startsWith('/backend/logs') || pathname?.startsWith('/backend/directory') || pathname?.startsWith('/backend/feature-toggles')) && (\n <span className=\"absolute left-0 top-1 bottom-1 w-0.5 rounded bg-foreground\" />\n )}\n <span className={`flex items-center justify-center shrink-0 ${compact ? '' : 'text-muted-foreground'}`}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\" />\n </svg>\n </span>\n {!compact && <span>{t('backend.nav.settings', 'Settings')}</span>}\n </Link>\n {!customizing && (\n <div className=\"mt-2\">\n {shouldRenderSidebarInjectionSpots ? (\n <StatusBadgeInjectionSpot\n spotId={GLOBAL_SIDEBAR_STATUS_BADGES_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n {compact || isMobileVariant ? (\n <IconButton\n variant=\"outline\"\n size=\"lg\"\n onClick={startCustomization}\n disabled={loadingPreferences}\n aria-label={t('appShell.customizeSidebar')}\n >\n {CustomizeIcon}\n </IconButton>\n ) : (\n <Button\n variant=\"outline\"\n size=\"default\"\n onClick={startCustomization}\n disabled={loadingPreferences}\n aria-label={t('appShell.customizeSidebar')}\n >\n {CustomizeIcon}\n {loadingPreferences ? t('appShell.sidebarCustomizationLoading') : t('appShell.customizeSidebar')}\n </Button>\n )}\n </div>\n )}\n {shouldRenderSidebarInjectionSpots ? (\n <InjectionSpot\n spotId={BACKEND_SIDEBAR_FOOTER_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n </div>\n </div>\n )\n }\n\n const gridColsClass = customizing\n ? 'lg:grid-cols-[320px_1fr]'\n : (effectiveCollapsed ? 'lg:grid-cols-[72px_1fr]' : 'lg:grid-cols-[240px_1fr]')\n const headerCtxValue = React.useMemo(() => ({\n setBreadcrumb: setHeaderBreadcrumb,\n setTitle: setHeaderTitle,\n }), [])\n const renderedTopbarInjectedActions = React.useMemo(\n () =>\n topbarInjectedMenuItems.map((item) => {\n const label = resolveInjectedMenuLabel(item, t)\n if (item.href) {\n return (\n <Link\n key={item.id}\n href={item.href}\n className=\"inline-flex items-center rounded border px-2 py-1 text-xs hover:bg-accent hover:text-accent-foreground\"\n data-menu-item-id={item.id}\n >\n {label}\n </Link>\n )\n }\n return (\n <Button\n key={item.id}\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-7 text-xs\"\n data-menu-item-id={item.id}\n onClick={() => item.onClick?.()}\n >\n {label}\n </Button>\n )\n }),\n [t, topbarInjectedMenuItems],\n )\n\n return (\n <HeaderContext.Provider value={headerCtxValue}>\n <div className={`min-h-svh lg:grid ${gridColsClass}`}>\n {/* Desktop sidebar */}\n <aside className={`${asideClassesBase} ${effectiveCollapsed ? 'px-2' : 'px-3'} hidden lg:block`} style={{ width: asideWidth }}>{renderSidebar(effectiveCollapsed)}</aside>\n\n <div className=\"flex min-h-svh flex-col min-w-0\">\n <header className=\"border-b bg-background/60 px-3 lg:px-4 py-2 lg:py-3 flex items-center justify-between gap-2\">\n <div\n data-testid=\"backend-chrome-ready\"\n data-ready={isChromeReady ? 'true' : 'false'}\n className=\"hidden\"\n />\n <div className=\"flex items-center gap-2 min-w-0\">\n {/* Mobile menu button */}\n <IconButton variant=\"outline\" size=\"sm\" className=\"lg:hidden\" aria-label={t('appShell.openMenu')} onClick={() => setMobileOpen(true)}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><path d=\"M3 6h18M3 12h18M3 18h18\"/></svg>\n </IconButton>\n {/* Desktop collapse toggle */}\n <IconButton\n variant=\"outline\"\n size=\"sm\"\n className=\"hidden lg:inline-flex\"\n aria-label={t('appShell.toggleSidebar')}\n onClick={() => setCollapsed((c) => !c)}\n disabled={customizing}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\"/>\n <path d=\"M9 4v16\"/>\n </svg>\n </IconButton>\n {/* Header breadcrumb: always starts with Dashboard */}\n {(() => {\n const dashboardLabel = t('dashboard.title')\n const root: Breadcrumb = [{ label: dashboardLabel, href: '/backend' }]\n let rest: Breadcrumb = []\n if (headerBreadcrumb && headerBreadcrumb.length) {\n const first = headerBreadcrumb[0]\n const dup = first && (first.href === '/backend' || first.label === dashboardLabel || first.label?.toLowerCase() === 'dashboard')\n rest = dup ? headerBreadcrumb.slice(1) : headerBreadcrumb\n } else if (headerTitle) {\n rest = [{ label: headerTitle }]\n }\n const items = [...root, ...rest]\n const lastIndex = items.length - 1\n return (\n <nav className=\"flex items-center gap-2 text-sm min-w-0\">\n {items.map((b, i) => {\n const isLast = i === lastIndex\n const hiddenOnMobile = !isLast ? 'hidden md:inline' : ''\n return (\n <React.Fragment key={i}>\n {i > 0 && <span className={`text-muted-foreground hidden md:inline`}>/</span>}\n {b.href ? (\n <Link href={b.href} className={`text-muted-foreground hover:text-foreground ${hiddenOnMobile}`}>\n {b.label}\n </Link>\n ) : (\n <span className={`font-medium truncate max-w-[45vw] md:max-w-[60vw]`}>{b.label}</span>\n )}\n </React.Fragment>\n )\n })}\n </nav>\n )\n })()}\n </div>\n <div className=\"flex items-center gap-1 md:gap-2 text-sm shrink-0\">\n <StatusBadgeInjectionSpot\n spotId={GLOBAL_HEADER_STATUS_INDICATORS_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n <InjectionSpot\n spotId={BACKEND_TOPBAR_ACTIONS_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n {renderedTopbarInjectedActions}\n {rightHeaderSlot ? (\n rightHeaderSlot\n ) : (\n <span className=\"opacity-80\">{email || t('appShell.userFallback')}</span>\n )}\n </div>\n </header>\n <ProgressTopBar t={t} className=\"sticky top-0 z-10\" />\n <main className=\"flex-1 p-4 lg:p-6\">\n <InjectionSpot spotId={BACKEND_LAYOUT_TOP_INJECTION_SPOT_ID} context={injectionContext} />\n <FlashMessages />\n <PartialIndexBanner />\n <UpgradeActionBanner />\n <LastOperationBanner />\n <InjectionSpot spotId={BACKEND_RECORD_CURRENT_INJECTION_SPOT_ID} context={injectionContext} />\n <InjectionSpot\n spotId={LEGACY_GLOBAL_MUTATION_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n <div id=\"om-top-banners\" className=\"mb-3 space-y-2\" />\n {children}\n <InjectionSpot spotId={BACKEND_LAYOUT_FOOTER_INJECTION_SPOT_ID} context={injectionContext} />\n </main>\n <footer className=\"border-t bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/50 px-4 py-3 flex flex-wrap items-center justify-end gap-4\">\n {version ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('appShell.version', { version })}\n </span>\n ) : null}\n <nav className=\"flex items-center gap-3 text-xs text-muted-foreground\">\n <Link href=\"/terms\" className=\"transition hover:text-foreground\">\n {t('common.terms')}\n </Link>\n <Link href=\"/privacy\" className=\"transition hover:text-foreground\">\n {t('common.privacy')}\n </Link>\n </nav>\n </footer>\n </div>\n\n {/* Mobile drawer */}\n {mobileOpen && (\n <div className=\"lg:hidden fixed inset-0 z-50\">\n <div className=\"absolute inset-0 bg-black/40\" onClick={() => setMobileOpen(false)} aria-hidden=\"true\" />\n <aside className=\"absolute left-0 top-0 flex h-full w-[260px] flex-col bg-background border-r overflow-hidden\">\n <div className=\"shrink-0 p-3 pb-2 flex items-center justify-between border-b\">\n <Link href=\"/backend\" className=\"flex items-center gap-2 text-sm font-semibold\" onClick={() => setMobileOpen(false)} aria-label={t('appShell.goToDashboard')}>\n <Image src={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? resolvedProductName} width={28} height={28} className=\"rounded\" />\n {resolvedProductName}\n </Link>\n <IconButton variant=\"outline\" size=\"sm\" onClick={() => setMobileOpen(false)} aria-label={t('appShell.closeMenu')}>\u2715</IconButton>\n </div>\n {mobileSidebarSlot && (\n <div className=\"shrink-0 border-b px-3 py-2\">\n {mobileSidebarSlot}\n </div>\n )}\n <div className=\"min-h-0 flex-1 overflow-y-auto overflow-x-hidden p-3\">\n {/* Force expanded sidebar in mobile drawer, hide its header and collapse toggle */}\n {renderSidebar(false, true)}\n </div>\n </aside>\n </div>\n )}\n </div>\n <UmesDevToolsPanel />\n </HeaderContext.Provider>\n )\n}\n\n// Helper: deep-clone minimal shape we mutate (children arrays)\nAppShell.cloneGroups = function cloneGroups(groups: AppShellProps['groups']): AppShellProps['groups'] {\n const cloneItem = (item: SidebarItem): SidebarItem => ({\n id: item.id,\n href: item.href,\n title: item.title,\n defaultTitle: item.defaultTitle,\n icon: item.icon,\n iconName: item.iconName,\n iconMarkup: item.iconMarkup,\n enabled: item.enabled,\n hidden: item.hidden,\n pageContext: item.pageContext,\n children: item.children ? item.children.map((child) => cloneItem(child)) : undefined,\n })\n return groups.map((group) => ({\n id: group.id,\n name: group.name,\n defaultName: group.defaultName,\n items: group.items.map((item) => cloneItem(item)),\n }))\n}\n\nfunction applyCustomizationDraft(baseGroups: SidebarGroup[], draft: SidebarCustomizationDraft): SidebarGroup[] {\n const clones = AppShell.cloneGroups(baseGroups)\n const byId = new Map<string, SidebarGroup>()\n for (const group of clones) {\n byId.set(resolveGroupKey(group), group)\n }\n const orderedIds = mergeGroupOrder(draft.order, Array.from(byId.keys()))\n const seen = new Set<string>()\n const result: SidebarGroup[] = []\n for (const id of orderedIds) {\n if (seen.has(id)) continue\n const group = byId.get(id)\n if (!group) continue\n seen.add(id)\n const baseName = group.defaultName ?? group.name\n const override = draft.groupLabels[id]?.trim()\n result.push({\n ...group,\n name: override && override.length > 0 ? override : baseName,\n items: group.items.map((item) => applyItemDraft(item, draft)),\n })\n }\n return result\n}\n\nfunction applyItemDraft(item: SidebarItem, draft: SidebarCustomizationDraft): SidebarItem {\n const itemKey = resolveItemKey(item)\n const baseTitle = item.defaultTitle ?? item.title\n const override = draft.itemLabels[itemKey]?.trim()\n const children = item.children\n ? item.children\n .map((child) => applyItemDraft(child, draft))\n : undefined\n const hidden = draft.hiddenItemIds[itemKey] === true\n return {\n ...item,\n title: override && override.length > 0 ? override : baseTitle,\n hidden,\n children,\n }\n}\n\nfunction mergeGroupOrder(preferred: string[], current: string[]): string[] {\n const seen = new Set<string>()\n const merged: string[] = []\n for (const id of preferred) {\n const trimmed = id.trim()\n if (!trimmed || seen.has(trimmed) || !current.includes(trimmed)) continue\n seen.add(trimmed)\n merged.push(trimmed)\n }\n for (const id of current) {\n if (seen.has(id)) continue\n seen.add(id)\n merged.push(id)\n }\n return merged\n}\n\nfunction collectSidebarDefaults(groups: SidebarGroup[]) {\n const groupDefaults = new Map<string, string>()\n const itemDefaults = new Map<string, string>()\n\n const visitItems = (items: SidebarItem[]) => {\n for (const item of items) {\n const key = resolveItemKey(item)\n const baseTitle = item.defaultTitle ?? item.title\n itemDefaults.set(key, baseTitle)\n // Backward-compatible alias for legacy stored href-based preferences.\n itemDefaults.set(item.href, baseTitle)\n if (item.children && item.children.length > 0) visitItems(item.children)\n }\n }\n\n for (const group of groups) {\n const key = resolveGroupKey(group)\n groupDefaults.set(key, group.defaultName ?? group.name)\n visitItems(group.items)\n }\n\n return { groupDefaults, itemDefaults }\n}\n\n/**\n * Filters groups to include only main sidebar items.\n * Excludes items with pageContext 'settings' or 'profile' from customization.\n * Per SPEC-007: Sidebar customization applies only to the main sidebar.\n */\nfunction filterMainSidebarGroups(groups: SidebarGroup[]): SidebarGroup[] {\n const isMainItem = (item: SidebarItem): boolean => {\n if (item.pageContext && item.pageContext !== 'main') return false\n return true\n }\n\n return groups\n .map((group) => ({\n ...group,\n items: group.items.filter(isMainItem).map((item) => ({\n ...item,\n children: item.children?.filter(isMainItem),\n })),\n }))\n .filter((group) => group.items.length > 0)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -80,6 +80,7 @@ function PortalShell({
80
80
  children,
81
81
  orgSlug: orgSlugProp,
82
82
  organizationName: orgNameProp,
83
+ logo,
83
84
  authenticated: authenticatedProp,
84
85
  onLogout: onLogoutProp,
85
86
  enableEventBridge = false,
@@ -153,7 +154,7 @@ function PortalShell({
153
154
  return /* @__PURE__ */ jsxs("div", { className: "flex min-h-svh flex-col bg-background", "data-portal-handle": PORTAL_SHELL_HANDLE, children: [
154
155
  /* @__PURE__ */ jsx("header", { className: "sticky top-0 z-40 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80", "data-portal-handle": PORTAL_HEADER_HANDLE, children: /* @__PURE__ */ jsxs("div", { className: "mx-auto flex h-16 w-full max-w-screen-lg items-center justify-between px-6", children: [
155
156
  /* @__PURE__ */ jsxs(Link, { href: portalHome, className: "flex items-center gap-2.5 text-foreground transition hover:opacity-80", "aria-label": headerTitle, children: [
156
- /* @__PURE__ */ jsx(Image, { src: "/open-mercato.svg", alt: "", width: 28, height: 28, className: "", priority: true }),
157
+ /* @__PURE__ */ jsx(Image, { src: logo?.src ?? "/open-mercato.svg", alt: logo?.alt ?? "", width: 28, height: 28, className: "", priority: true }),
157
158
  /* @__PURE__ */ jsx("span", { className: "text-[15px] font-semibold tracking-tight", children: headerTitle })
158
159
  ] }),
159
160
  /* @__PURE__ */ jsxs("nav", { "aria-label": "Primary", className: "flex items-center gap-1", children: [
@@ -164,7 +165,7 @@ function PortalShell({
164
165
  /* @__PURE__ */ jsx("main", { className: "flex-1", children: /* @__PURE__ */ jsx("div", { className: "mx-auto flex w-full max-w-screen-lg flex-col gap-8 px-6 py-12 sm:py-20", children }) }),
165
166
  /* @__PURE__ */ jsx("footer", { className: "border-t", "data-portal-handle": PORTAL_FOOTER_HANDLE, children: /* @__PURE__ */ jsxs("div", { className: "mx-auto flex w-full max-w-screen-lg items-center justify-between px-6 py-6", children: [
166
167
  /* @__PURE__ */ jsxs(Link, { href: portalHome, className: "flex items-center gap-2 text-muted-foreground transition hover:text-foreground", children: [
167
- /* @__PURE__ */ jsx(Image, { src: "/open-mercato.svg", alt: "", width: 20, height: 20, className: "" }),
168
+ /* @__PURE__ */ jsx(Image, { src: logo?.src ?? "/open-mercato.svg", alt: logo?.alt ?? "", width: 20, height: 20, className: "" }),
168
169
  /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: headerTitle })
169
170
  ] }),
170
171
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground/60", children: t("portal.footer.copyright", "\xA9 {year} All rights reserved.", { year: (/* @__PURE__ */ new Date()).getFullYear() }) })
@@ -173,7 +174,7 @@ function PortalShell({
173
174
  }
174
175
  const sidebarContent = /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col", "data-portal-handle": PORTAL_SIDEBAR_HANDLE, children: [
175
176
  /* @__PURE__ */ jsx("div", { className: "flex h-16 items-center gap-2.5 border-b px-5", children: /* @__PURE__ */ jsxs(Link, { href: portalHome, className: "flex items-center gap-2.5 text-foreground transition hover:opacity-80", "aria-label": headerTitle, children: [
176
- /* @__PURE__ */ jsx(Image, { src: "/open-mercato.svg", alt: "", width: 22, height: 22, className: "" }),
177
+ /* @__PURE__ */ jsx(Image, { src: logo?.src ?? "/open-mercato.svg", alt: logo?.alt ?? "", width: 22, height: 22, className: "" }),
177
178
  /* @__PURE__ */ jsx("span", { className: "text-[14px] font-semibold tracking-tight truncate", children: headerTitle })
178
179
  ] }) }),
179
180
  /* @__PURE__ */ jsxs("nav", { "aria-label": "Portal navigation", className: "flex-1 overflow-y-auto px-3 py-5", children: [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/portal/PortalShell.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport { type ReactNode, useEffect, useState, useCallback, useMemo, useContext } from 'react'\nimport Image from 'next/image'\nimport Link from 'next/link'\nimport { usePathname } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '../primitives/button'\nimport { IconButton } from '../primitives/icon-button'\nimport { usePortalInjectedMenuItems } from './hooks/usePortalInjectedMenuItems'\nimport { usePortalEventBridge } from './hooks/usePortalEventBridge'\nimport { mergeMenuItems } from '../backend/injection/mergeMenuItems'\nimport type { MergedMenuItem } from '../backend/injection/mergeMenuItems'\nimport { PortalNotificationBell } from './components/PortalNotificationBell'\nimport { usePortalContext } from './PortalContext'\nimport { apiCall } from '../backend/utils/apiCall'\nimport type { PortalNavGroup } from './utils/nav'\n\n// Component replacement handle IDs (FROZEN once shipped)\nexport const PORTAL_SHELL_HANDLE = 'page:portal:layout'\nexport const PORTAL_HEADER_HANDLE = 'section:portal:header'\nexport const PORTAL_FOOTER_HANDLE = 'section:portal:footer'\nexport const PORTAL_SIDEBAR_HANDLE = 'section:portal:sidebar'\nexport const PORTAL_USER_MENU_HANDLE = 'section:portal:user-menu'\n\nexport type PortalShellProps = {\n children: ReactNode\n /** Override orgSlug (used on public pages without context) */\n orgSlug?: string\n /** Override organization name (used on public pages without context) */\n organizationName?: string\n /** Whether to show authenticated layout. Auto-detected from context when omitted. */\n authenticated?: boolean\n /** Logout handler. Auto-provided from context when omitted. */\n onLogout?: () => void\n enableEventBridge?: boolean\n /** Override user name. Auto-read from context when omitted. */\n userName?: string\n /** Override user email. Auto-read from context when omitted. */\n userEmail?: string\n}\n\nfunction PortalEventBridgeMount() {\n usePortalEventBridge()\n return null\n}\n\n/* ---- Inline SVG icons ---- */\n\nfunction MenuIcon({ className }: { className?: string }) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <line x1=\"4\" x2=\"20\" y1=\"12\" y2=\"12\" /><line x1=\"4\" x2=\"20\" y1=\"6\" y2=\"6\" /><line x1=\"4\" x2=\"20\" y1=\"18\" y2=\"18\" />\n </svg>\n )\n}\n\nfunction XIcon({ className }: { className?: string }) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n )\n}\n\nfunction LogOutIcon({ className }: { className?: string }) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" /><polyline points=\"16 17 21 12 16 7\" /><line x1=\"21\" x2=\"9\" y1=\"12\" y2=\"12\" />\n </svg>\n )\n}\n\n/* ---- Sidebar nav item ---- */\n\nfunction SidebarNavItem({\n item,\n active,\n t,\n onClick,\n}: {\n item: MergedMenuItem\n active: boolean\n t: (key: string, fallback?: string) => string\n onClick?: () => void\n}) {\n const label = item.labelKey ? t(item.labelKey, item.label) : item.label\n if (!label) return null\n\n const cls = [\n 'flex items-center gap-2.5 rounded-lg px-3 py-2 text-[13px] font-medium transition-colors',\n active\n ? 'bg-foreground text-background'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground',\n ].join(' ')\n\n if (item.href) {\n return (\n <Link href={item.href} className={cls} data-menu-item-id={item.id} onClick={onClick}>\n {label}\n </Link>\n )\n }\n if (item.onClick) {\n return (\n <button type=\"button\" className={cls} data-menu-item-id={item.id} onClick={() => { item.onClick?.(); onClick?.() }}>\n {label}\n </button>\n )\n }\n return null\n}\n\n/* ---- User initials avatar ---- */\n\nfunction UserAvatar({ name, className }: { name?: string; className?: string }) {\n const initials = name\n ? name.split(' ').map((w) => w[0]).slice(0, 2).join('').toUpperCase()\n : '?'\n return (\n <div className={`flex items-center justify-center rounded-full bg-foreground text-[11px] font-semibold text-background ${className ?? 'size-8'}`}>\n {initials}\n </div>\n )\n}\n\n/* ---- Try reading from PortalContext ---- */\n\nfunction useOptionalPortalContext() {\n try {\n return usePortalContext()\n } catch {\n return null\n }\n}\n\n/* ================================================================== */\n/* PortalShell */\n/* ================================================================== */\n\n/**\n * Portal layout shell.\n *\n * When a `PortalProvider` is mounted in a parent layout, PortalShell reads\n * auth/tenant state from context \u2014 no re-fetching on navigation. Props are\n * used as overrides or for public pages that don't have a context.\n */\nexport function PortalShell({\n children,\n orgSlug: orgSlugProp,\n organizationName: orgNameProp,\n authenticated: authenticatedProp,\n onLogout: onLogoutProp,\n enableEventBridge = false,\n userName: userNameProp,\n userEmail: userEmailProp,\n}: PortalShellProps) {\n const t = useT()\n const pathname = usePathname()\n const [mobileOpen, setMobileOpen] = useState(false)\n\n // Read from context when available (persists across navigations)\n const portalCtx = useOptionalPortalContext()\n\n // Resolve values: context takes priority, props are fallback/override\n const orgSlug = portalCtx?.orgSlug ?? orgSlugProp\n const orgName = portalCtx?.tenant.organizationName ?? orgNameProp\n const user = portalCtx?.auth.user ?? null\n const authenticated = authenticatedProp ?? !!user\n const onLogout = onLogoutProp ?? portalCtx?.auth.logout\n const userName = userNameProp ?? user?.displayName\n const userEmail = userEmailProp ?? user?.email\n\n const { items: injectedMainItems } = usePortalInjectedMenuItems('menu:portal:sidebar:main')\n const { items: injectedAccountItems } = usePortalInjectedMenuItems('menu:portal:sidebar:account')\n\n const portalHome = orgSlug ? `/${orgSlug}/portal` : '/portal'\n const loginHref = orgSlug ? `/${orgSlug}/portal/login` : '/portal/login'\n const signupHref = orgSlug ? `/${orgSlug}/portal/signup` : '/portal/signup'\n // Always use the resolved organization name from the database.\n // Fall back to the generic portal title \u2014 never display the raw slug.\n const headerTitle = orgName || t('portal.title', 'Customer Portal')\n\n const closeMobile = useCallback(() => setMobileOpen(false), [])\n\n const [autoNavGroups, setAutoNavGroups] = useState<PortalNavGroup[]>([])\n useEffect(() => {\n if (!authenticated) {\n setAutoNavGroups([])\n return\n }\n let cancelled = false\n const load = async () => {\n try {\n const { ok, result } = await apiCall<{ ok: boolean; groups?: PortalNavGroup[] }>(\n '/api/customer_accounts/portal/nav',\n )\n if (cancelled || !ok || !result?.ok) return\n setAutoNavGroups(Array.isArray(result.groups) ? result.groups : [])\n } catch {\n if (!cancelled) setAutoNavGroups([])\n }\n }\n void load()\n return () => {\n cancelled = true\n }\n }, [authenticated])\n\n const mergedNavItems = useMemo(() => {\n if (!authenticated) return []\n const discovered = autoNavGroups.find((g) => g.id === 'main')?.items ?? []\n const builtIn = discovered.map((item) => ({\n id: item.id,\n labelKey: item.labelKey,\n label: item.label,\n href: item.href,\n }))\n return mergeMenuItems(builtIn, injectedMainItems)\n }, [authenticated, autoNavGroups, injectedMainItems])\n\n const mergedAccountItems = useMemo(() => {\n if (!authenticated) return []\n const discovered = autoNavGroups.find((g) => g.id === 'account')?.items ?? []\n const builtIn = discovered.map((item) => ({\n id: item.id,\n labelKey: item.labelKey,\n label: item.label,\n href: item.href,\n }))\n return mergeMenuItems(builtIn, injectedAccountItems)\n }, [authenticated, autoNavGroups, injectedAccountItems])\n\n /* ---- PUBLIC LAYOUT ---- */\n if (!authenticated) {\n return (\n <div className=\"flex min-h-svh flex-col bg-background\" data-portal-handle={PORTAL_SHELL_HANDLE}>\n <header className=\"sticky top-0 z-40 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80\" data-portal-handle={PORTAL_HEADER_HANDLE}>\n <div className=\"mx-auto flex h-16 w-full max-w-screen-lg items-center justify-between px-6\">\n <Link href={portalHome} className=\"flex items-center gap-2.5 text-foreground transition hover:opacity-80\" aria-label={headerTitle}>\n <Image src=\"/open-mercato.svg\" alt=\"\" width={28} height={28} className=\"\" priority />\n <span className=\"text-[15px] font-semibold tracking-tight\">{headerTitle}</span>\n </Link>\n <nav aria-label=\"Primary\" className=\"flex items-center gap-1\">\n <Button asChild variant=\"ghost\" size=\"sm\" className=\"text-[13px]\">\n <Link href={loginHref}>{t('portal.nav.login', 'Log In')}</Link>\n </Button>\n <Button asChild size=\"sm\" className=\"rounded-lg text-[13px]\">\n <Link href={signupHref}>{t('portal.nav.signup', 'Sign Up')}</Link>\n </Button>\n </nav>\n </div>\n </header>\n\n <main className=\"flex-1\">\n <div className=\"mx-auto flex w-full max-w-screen-lg flex-col gap-8 px-6 py-12 sm:py-20\">\n {children}\n </div>\n </main>\n\n <footer className=\"border-t\" data-portal-handle={PORTAL_FOOTER_HANDLE}>\n <div className=\"mx-auto flex w-full max-w-screen-lg items-center justify-between px-6 py-6\">\n <Link href={portalHome} className=\"flex items-center gap-2 text-muted-foreground transition hover:text-foreground\">\n <Image src=\"/open-mercato.svg\" alt=\"\" width={20} height={20} className=\"\" />\n <span className=\"text-sm font-medium text-foreground\">{headerTitle}</span>\n </Link>\n <p className=\"text-xs text-muted-foreground/60\">\n {t('portal.footer.copyright', '\\u00A9 {year} All rights reserved.', { year: new Date().getFullYear() })}\n </p>\n </div>\n </footer>\n </div>\n )\n }\n\n /* ---- AUTHENTICATED LAYOUT ---- */\n\n const sidebarContent = (\n <div className=\"flex h-full flex-col\" data-portal-handle={PORTAL_SIDEBAR_HANDLE}>\n <div className=\"flex h-16 items-center gap-2.5 border-b px-5\">\n <Link href={portalHome} className=\"flex items-center gap-2.5 text-foreground transition hover:opacity-80\" aria-label={headerTitle}>\n <Image src=\"/open-mercato.svg\" alt=\"\" width={22} height={22} className=\"\" />\n <span className=\"text-[14px] font-semibold tracking-tight truncate\">{headerTitle}</span>\n </Link>\n </div>\n\n <nav aria-label=\"Portal navigation\" className=\"flex-1 overflow-y-auto px-3 py-5\">\n <p className=\"mb-2 px-3 text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground/50\">\n {t('portal.nav.home', 'Portal')}\n </p>\n <div className=\"flex flex-col gap-0.5\">\n {mergedNavItems.map((item) => (\n <SidebarNavItem\n key={item.id}\n item={item}\n active={!!item.href && pathname.startsWith(item.href)}\n t={t}\n onClick={closeMobile}\n />\n ))}\n </div>\n\n {mergedAccountItems.length > 0 ? (\n <div className=\"mt-8\">\n <p className=\"mb-2 px-3 text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground/50\">\n {t('portal.nav.account', 'Account')}\n </p>\n <div className=\"flex flex-col gap-0.5\">\n {mergedAccountItems.map((item) => (\n <SidebarNavItem\n key={item.id}\n item={item}\n active={!!item.href && pathname.startsWith(item.href)}\n t={t}\n onClick={closeMobile}\n />\n ))}\n </div>\n </div>\n ) : null}\n </nav>\n\n <div className=\"border-t px-3 py-3\">\n <div className=\"flex items-center gap-2.5 rounded-lg px-3 py-2\">\n <UserAvatar name={userName} className=\"size-8\" />\n <div className=\"min-w-0 flex-1\">\n {userName ? (\n <p className=\"truncate text-[13px] font-medium leading-tight\">{userName}</p>\n ) : (\n <div className=\"h-4 w-24 animate-pulse rounded bg-muted\" />\n )}\n {userEmail ? (\n <p className=\"truncate text-[11px] text-muted-foreground\">{userEmail}</p>\n ) : (\n <div className=\"mt-1 h-3 w-32 animate-pulse rounded bg-muted\" />\n )}\n </div>\n </div>\n <button\n type=\"button\"\n onClick={onLogout}\n className=\"mt-0.5 flex w-full items-center gap-2.5 rounded-lg px-3 py-2 text-[13px] text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n data-portal-handle={PORTAL_USER_MENU_HANDLE}\n data-menu-item-id=\"portal-logout\"\n >\n <LogOutIcon className=\"size-4\" />\n {t('portal.nav.logout', 'Log Out')}\n </button>\n </div>\n </div>\n )\n\n return (\n <div className=\"flex min-h-svh bg-background\" data-portal-handle={PORTAL_SHELL_HANDLE}>\n {enableEventBridge ? <PortalEventBridgeMount /> : null}\n\n <aside className=\"hidden w-[240px] shrink-0 border-r lg:block\">\n {sidebarContent}\n </aside>\n\n {mobileOpen ? (\n <div className=\"fixed inset-0 z-50 lg:hidden\">\n <div className=\"absolute inset-0 bg-black/30 backdrop-blur-sm\" onClick={closeMobile} />\n <aside className=\"relative z-10 h-full w-[280px] bg-background shadow-2xl\">\n <div className=\"absolute right-3 top-4 z-20\">\n <IconButton variant=\"ghost\" size=\"sm\" type=\"button\" onClick={closeMobile} aria-label=\"Close menu\">\n <XIcon className=\"size-4\" />\n </IconButton>\n </div>\n {sidebarContent}\n </aside>\n </div>\n ) : null}\n\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <header className=\"flex h-16 items-center justify-between border-b px-4 lg:px-8\" data-portal-handle={PORTAL_HEADER_HANDLE}>\n <div className=\"flex items-center gap-3\">\n <IconButton variant=\"ghost\" size=\"sm\" type=\"button\" onClick={() => setMobileOpen(true)} className=\"lg:hidden\" aria-label=\"Open menu\">\n <MenuIcon className=\"size-5\" />\n </IconButton>\n </div>\n <div className=\"flex items-center gap-3\">\n <PortalNotificationBell t={t} />\n </div>\n </header>\n\n <main className=\"flex-1 overflow-y-auto\">\n <div className=\"w-full px-4 py-6 lg:px-8 lg:py-8\">\n {children}\n </div>\n </main>\n\n <footer className=\"border-t px-4 py-4 lg:px-8\" data-portal-handle={PORTAL_FOOTER_HANDLE}>\n <p className=\"text-[11px] text-muted-foreground/50\">\n {t('portal.footer.copyright', '\\u00A9 {year} All rights reserved.', { year: new Date().getFullYear() })}\n </p>\n </footer>\n </div>\n </div>\n )\n}\n\nexport default PortalShell\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport { type ReactNode, useEffect, useState, useCallback, useMemo, useContext } from 'react'\nimport Image from 'next/image'\nimport Link from 'next/link'\nimport { usePathname } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '../primitives/button'\nimport { IconButton } from '../primitives/icon-button'\nimport { usePortalInjectedMenuItems } from './hooks/usePortalInjectedMenuItems'\nimport { usePortalEventBridge } from './hooks/usePortalEventBridge'\nimport { mergeMenuItems } from '../backend/injection/mergeMenuItems'\nimport type { MergedMenuItem } from '../backend/injection/mergeMenuItems'\nimport { PortalNotificationBell } from './components/PortalNotificationBell'\nimport { usePortalContext } from './PortalContext'\nimport { apiCall } from '../backend/utils/apiCall'\nimport type { PortalNavGroup } from './utils/nav'\n\n// Component replacement handle IDs (FROZEN once shipped)\nexport const PORTAL_SHELL_HANDLE = 'page:portal:layout'\nexport const PORTAL_HEADER_HANDLE = 'section:portal:header'\nexport const PORTAL_FOOTER_HANDLE = 'section:portal:footer'\nexport const PORTAL_SIDEBAR_HANDLE = 'section:portal:sidebar'\nexport const PORTAL_USER_MENU_HANDLE = 'section:portal:user-menu'\n\nexport type ShellLogo = {\n src: string\n alt?: string\n}\n\nexport type PortalShellProps = {\n children: ReactNode\n /** Override orgSlug (used on public pages without context) */\n orgSlug?: string\n /** Override organization name (used on public pages without context) */\n organizationName?: string\n /** Override the brand logo rendered in the header, footer, and sidebar. */\n logo?: ShellLogo\n /** Whether to show authenticated layout. Auto-detected from context when omitted. */\n authenticated?: boolean\n /** Logout handler. Auto-provided from context when omitted. */\n onLogout?: () => void\n enableEventBridge?: boolean\n /** Override user name. Auto-read from context when omitted. */\n userName?: string\n /** Override user email. Auto-read from context when omitted. */\n userEmail?: string\n}\n\nfunction PortalEventBridgeMount() {\n usePortalEventBridge()\n return null\n}\n\n/* ---- Inline SVG icons ---- */\n\nfunction MenuIcon({ className }: { className?: string }) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <line x1=\"4\" x2=\"20\" y1=\"12\" y2=\"12\" /><line x1=\"4\" x2=\"20\" y1=\"6\" y2=\"6\" /><line x1=\"4\" x2=\"20\" y1=\"18\" y2=\"18\" />\n </svg>\n )\n}\n\nfunction XIcon({ className }: { className?: string }) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n )\n}\n\nfunction LogOutIcon({ className }: { className?: string }) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" /><polyline points=\"16 17 21 12 16 7\" /><line x1=\"21\" x2=\"9\" y1=\"12\" y2=\"12\" />\n </svg>\n )\n}\n\n/* ---- Sidebar nav item ---- */\n\nfunction SidebarNavItem({\n item,\n active,\n t,\n onClick,\n}: {\n item: MergedMenuItem\n active: boolean\n t: (key: string, fallback?: string) => string\n onClick?: () => void\n}) {\n const label = item.labelKey ? t(item.labelKey, item.label) : item.label\n if (!label) return null\n\n const cls = [\n 'flex items-center gap-2.5 rounded-lg px-3 py-2 text-[13px] font-medium transition-colors',\n active\n ? 'bg-foreground text-background'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground',\n ].join(' ')\n\n if (item.href) {\n return (\n <Link href={item.href} className={cls} data-menu-item-id={item.id} onClick={onClick}>\n {label}\n </Link>\n )\n }\n if (item.onClick) {\n return (\n <button type=\"button\" className={cls} data-menu-item-id={item.id} onClick={() => { item.onClick?.(); onClick?.() }}>\n {label}\n </button>\n )\n }\n return null\n}\n\n/* ---- User initials avatar ---- */\n\nfunction UserAvatar({ name, className }: { name?: string; className?: string }) {\n const initials = name\n ? name.split(' ').map((w) => w[0]).slice(0, 2).join('').toUpperCase()\n : '?'\n return (\n <div className={`flex items-center justify-center rounded-full bg-foreground text-[11px] font-semibold text-background ${className ?? 'size-8'}`}>\n {initials}\n </div>\n )\n}\n\n/* ---- Try reading from PortalContext ---- */\n\nfunction useOptionalPortalContext() {\n try {\n return usePortalContext()\n } catch {\n return null\n }\n}\n\n/* ================================================================== */\n/* PortalShell */\n/* ================================================================== */\n\n/**\n * Portal layout shell.\n *\n * When a `PortalProvider` is mounted in a parent layout, PortalShell reads\n * auth/tenant state from context \u2014 no re-fetching on navigation. Props are\n * used as overrides or for public pages that don't have a context.\n */\nexport function PortalShell({\n children,\n orgSlug: orgSlugProp,\n organizationName: orgNameProp,\n logo,\n authenticated: authenticatedProp,\n onLogout: onLogoutProp,\n enableEventBridge = false,\n userName: userNameProp,\n userEmail: userEmailProp,\n}: PortalShellProps) {\n const t = useT()\n const pathname = usePathname()\n const [mobileOpen, setMobileOpen] = useState(false)\n\n // Read from context when available (persists across navigations)\n const portalCtx = useOptionalPortalContext()\n\n // Resolve values: context takes priority, props are fallback/override\n const orgSlug = portalCtx?.orgSlug ?? orgSlugProp\n const orgName = portalCtx?.tenant.organizationName ?? orgNameProp\n const user = portalCtx?.auth.user ?? null\n const authenticated = authenticatedProp ?? !!user\n const onLogout = onLogoutProp ?? portalCtx?.auth.logout\n const userName = userNameProp ?? user?.displayName\n const userEmail = userEmailProp ?? user?.email\n\n const { items: injectedMainItems } = usePortalInjectedMenuItems('menu:portal:sidebar:main')\n const { items: injectedAccountItems } = usePortalInjectedMenuItems('menu:portal:sidebar:account')\n\n const portalHome = orgSlug ? `/${orgSlug}/portal` : '/portal'\n const loginHref = orgSlug ? `/${orgSlug}/portal/login` : '/portal/login'\n const signupHref = orgSlug ? `/${orgSlug}/portal/signup` : '/portal/signup'\n // Always use the resolved organization name from the database.\n // Fall back to the generic portal title \u2014 never display the raw slug.\n const headerTitle = orgName || t('portal.title', 'Customer Portal')\n\n const closeMobile = useCallback(() => setMobileOpen(false), [])\n\n const [autoNavGroups, setAutoNavGroups] = useState<PortalNavGroup[]>([])\n useEffect(() => {\n if (!authenticated) {\n setAutoNavGroups([])\n return\n }\n let cancelled = false\n const load = async () => {\n try {\n const { ok, result } = await apiCall<{ ok: boolean; groups?: PortalNavGroup[] }>(\n '/api/customer_accounts/portal/nav',\n )\n if (cancelled || !ok || !result?.ok) return\n setAutoNavGroups(Array.isArray(result.groups) ? result.groups : [])\n } catch {\n if (!cancelled) setAutoNavGroups([])\n }\n }\n void load()\n return () => {\n cancelled = true\n }\n }, [authenticated])\n\n const mergedNavItems = useMemo(() => {\n if (!authenticated) return []\n const discovered = autoNavGroups.find((g) => g.id === 'main')?.items ?? []\n const builtIn = discovered.map((item) => ({\n id: item.id,\n labelKey: item.labelKey,\n label: item.label,\n href: item.href,\n }))\n return mergeMenuItems(builtIn, injectedMainItems)\n }, [authenticated, autoNavGroups, injectedMainItems])\n\n const mergedAccountItems = useMemo(() => {\n if (!authenticated) return []\n const discovered = autoNavGroups.find((g) => g.id === 'account')?.items ?? []\n const builtIn = discovered.map((item) => ({\n id: item.id,\n labelKey: item.labelKey,\n label: item.label,\n href: item.href,\n }))\n return mergeMenuItems(builtIn, injectedAccountItems)\n }, [authenticated, autoNavGroups, injectedAccountItems])\n\n /* ---- PUBLIC LAYOUT ---- */\n if (!authenticated) {\n return (\n <div className=\"flex min-h-svh flex-col bg-background\" data-portal-handle={PORTAL_SHELL_HANDLE}>\n <header className=\"sticky top-0 z-40 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80\" data-portal-handle={PORTAL_HEADER_HANDLE}>\n <div className=\"mx-auto flex h-16 w-full max-w-screen-lg items-center justify-between px-6\">\n <Link href={portalHome} className=\"flex items-center gap-2.5 text-foreground transition hover:opacity-80\" aria-label={headerTitle}>\n <Image src={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? \"\"} width={28} height={28} className=\"\" priority />\n <span className=\"text-[15px] font-semibold tracking-tight\">{headerTitle}</span>\n </Link>\n <nav aria-label=\"Primary\" className=\"flex items-center gap-1\">\n <Button asChild variant=\"ghost\" size=\"sm\" className=\"text-[13px]\">\n <Link href={loginHref}>{t('portal.nav.login', 'Log In')}</Link>\n </Button>\n <Button asChild size=\"sm\" className=\"rounded-lg text-[13px]\">\n <Link href={signupHref}>{t('portal.nav.signup', 'Sign Up')}</Link>\n </Button>\n </nav>\n </div>\n </header>\n\n <main className=\"flex-1\">\n <div className=\"mx-auto flex w-full max-w-screen-lg flex-col gap-8 px-6 py-12 sm:py-20\">\n {children}\n </div>\n </main>\n\n <footer className=\"border-t\" data-portal-handle={PORTAL_FOOTER_HANDLE}>\n <div className=\"mx-auto flex w-full max-w-screen-lg items-center justify-between px-6 py-6\">\n <Link href={portalHome} className=\"flex items-center gap-2 text-muted-foreground transition hover:text-foreground\">\n <Image src={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? \"\"} width={20} height={20} className=\"\" />\n <span className=\"text-sm font-medium text-foreground\">{headerTitle}</span>\n </Link>\n <p className=\"text-xs text-muted-foreground/60\">\n {t('portal.footer.copyright', '\\u00A9 {year} All rights reserved.', { year: new Date().getFullYear() })}\n </p>\n </div>\n </footer>\n </div>\n )\n }\n\n /* ---- AUTHENTICATED LAYOUT ---- */\n\n const sidebarContent = (\n <div className=\"flex h-full flex-col\" data-portal-handle={PORTAL_SIDEBAR_HANDLE}>\n <div className=\"flex h-16 items-center gap-2.5 border-b px-5\">\n <Link href={portalHome} className=\"flex items-center gap-2.5 text-foreground transition hover:opacity-80\" aria-label={headerTitle}>\n <Image src={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? \"\"} width={22} height={22} className=\"\" />\n <span className=\"text-[14px] font-semibold tracking-tight truncate\">{headerTitle}</span>\n </Link>\n </div>\n\n <nav aria-label=\"Portal navigation\" className=\"flex-1 overflow-y-auto px-3 py-5\">\n <p className=\"mb-2 px-3 text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground/50\">\n {t('portal.nav.home', 'Portal')}\n </p>\n <div className=\"flex flex-col gap-0.5\">\n {mergedNavItems.map((item) => (\n <SidebarNavItem\n key={item.id}\n item={item}\n active={!!item.href && pathname.startsWith(item.href)}\n t={t}\n onClick={closeMobile}\n />\n ))}\n </div>\n\n {mergedAccountItems.length > 0 ? (\n <div className=\"mt-8\">\n <p className=\"mb-2 px-3 text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground/50\">\n {t('portal.nav.account', 'Account')}\n </p>\n <div className=\"flex flex-col gap-0.5\">\n {mergedAccountItems.map((item) => (\n <SidebarNavItem\n key={item.id}\n item={item}\n active={!!item.href && pathname.startsWith(item.href)}\n t={t}\n onClick={closeMobile}\n />\n ))}\n </div>\n </div>\n ) : null}\n </nav>\n\n <div className=\"border-t px-3 py-3\">\n <div className=\"flex items-center gap-2.5 rounded-lg px-3 py-2\">\n <UserAvatar name={userName} className=\"size-8\" />\n <div className=\"min-w-0 flex-1\">\n {userName ? (\n <p className=\"truncate text-[13px] font-medium leading-tight\">{userName}</p>\n ) : (\n <div className=\"h-4 w-24 animate-pulse rounded bg-muted\" />\n )}\n {userEmail ? (\n <p className=\"truncate text-[11px] text-muted-foreground\">{userEmail}</p>\n ) : (\n <div className=\"mt-1 h-3 w-32 animate-pulse rounded bg-muted\" />\n )}\n </div>\n </div>\n <button\n type=\"button\"\n onClick={onLogout}\n className=\"mt-0.5 flex w-full items-center gap-2.5 rounded-lg px-3 py-2 text-[13px] text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n data-portal-handle={PORTAL_USER_MENU_HANDLE}\n data-menu-item-id=\"portal-logout\"\n >\n <LogOutIcon className=\"size-4\" />\n {t('portal.nav.logout', 'Log Out')}\n </button>\n </div>\n </div>\n )\n\n return (\n <div className=\"flex min-h-svh bg-background\" data-portal-handle={PORTAL_SHELL_HANDLE}>\n {enableEventBridge ? <PortalEventBridgeMount /> : null}\n\n <aside className=\"hidden w-[240px] shrink-0 border-r lg:block\">\n {sidebarContent}\n </aside>\n\n {mobileOpen ? (\n <div className=\"fixed inset-0 z-50 lg:hidden\">\n <div className=\"absolute inset-0 bg-black/30 backdrop-blur-sm\" onClick={closeMobile} />\n <aside className=\"relative z-10 h-full w-[280px] bg-background shadow-2xl\">\n <div className=\"absolute right-3 top-4 z-20\">\n <IconButton variant=\"ghost\" size=\"sm\" type=\"button\" onClick={closeMobile} aria-label=\"Close menu\">\n <XIcon className=\"size-4\" />\n </IconButton>\n </div>\n {sidebarContent}\n </aside>\n </div>\n ) : null}\n\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <header className=\"flex h-16 items-center justify-between border-b px-4 lg:px-8\" data-portal-handle={PORTAL_HEADER_HANDLE}>\n <div className=\"flex items-center gap-3\">\n <IconButton variant=\"ghost\" size=\"sm\" type=\"button\" onClick={() => setMobileOpen(true)} className=\"lg:hidden\" aria-label=\"Open menu\">\n <MenuIcon className=\"size-5\" />\n </IconButton>\n </div>\n <div className=\"flex items-center gap-3\">\n <PortalNotificationBell t={t} />\n </div>\n </header>\n\n <main className=\"flex-1 overflow-y-auto\">\n <div className=\"w-full px-4 py-6 lg:px-8 lg:py-8\">\n {children}\n </div>\n </main>\n\n <footer className=\"border-t px-4 py-4 lg:px-8\" data-portal-handle={PORTAL_FOOTER_HANDLE}>\n <p className=\"text-[11px] text-muted-foreground/50\">\n {t('portal.footer.copyright', '\\u00A9 {year} All rights reserved.', { year: new Date().getFullYear() })}\n </p>\n </footer>\n </div>\n </div>\n )\n}\n\nexport default PortalShell\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/ui",
3
- "version": "0.5.1-develop.2851.2854b4507f",
3
+ "version": "0.5.1-develop.2856.35de414092",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -132,12 +132,12 @@
132
132
  "recharts": "^3.8.1"
133
133
  },
134
134
  "peerDependencies": {
135
- "@open-mercato/shared": "0.5.1-develop.2851.2854b4507f",
135
+ "@open-mercato/shared": "0.5.1-develop.2856.35de414092",
136
136
  "react": ">=18.0.0",
137
137
  "react-dom": ">=18.0.0"
138
138
  },
139
139
  "devDependencies": {
140
- "@open-mercato/shared": "0.5.1-develop.2851.2854b4507f",
140
+ "@open-mercato/shared": "0.5.1-develop.2856.35de414092",
141
141
  "@testing-library/dom": "^10.4.1",
142
142
  "@testing-library/jest-dom": "^6.9.1",
143
143
  "@testing-library/react": "^16.3.1",
@@ -41,8 +41,14 @@ import {
41
41
  GLOBAL_SIDEBAR_STATUS_BADGES_INJECTION_SPOT_ID,
42
42
  } from './injection/spotIds'
43
43
 
44
+ export type ShellLogo = {
45
+ src: string
46
+ alt?: string
47
+ }
48
+
44
49
  export type AppShellProps = {
45
50
  productName?: string
51
+ logo?: ShellLogo
46
52
  email?: string
47
53
  groups: {
48
54
  id?: string
@@ -398,7 +404,7 @@ export function AppShell(props: AppShellProps) {
398
404
  )
399
405
  }
400
406
 
401
- function AppShellBody({ productName, email, groups, rightHeaderSlot, children, sidebarCollapsedDefault = false, currentTitle, breadcrumb, version, settingsSectionTitle, settingsPathPrefixes = [], settingsSections, profileSections, profileSectionTitle, profilePathPrefixes = [], mobileSidebarSlot }: AppShellProps) {
407
+ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, children, sidebarCollapsedDefault = false, currentTitle, breadcrumb, version, settingsSectionTitle, settingsPathPrefixes = [], settingsSections, profileSections, profileSectionTitle, profilePathPrefixes = [], mobileSidebarSlot }: AppShellProps) {
402
408
  const pathname = usePathname()
403
409
  const searchParams = useSearchParams()
404
410
  const t = useT()
@@ -808,7 +814,7 @@ function AppShellBody({ productName, email, groups, rightHeaderSlot, children, s
808
814
  {!hideHeader && (
809
815
  <div className={`flex items-center ${compact ? 'justify-center' : 'justify-between'} mb-2`}>
810
816
  <Link href="/backend" className="flex items-center gap-2" aria-label={t('appShell.goToDashboard')}>
811
- <Image src="/open-mercato.svg" alt={resolvedProductName} width={32} height={32} className="rounded m-4" />
817
+ <Image src={logo?.src ?? "/open-mercato.svg"} alt={logo?.alt ?? resolvedProductName} width={32} height={32} className="rounded m-4" />
812
818
  {!compact && <div className="text-m font-semibold">{resolvedProductName}</div>}
813
819
  </Link>
814
820
  </div>
@@ -919,7 +925,7 @@ function AppShellBody({ productName, email, groups, rightHeaderSlot, children, s
919
925
  {!hideHeader ? (
920
926
  <div className={`flex items-center ${compact ? 'justify-center' : 'justify-between'} mb-2`}>
921
927
  <Link href="/backend" className="flex items-center gap-2" aria-label={t('appShell.goToDashboard')}>
922
- <Image src="/open-mercato.svg" alt={resolvedProductName} width={32} height={32} className="rounded m-4" />
928
+ <Image src={logo?.src ?? "/open-mercato.svg"} alt={logo?.alt ?? resolvedProductName} width={32} height={32} className="rounded m-4" />
923
929
  {!compact && <div className="text-m font-semibold">{resolvedProductName}</div>}
924
930
  </Link>
925
931
  </div>
@@ -1168,7 +1174,7 @@ function AppShellBody({ productName, email, groups, rightHeaderSlot, children, s
1168
1174
  {!hideHeader && (
1169
1175
  <div className={`flex items-center ${compact ? 'justify-center' : 'justify-between'} mb-2`}>
1170
1176
  <Link href="/backend" className="flex items-center gap-2" aria-label={t('appShell.goToDashboard')}>
1171
- <Image src="/open-mercato.svg" alt={resolvedProductName} width={32} height={32} className="rounded m-4" />
1177
+ <Image src={logo?.src ?? "/open-mercato.svg"} alt={logo?.alt ?? resolvedProductName} width={32} height={32} className="rounded m-4" />
1172
1178
  {!compact && <div className="text-m font-semibold">{resolvedProductName}</div>}
1173
1179
  </Link>
1174
1180
  </div>
@@ -1552,7 +1558,7 @@ function AppShellBody({ productName, email, groups, rightHeaderSlot, children, s
1552
1558
  <aside className="absolute left-0 top-0 flex h-full w-[260px] flex-col bg-background border-r overflow-hidden">
1553
1559
  <div className="shrink-0 p-3 pb-2 flex items-center justify-between border-b">
1554
1560
  <Link href="/backend" className="flex items-center gap-2 text-sm font-semibold" onClick={() => setMobileOpen(false)} aria-label={t('appShell.goToDashboard')}>
1555
- <Image src="/open-mercato.svg" alt={resolvedProductName} width={28} height={28} className="rounded" />
1561
+ <Image src={logo?.src ?? "/open-mercato.svg"} alt={logo?.alt ?? resolvedProductName} width={28} height={28} className="rounded" />
1556
1562
  {resolvedProductName}
1557
1563
  </Link>
1558
1564
  <IconButton variant="outline" size="sm" onClick={() => setMobileOpen(false)} aria-label={t('appShell.closeMenu')}>✕</IconButton>
@@ -22,12 +22,19 @@ export const PORTAL_FOOTER_HANDLE = 'section:portal:footer'
22
22
  export const PORTAL_SIDEBAR_HANDLE = 'section:portal:sidebar'
23
23
  export const PORTAL_USER_MENU_HANDLE = 'section:portal:user-menu'
24
24
 
25
+ export type ShellLogo = {
26
+ src: string
27
+ alt?: string
28
+ }
29
+
25
30
  export type PortalShellProps = {
26
31
  children: ReactNode
27
32
  /** Override orgSlug (used on public pages without context) */
28
33
  orgSlug?: string
29
34
  /** Override organization name (used on public pages without context) */
30
35
  organizationName?: string
36
+ /** Override the brand logo rendered in the header, footer, and sidebar. */
37
+ logo?: ShellLogo
31
38
  /** Whether to show authenticated layout. Auto-detected from context when omitted. */
32
39
  authenticated?: boolean
33
40
  /** Logout handler. Auto-provided from context when omitted. */
@@ -148,6 +155,7 @@ export function PortalShell({
148
155
  children,
149
156
  orgSlug: orgSlugProp,
150
157
  organizationName: orgNameProp,
158
+ logo,
151
159
  authenticated: authenticatedProp,
152
160
  onLogout: onLogoutProp,
153
161
  enableEventBridge = false,
@@ -237,7 +245,7 @@ export function PortalShell({
237
245
  <header className="sticky top-0 z-40 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80" data-portal-handle={PORTAL_HEADER_HANDLE}>
238
246
  <div className="mx-auto flex h-16 w-full max-w-screen-lg items-center justify-between px-6">
239
247
  <Link href={portalHome} className="flex items-center gap-2.5 text-foreground transition hover:opacity-80" aria-label={headerTitle}>
240
- <Image src="/open-mercato.svg" alt="" width={28} height={28} className="" priority />
248
+ <Image src={logo?.src ?? "/open-mercato.svg"} alt={logo?.alt ?? ""} width={28} height={28} className="" priority />
241
249
  <span className="text-[15px] font-semibold tracking-tight">{headerTitle}</span>
242
250
  </Link>
243
251
  <nav aria-label="Primary" className="flex items-center gap-1">
@@ -260,7 +268,7 @@ export function PortalShell({
260
268
  <footer className="border-t" data-portal-handle={PORTAL_FOOTER_HANDLE}>
261
269
  <div className="mx-auto flex w-full max-w-screen-lg items-center justify-between px-6 py-6">
262
270
  <Link href={portalHome} className="flex items-center gap-2 text-muted-foreground transition hover:text-foreground">
263
- <Image src="/open-mercato.svg" alt="" width={20} height={20} className="" />
271
+ <Image src={logo?.src ?? "/open-mercato.svg"} alt={logo?.alt ?? ""} width={20} height={20} className="" />
264
272
  <span className="text-sm font-medium text-foreground">{headerTitle}</span>
265
273
  </Link>
266
274
  <p className="text-xs text-muted-foreground/60">
@@ -278,7 +286,7 @@ export function PortalShell({
278
286
  <div className="flex h-full flex-col" data-portal-handle={PORTAL_SIDEBAR_HANDLE}>
279
287
  <div className="flex h-16 items-center gap-2.5 border-b px-5">
280
288
  <Link href={portalHome} className="flex items-center gap-2.5 text-foreground transition hover:opacity-80" aria-label={headerTitle}>
281
- <Image src="/open-mercato.svg" alt="" width={22} height={22} className="" />
289
+ <Image src={logo?.src ?? "/open-mercato.svg"} alt={logo?.alt ?? ""} width={22} height={22} className="" />
282
290
  <span className="text-[14px] font-semibold tracking-tight truncate">{headerTitle}</span>
283
291
  </Link>
284
292
  </div>