@open-mercato/ui 0.6.6-develop.6317.1.b3be10ab84 → 0.6.6-develop.6331.1.a33b8e99b7
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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/backend/AppShell.js +13 -2
- package/dist/backend/AppShell.js.map +2 -2
- package/dist/backend/CrudForm.js +2 -1
- package/dist/backend/CrudForm.js.map +2 -2
- package/dist/backend/OrganizationScopeBoundary.js +33 -0
- package/dist/backend/OrganizationScopeBoundary.js.map +7 -0
- package/dist/backend/conflicts/index.js +50 -13
- package/dist/backend/conflicts/index.js.map +2 -2
- package/dist/backend/detail/AddressesSection.js +9 -5
- package/dist/backend/detail/AddressesSection.js.map +2 -2
- package/dist/backend/detail/NotesSection.js +11 -6
- package/dist/backend/detail/NotesSection.js.map +2 -2
- package/dist/backend/injection/recordContext.js +40 -0
- package/dist/backend/injection/recordContext.js.map +7 -0
- package/dist/backend/notifications/NotificationPanel.js +14 -28
- package/dist/backend/notifications/NotificationPanel.js.map +2 -2
- package/dist/backend/utils/optimisticLock.js +19 -1
- package/dist/backend/utils/optimisticLock.js.map +2 -2
- package/package.json +3 -3
- package/src/backend/AppShell.tsx +26 -2
- package/src/backend/CrudForm.tsx +4 -1
- package/src/backend/OrganizationScopeBoundary.tsx +54 -0
- package/src/backend/__tests__/CrudForm.custom-fields.test.tsx +59 -0
- package/src/backend/__tests__/NotesSection.test.tsx +71 -0
- package/src/backend/__tests__/OrganizationScopeBoundary.test.tsx +74 -0
- package/src/backend/conflicts/__tests__/recordLockDeferral.test.ts +99 -0
- package/src/backend/conflicts/index.ts +96 -19
- package/src/backend/detail/AddressesSection.tsx +12 -7
- package/src/backend/detail/NotesSection.tsx +19 -8
- package/src/backend/injection/recordContext.tsx +101 -0
- package/src/backend/notifications/NotificationPanel.tsx +35 -38
- package/src/backend/notifications/__tests__/NotificationPanel.test.tsx +124 -0
- package/src/backend/utils/optimisticLock.ts +36 -0
package/.turbo/turbo-build.log
CHANGED
package/dist/backend/AppShell.js
CHANGED
|
@@ -26,11 +26,15 @@ import { dismissRecordConflict } from "./conflicts/store.js";
|
|
|
26
26
|
import { ProgressTopBar } from "./progress/ProgressTopBar.js";
|
|
27
27
|
import { UpgradeActionBanner } from "./upgrades/UpgradeActionBanner.js";
|
|
28
28
|
import { PartialIndexBanner } from "./indexes/PartialIndexBanner.js";
|
|
29
|
+
import { OrganizationScopeBoundary } from "./OrganizationScopeBoundary.js";
|
|
29
30
|
import { useLocale, useT } from "@open-mercato/shared/lib/i18n/context";
|
|
30
31
|
import { slugifySidebarId } from "@open-mercato/shared/modules/navigation/sidebarPreferences";
|
|
31
32
|
import { readVersionedPreference, writeVersionedPreference } from "@open-mercato/shared/lib/browser/versionedPreference";
|
|
32
33
|
import { cloneSidebarGroups } from "./sidebar/customization-helpers.js";
|
|
33
34
|
import { InjectionSpot } from "./injection/InjectionSpot.js";
|
|
35
|
+
import {
|
|
36
|
+
BackendRecordInjectionContextProvider
|
|
37
|
+
} from "./injection/recordContext.js";
|
|
34
38
|
import { LEGACY_GLOBAL_MUTATION_INJECTION_SPOT_ID } from "./injection/mutationEvents.js";
|
|
35
39
|
import { mergeMenuItems } from "./injection/mergeMenuItems.js";
|
|
36
40
|
import { useInjectedMenuItems } from "./injection/useInjectedMenuItems.js";
|
|
@@ -399,6 +403,13 @@ function AppShellBody({ productName, logo, email, canManageUpgradeActions = fals
|
|
|
399
403
|
}),
|
|
400
404
|
[pathname, searchParams]
|
|
401
405
|
);
|
|
406
|
+
const [currentRecordInjectionContext, setCurrentRecordInjectionContext] = React.useState(null);
|
|
407
|
+
const recordInjectionContext = React.useMemo(() => {
|
|
408
|
+
if (!currentRecordInjectionContext) return injectionContext;
|
|
409
|
+
const publishedPath = currentRecordInjectionContext.path;
|
|
410
|
+
if (publishedPath && pathname && publishedPath !== pathname) return injectionContext;
|
|
411
|
+
return { ...injectionContext, ...currentRecordInjectionContext };
|
|
412
|
+
}, [injectionContext, currentRecordInjectionContext, pathname]);
|
|
402
413
|
const isOnSettingsPath = React.useMemo(() => {
|
|
403
414
|
if (!pathname) return false;
|
|
404
415
|
if (pathname === "/backend/settings") return true;
|
|
@@ -1044,7 +1055,7 @@ function AppShellBody({ productName, logo, email, canManageUpgradeActions = fals
|
|
|
1044
1055
|
canManageUpgradeActions ? /* @__PURE__ */ jsx(UpgradeActionBanner, {}) : null,
|
|
1045
1056
|
/* @__PURE__ */ jsx(LastOperationBanner, {}),
|
|
1046
1057
|
/* @__PURE__ */ jsx(RecordConflictBanner, {}),
|
|
1047
|
-
/* @__PURE__ */ jsx(InjectionSpot, { spotId: BACKEND_RECORD_CURRENT_INJECTION_SPOT_ID, context:
|
|
1058
|
+
/* @__PURE__ */ jsx(InjectionSpot, { spotId: BACKEND_RECORD_CURRENT_INJECTION_SPOT_ID, context: recordInjectionContext }),
|
|
1048
1059
|
/* @__PURE__ */ jsx(
|
|
1049
1060
|
InjectionSpot,
|
|
1050
1061
|
{
|
|
@@ -1053,7 +1064,7 @@ function AppShellBody({ productName, logo, email, canManageUpgradeActions = fals
|
|
|
1053
1064
|
}
|
|
1054
1065
|
),
|
|
1055
1066
|
/* @__PURE__ */ jsx("div", { id: "om-top-banners", className: "mb-3 space-y-2" }),
|
|
1056
|
-
children,
|
|
1067
|
+
/* @__PURE__ */ jsx(OrganizationScopeBoundary, { active: isOnSettingsPath, children: /* @__PURE__ */ jsx(BackendRecordInjectionContextProvider, { setCurrentRecordInjectionContext, children }) }),
|
|
1057
1068
|
/* @__PURE__ */ jsx(InjectionSpot, { spotId: BACKEND_LAYOUT_FOOTER_INJECTION_SPOT_ID, context: injectionContext })
|
|
1058
1069
|
] }),
|
|
1059
1070
|
/* @__PURE__ */ jsxs("footer", { className: "border-t bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/80 px-4 py-3 flex flex-wrap items-center justify-end gap-4", children: [
|
|
@@ -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 { ChevronDown, ChevronLeft, Home, PanelLeftClose, PanelLeftOpen, Search, X } from 'lucide-react'\nimport { Button } from '../primitives/button'\nimport {\n Breadcrumb as BreadcrumbNav,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from '../primitives/breadcrumb'\nimport { IconButton } from '../primitives/icon-button'\nimport { Input } from '../primitives/input'\nimport { SearchInput } from '../primitives/search-input'\nimport { Checkbox } from '../primitives/checkbox'\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 { RecordConflictBanner } from './conflicts/RecordConflictBanner'\nimport { dismissRecordConflict } from './conflicts/store'\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 { readVersionedPreference, writeVersionedPreference } from '@open-mercato/shared/lib/browser/versionedPreference'\nimport { cloneSidebarGroups } from './sidebar/customization-helpers'\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 { AiDockProvider } from '../ai/AiDock'\nimport { AiChatSessionsProvider } from '../ai/AiChatSessions'\nimport { AiAssistantLauncher } from '../ai/AiAssistantLauncher'\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\n// Versioned-envelope discriminator for the persisted sidebar open/closed group\n// map. This is a structured value (a record), so it carries a version so future\n// shape changes can migrate or safely discard stale data; legacy bare\n// `Record<string, boolean>` values are migrated forward on the next write. The\n// neighbouring `om:sidebarCollapsed` / `om:progress:expanded` flags are trivial\n// scalar booleans and deliberately stay raw (see their write sites). See\n// `@open-mercato/shared/lib/browser/versionedPreference`.\nconst SIDEBAR_OPEN_GROUPS_KEY = 'om:sidebarOpenGroups'\nconst SIDEBAR_OPEN_GROUPS_VERSION = 1\n\nfunction isBooleanRecord(value: unknown): value is Record<string, boolean> {\n return (\n !!value &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n Object.values(value as Record<string, unknown>).every((entry) => typeof entry === 'boolean')\n )\n}\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 canManageUpgradeActions?: boolean\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 * How long (ms) to keep successfully completed progress operations visible\n * before auto-hiding. Pass `false` or `0` to disable. Defaults to 10 000 ms.\n */\n progressCompletedAutoHideMs?: number | false\n}\n\ntype Breadcrumb = Array<{ label: string; href?: string }>\n\ntype SidebarGroup = AppShellProps['groups'][number]\ntype SidebarItem = SidebarGroup['items'][number]\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 shouldBypassLogoOptimization(src?: string | null): boolean {\n const value = src ?? ''\n return /^https?:\\/\\//.test(value) || /^\\/api\\/attachments\\/(?:image|file)\\//.test(value)\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 <AiChatSessionsProvider>\n <AiDockProvider>\n <AppShellBody {...props} />\n </AiDockProvider>\n </AiChatSessionsProvider>\n </BackendChromeProvider>\n </QueryProvider>\n )\n}\n\nfunction AppShellBody({ productName, logo, email, canManageUpgradeActions = false, groups, rightHeaderSlot, children, sidebarCollapsedDefault = false, currentTitle, breadcrumb, version, settingsSectionTitle, settingsPathPrefixes = [], settingsSections, profileSections, profileSectionTitle, profilePathPrefixes = [], mobileSidebarSlot, progressCompletedAutoHideMs }: 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 () => cloneSidebarGroups(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 resolvedLogo = chromePayload?.brand?.logo?.src ? chromePayload.brand.logo : logo\n const resolvedBrandName = chromePayload?.brand?.logo?.src\n ? chromePayload.brand.name ?? resolvedProductName\n : resolvedProductName\n const resolvedLogoBypassesOptimization = shouldBypassLogoOptimization(resolvedLogo?.src)\n const [mobileOpen, setMobileOpen] = React.useState(false)\n // When the mobile drawer opens on a settings/profile route, it follows the\n // section sidebar by default. Set to 'main' to force-show the main nav even\n // when the route is in a section context. Reset on close.\n const [mobileDrawerView, setMobileDrawerView] = React.useState<'auto' | 'main'>('auto')\n // Clear the persistent record-conflict bar when the route changes. The\n // conflict is scoped to the record the user was editing, so navigating to an\n // unrelated page should dismiss it instead of carrying a stale \"Record\n // changed\" bar across modules.\n React.useEffect(() => {\n dismissRecordConflict()\n }, [pathname])\n React.useEffect(() => {\n if (!mobileOpen) setMobileDrawerView('auto')\n }, [mobileOpen])\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 [headerTitle, setHeaderTitle] = React.useState<string | undefined>(currentTitle)\n const [headerBreadcrumb, setHeaderBreadcrumb] = React.useState<Breadcrumb | undefined>(breadcrumb)\n const [navQuery, setNavQuery] = React.useState('')\n const navQueryNorm = navQuery.trim().toLowerCase()\n const navQueryActive = navQueryNorm.length > 0\n const matchesQuery = React.useCallback((label: string | undefined) => {\n if (!navQueryActive) return true\n if (!label) return false\n return label.toLowerCase().includes(navQueryNorm)\n }, [navQueryActive, navQueryNorm])\n const effectiveCollapsed = collapsed\n const expandedSidebarWidth = '240px'\n\n // Track scroll position of the desktop sidebar's inner scroll container so we can\n // flip the affordance chevron between down/up (and hide it entirely when content\n // fits without scrolling). The inner div is rendered deep in renderSidebar /\n // renderSectionSidebar \u2014 we tag it with `data-sidebar-scroll=\"true\"` and look it\n // up via the aside ref so we don't have to thread refs through the JSX tree.\n const sidebarAsideRef = React.useRef<HTMLElement>(null)\n const [sidebarScrollState, setSidebarScrollState] = React.useState<'down' | 'up' | 'none'>('down')\n const sidebarScrollIntentRef = React.useRef<'top' | 'bottom' | null>(null)\n\n // Click-to-scroll handler for the sidebar affordance chevron (#1803). Resolves the\n // scroll target lazily through the aside ref so we don't have to thread refs into\n // renderSidebar; respects `prefers-reduced-motion` by falling back to instant\n // scrolling when the user has opted out of smooth motion.\n const handleSidebarChevronScroll = React.useCallback((target: 'top' | 'bottom') => {\n const aside = sidebarAsideRef.current\n if (!aside) return\n const scrollTarget = aside.querySelector<HTMLElement>('[data-sidebar-scroll=\"true\"]')\n if (!scrollTarget) return\n const prefersReducedMotion =\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches\n const behavior: ScrollBehavior = prefersReducedMotion ? 'auto' : 'smooth'\n const maxScrollTop = Math.max(0, scrollTarget.scrollHeight - scrollTarget.clientHeight)\n if (maxScrollTop <= 1) {\n sidebarScrollIntentRef.current = null\n setSidebarScrollState('none')\n return\n }\n sidebarScrollIntentRef.current = target\n setSidebarScrollState(target === 'bottom' ? 'up' : 'down')\n scrollTarget.scrollTo({\n top: target === 'top' ? 0 : maxScrollTop,\n behavior,\n })\n }, [])\n React.useEffect(() => {\n const aside = sidebarAsideRef.current\n if (!aside) return\n const target = aside.querySelector<HTMLElement>('[data-sidebar-scroll=\"true\"]')\n if (!target) return\n const update = () => {\n const { scrollTop, scrollHeight, clientHeight } = target\n const canScroll = scrollHeight > clientHeight + 1\n if (!canScroll) {\n sidebarScrollIntentRef.current = null\n setSidebarScrollState('none')\n return\n }\n const maxScrollTop = Math.max(0, scrollHeight - clientHeight)\n const atTop = scrollTop <= 8\n const atBottom = scrollTop >= maxScrollTop - 8\n const scrollIntent = sidebarScrollIntentRef.current\n if (scrollIntent === 'bottom') {\n if (atBottom) sidebarScrollIntentRef.current = null\n setSidebarScrollState('up')\n return\n }\n if (scrollIntent === 'top') {\n if (atTop) sidebarScrollIntentRef.current = null\n setSidebarScrollState('down')\n return\n }\n setSidebarScrollState(atBottom ? 'up' : 'down')\n }\n update()\n target.addEventListener('scroll', update, { passive: true })\n const ro = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(update) : null\n ro?.observe(target)\n return () => {\n target.removeEventListener('scroll', update)\n ro?.disconnect()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pathname, effectiveCollapsed])\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 const parsed = readVersionedPreference<Record<string, boolean>>(\n SIDEBAR_OPEN_GROUPS_KEY,\n SIDEBAR_OPEN_GROUPS_VERSION,\n isBooleanRecord,\n {},\n { legacyIsValid: isBooleanRecord },\n )\n if (Object.keys(parsed).length === 0) return\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 }, [resolvedGroups])\n\n const toggleGroup = (groupId: string) => setOpenGroups((prev) => ({ ...prev, [groupId]: prev[groupId] === false }))\n\n const asideWidth = effectiveCollapsed ? '80px' : 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 py-4`;\n\n // Persist collapse state to localStorage and cookie. Both writes can throw in\n // private/incognito mode (storage blocked) or when cookies are disabled \u2014\n // the persisted preference is purely a UX nice-to-have, never functional, so\n // swallow the failure and let the component fall back to the default state.\n // This is a trivial scalar flag ('1' | '0') with no schema to evolve, so it is\n // intentionally kept raw rather than wrapped in a versioned envelope (the\n // versioning threshold lives in `@open-mercato/shared/lib/browser/versionedPreference`).\n React.useEffect(() => {\n try { localStorage.setItem('om:sidebarCollapsed', collapsed ? '1' : '0') } catch { /* localStorage blocked (private mode) \u2014 non-critical */ }\n try {\n document.cookie = `om_sidebar_collapsed=${collapsed ? '1' : '0'}; path=/; max-age=31536000; samesite=lax`\n } catch { /* cookies disabled \u2014 non-critical */ }\n }, [collapsed])\n\n // Two-level sidebar (Option B): when entering settings/profile mode, force the\n // main sidebar to collapsed (icons only) so the section sub-nav can sit beside\n // it; restore the user's previous expansion when returning to the main mode.\n // Initial ref is 'main' so direct mounts on /backend/settings also auto-collapse.\n const collapsedBeforeSectionRef = React.useRef<boolean | null>(null)\n const previousSidebarModeRef = React.useRef<'main' | 'settings' | 'profile'>('main')\n React.useEffect(() => {\n const previous = previousSidebarModeRef.current\n if (previous === 'main' && sidebarMode !== 'main') {\n collapsedBeforeSectionRef.current = collapsed\n if (!collapsed) setCollapsed(true)\n } else if (previous !== 'main' && sidebarMode === 'main' && collapsedBeforeSectionRef.current !== null) {\n const restoreTo = collapsedBeforeSectionRef.current\n collapsedBeforeSectionRef.current = null\n if (collapsed !== restoreTo) setCollapsed(restoreTo)\n }\n previousSidebarModeRef.current = sidebarMode\n }, [sidebarMode, collapsed])\n React.useEffect(() => {\n writeVersionedPreference(SIDEBAR_OPEN_GROUPS_KEY, SIDEBAR_OPEN_GROUPS_VERSION, openGroups)\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 setNavGroups(cloneSidebarGroups(resolvedGroups))\n }, [resolvedGroups])\n\n function renderSectionSidebar(\n sections: SectionNavGroup[],\n title: string,\n compact: boolean,\n hideHeader?: boolean,\n hideSearch?: 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 h-full flex-col gap-3\">\n {!hideHeader && (\n <div className=\"mb-2\">\n <Link\n href=\"/backend\"\n className={`flex items-center gap-3 rounded-xl transition-colors hover:bg-muted ${compact ? 'p-2 justify-center' : 'p-3'}`}\n aria-label={t('appShell.goToDashboard')}\n >\n <Image src={resolvedLogo?.src ?? \"/open-mercato.svg\"} alt={resolvedLogo?.alt ?? resolvedBrandName} width={40} height={40} className=\"rounded-full shrink-0\" unoptimized={resolvedLogoBypassesOptimization ? true : undefined} />\n {!compact && <span className=\"truncate text-sm font-medium text-foreground\">{resolvedBrandName}</span>}\n </Link>\n </div>\n )}\n {!compact && !hideSearch && (\n <SearchInput\n value={navQuery}\n onChange={setNavQuery}\n placeholder={t('appShell.searchNavPlaceholder', 'Search...')}\n aria-label={t('appShell.searchNavAria', 'Search navigation')}\n clearLabel={t('appShell.searchNavClear', 'Clear search')}\n className=\"mb-2\"\n />\n )}\n <div data-sidebar-scroll=\"true\" className={`flex flex-1 flex-col gap-3 overflow-y-auto scrollbar-hide pr-1 ${compact ? '-ml-2 pl-2' : '-ml-3 pl-3'}`}>\n <nav className=\"flex flex-col gap-2\">\n {sortedSections.map((section, sectionIndex) => {\n const sectionNavQueryActive = hideSearch ? false : navQueryActive\n const matchesItemQuery = (item: typeof section.items[number]): boolean => {\n if (!sectionNavQueryActive) return true\n const label = item.labelKey ? t(item.labelKey, item.label) : item.label\n if (matchesQuery(label)) return true\n return Array.isArray(item.children) && item.children.some(matchesItemQuery)\n }\n const visibleItems = sectionNavQueryActive\n ? section.items.filter(matchesItemQuery)\n : 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 const filterChildren = (children: typeof section.items | undefined) => {\n if (!children) return [] as typeof section.items\n if (!sectionNavQueryActive) return [...children]\n return children.filter(matchesItemQuery)\n }\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(filterChildren(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 || sectionNavQueryActive)\n const isActive = isOnItemBranch || hasActiveChild\n const base = compact ? 'w-10 h-10 justify-center' : 'w-full py-2 gap-2'\n const spacingStyle = !compact\n ? {\n paddingLeft: `${12 + depth * 16}px`,\n paddingRight: '12px',\n }\n : undefined\n\n return (\n <React.Fragment key={item.id}>\n <Link\n href={item.href}\n className={`relative text-sm font-medium rounded-lg inline-flex items-center ${base} ${\n isActive\n ? 'bg-muted text-foreground'\n : 'text-muted-foreground hover:bg-muted'\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 aria-hidden className={`absolute ${compact ? 'left-[-20px]' : 'left-[-12px]'} top-2 w-1 h-5 rounded-r bg-foreground`} />\n )}\n <span className=\"flex items-center justify-center shrink-0\">\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 {!compact && (\n <Button\n variant=\"muted\"\n onClick={() => toggleGroup(sectionKey)}\n className=\"w-full px-1 justify-between flex text-xs font-medium uppercase tracking-wider text-muted-foreground/70 py-1\"\n aria-expanded={open}\n >\n <span>{sectionLabel}</span>\n <Chevron open={open} />\n </Button>\n )}\n {(open || compact) && (\n <div className={`flex flex-col ${compact ? 'items-center' : ''} gap-1`}>\n {sortedItems.map((item) => renderSectionItem(item))}\n </div>\n )}\n {sectionIndex !== lastVisibleIndex && <div className={`my-2 border-t ${compact ? '-ml-2 -mr-3' : '-ml-3 -mr-4'}`} />}\n </div>\n )\n })}\n </nav>\n </div>\n </div>\n )\n }\n\n function renderSidebar(compact: boolean, hideHeader?: boolean, forceMainOnly?: boolean) {\n if (!isChromeReady && isChromeLoading) {\n return (\n <div className=\"flex flex-col min-h-full gap-3\" data-testid=\"backend-chrome-loading\">\n {!hideHeader ? (\n <div className=\"mb-2\">\n <Link\n href=\"/backend\"\n className={`flex items-center gap-3 rounded-xl transition-colors hover:bg-muted ${compact ? 'p-2 justify-center' : 'p-3'}`}\n aria-label={t('appShell.goToDashboard')}\n >\n <Image src={resolvedLogo?.src ?? \"/open-mercato.svg\"} alt={resolvedLogo?.alt ?? resolvedBrandName} width={40} height={40} className=\"rounded-full shrink-0\" unoptimized={resolvedLogoBypassesOptimization ? true : undefined} />\n {!compact && <span className=\"truncate text-sm font-medium text-foreground\">{resolvedBrandName}</span>}\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/50\" />\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/50\" />\n <div className=\"h-8 rounded bg-muted/50\" />\n </div>\n </div>\n <div className=\"space-y-3\">\n <div className=\"h-8 rounded bg-muted/50\" />\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/50\" />\n </div>\n </div>\n </div>\n </div>\n )\n }\n\n if (!forceMainOnly && 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 (!forceMainOnly && 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\n return (\n <div className=\"flex h-full flex-col gap-3\">\n {!hideHeader && (\n <div className=\"mb-2\">\n <Link\n href=\"/backend\"\n className={`flex items-center gap-3 rounded-xl transition-colors hover:bg-muted ${compact ? 'p-2 justify-center' : 'p-3'}`}\n aria-label={t('appShell.goToDashboard')}\n >\n <Image src={resolvedLogo?.src ?? \"/open-mercato.svg\"} alt={resolvedLogo?.alt ?? resolvedBrandName} width={40} height={40} className=\"rounded-full shrink-0\" unoptimized={resolvedLogoBypassesOptimization ? true : undefined} />\n {!compact && <span className=\"truncate text-sm font-medium text-foreground\">{resolvedBrandName}</span>}\n </Link>\n </div>\n )}\n {shouldRenderSidebarInjectionSpots ? (\n <InjectionSpot\n spotId={BACKEND_SIDEBAR_TOP_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n {!compact && (\n <SearchInput\n value={navQuery}\n onChange={setNavQuery}\n placeholder={t('appShell.searchNavPlaceholder', 'Search...')}\n aria-label={t('appShell.searchNavAria', 'Search navigation')}\n clearLabel={t('appShell.searchNavClear', 'Clear search')}\n className=\"mb-2\"\n />\n )}\n <div data-sidebar-scroll=\"true\" className={`flex flex-1 flex-col gap-3 overflow-y-auto scrollbar-hide pr-1 ${compact ? '-ml-2 pl-2' : '-ml-3 pl-3'}`}>\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 = navQueryActive ? true : openGroups[groupId] !== false\n const visibleItems = g.items.filter((item) => {\n if (item.hidden === true) return false\n if (!navQueryActive) return true\n if (matchesQuery(item.title)) return true\n const itemChildren = (item.children ?? []).filter((c) => c.hidden !== true)\n return itemChildren.some((c) => matchesQuery(c.title))\n })\n if (visibleItems.length === 0) return null\n return (\n <div key={groupId}>\n {!compact && (\n <Button\n variant=\"muted\"\n onClick={() => toggleGroup(groupId)}\n className=\"w-full px-1 justify-between flex text-xs font-medium uppercase tracking-wider text-muted-foreground/70 py-1\"\n aria-expanded={open}\n >\n <span>{g.name}</span>\n <Chevron open={open} />\n </Button>\n )}\n {(open || compact) && (\n <div className={`flex flex-col ${compact ? 'items-center' : ''} gap-1`}>\n {visibleItems.map((i) => {\n const allChildItems = (i.children ?? []).filter((child) => child.hidden !== true)\n const matchingChildItems = navQueryActive\n ? allChildItems.filter((c) => matchesQuery(c.title))\n : allChildItems\n const childItems = navQueryActive ? matchingChildItems : allChildItems\n const showChildren = navQueryActive\n ? matchingChildItems.length > 0\n : (!!pathname && allChildItems.length > 0 && pathname.startsWith(i.href))\n const hasActiveChild = !!(pathname && allChildItems.some((c) => pathname.startsWith(c.href)))\n const isParentActive = (pathname === i.href) || (!navQueryActive && showChildren && !hasActiveChild)\n const base = compact ? 'w-10 h-10 justify-center' : 'w-full px-3 py-2 gap-2'\n return (\n <React.Fragment key={i.href}>\n <Link\n href={i.href}\n className={`relative text-sm font-medium rounded-lg inline-flex items-center ${base} ${\n isParentActive ? 'bg-muted text-foreground' : 'text-muted-foreground hover:bg-muted'\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 aria-hidden className={`absolute ${compact ? 'left-[-20px]' : 'left-[-12px]'} top-2 w-1 h-5 rounded-r bg-foreground`} />\n ) : null}\n <span className=\"flex items-center justify-center shrink-0\">\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={`relative flex flex-col ${compact ? 'items-center' : ''} gap-1`}>\n {!compact && (\n <span aria-hidden className=\"pointer-events-none absolute left-1.5 top-1 bottom-1 w-px bg-border\" />\n )}\n {childItems.map((c) => {\n const childActive = pathname?.startsWith(c.href)\n const childBase = compact ? 'w-10 h-8 justify-center' : 'w-full pl-5 pr-3 py-2 gap-2'\n return (\n <Link\n key={c.href}\n href={c.href}\n className={`relative text-sm font-medium rounded-lg inline-flex items-center ${childBase} ${\n childActive ? 'bg-muted text-foreground' : 'text-muted-foreground hover:bg-muted'\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 aria-hidden className={`absolute ${compact ? 'left-[-20px]' : 'left-[-12px]'} top-2 w-1 h-5 rounded-r bg-foreground`} />\n ) : null}\n <span className=\"flex items-center justify-center shrink-0\">\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 ${compact ? '-ml-2 -mr-3' : '-ml-3 -mr-4'}`} />}\n </div>\n )\n })}\n </nav>\n </>\n )\n })()}\n </div>\n <div className=\"sticky bottom-0 bg-background pb-1\">\n {shouldRenderSidebarInjectionSpots ? (\n <InjectionSpot\n spotId={BACKEND_SIDEBAR_NAV_FOOTER_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n {shouldRenderSidebarInjectionSpots ? (\n <StatusBadgeInjectionSpot\n spotId={GLOBAL_SIDEBAR_STATUS_BADGES_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\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 function renderSectionAside() {\n let sections: SectionNavGroup[] | null = null\n let title = ''\n if (sidebarMode === 'settings' && resolvedSettingsSections && resolvedSettingsSections.length > 0) {\n sections = mergeSectionGroupsWithInjected(\n resolvedSettingsSections,\n settingsSidebarInjectedMenuItems,\n t,\n )\n title = settingsSectionTitle ?? t('backend.nav.settings', 'Settings')\n } else if (sidebarMode === 'profile' && resolvedProfileSections && resolvedProfileSections.length > 0) {\n sections = mergeSectionGroupsWithInjected(\n resolvedProfileSections,\n profileSidebarInjectedMenuItems,\n t,\n )\n title = profileSectionTitle ?? t('backend.nav.profile', 'Profile')\n }\n if (!sections) return null\n return (\n <div className=\"flex h-full flex-col gap-2\">\n <Link\n href=\"/backend\"\n className=\"inline-flex items-center gap-2 rounded-lg px-2 py-2 text-sm font-semibold text-foreground transition-colors hover:bg-muted\"\n data-testid=\"appshell-section-back-to-main\"\n aria-label={t('backend.nav.backToMain', 'Back to Main')}\n >\n <ChevronLeft className=\"size-4 shrink-0\" aria-hidden />\n <span className=\"truncate\">{title}</span>\n </Link>\n <div className=\"min-h-0 flex-1\">\n {renderSectionSidebar(sections, title, false, true, true)}\n </div>\n </div>\n )\n }\n\n const isSectionView =\n (sidebarMode === 'settings' && !!resolvedSettingsSections && resolvedSettingsSections.length > 0) ||\n (sidebarMode === 'profile' && !!resolvedProfileSections && resolvedProfileSections.length > 0)\n const gridColsClass = isSectionView\n ? (effectiveCollapsed ? 'lg:grid-cols-[80px_240px_1fr]' : 'lg:grid-cols-[240px_240px_1fr]')\n : (effectiveCollapsed ? 'lg:grid-cols-[80px_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 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\n className={`relative min-h-svh lg:grid transition-[grid-template-columns] duration-200 ease-out ${gridColsClass}`}\n style={{ '--topbar-height': '61px' } as React.CSSProperties}\n >\n {/* Desktop sidebar collapse/expand toggle \u2014 sits on the divider line between\n sidebar and content, like Notion/Vercel. Hidden on mobile (hamburger in\n topbar handles the drawer). */}\n <button\n type=\"button\"\n onClick={() => setCollapsed((c) => !c)}\n aria-label={t('appShell.toggleSidebar')}\n className=\"hidden lg:flex fixed top-4 z-dropdown size-7 items-center justify-center rounded-md border bg-background text-muted-foreground shadow-sm transition-all hover:text-foreground hover:bg-muted focus:outline-none focus-visible:shadow-focus\"\n style={{ left: `calc(${asideWidth} - 14px)` }}\n >\n {effectiveCollapsed ? <PanelLeftOpen className=\"size-4\" /> : <PanelLeftClose className=\"size-4\" />}\n </button>\n {/* Desktop main sidebar */}\n <aside ref={sidebarAsideRef} className={`${asideClassesBase} ${effectiveCollapsed ? 'px-2' : 'px-3'} hidden lg:block lg:sticky lg:top-0 lg:h-svh lg:self-start lg:overflow-hidden lg:relative transition-[width,padding] duration-200 ease-out`} style={{ width: asideWidth }}>\n {renderSidebar(effectiveCollapsed, false, isSectionView)}\n {/* Scroll affordance \u2014 gradient fade + clickable chevron that flips up when\n the user reaches the bottom and disappears when nothing is scrollable\n (#1803). Clicking the chevron scrolls the inner sidebar container to\n top/bottom (`prefers-reduced-motion: reduce` collapses to instant\n scrolling). The wrapper is `pointer-events-none` so the gradient fade\n doesn't block hover/click on the rendered nav items behind it; the\n IconButton restores `pointer-events-auto` so it stays interactive. */}\n {sidebarScrollState !== 'none' ? (\n <div\n className=\"pointer-events-none absolute inset-x-0 bottom-0 flex h-10 items-end justify-center bg-gradient-to-t from-background via-background/80 to-transparent pb-1.5\"\n >\n {/* The IconButton owns hover/focus affordance; the inner span owns the\n rotate transition so it doesn't fight with the animate-bounce\n keyframes (both target `transform`). */}\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n data-testid=\"sidebar-scroll-chevron\"\n data-sidebar-scroll-chevron={sidebarScrollState}\n aria-label={\n sidebarScrollState === 'up'\n ? t('ui.sidebar.chevron.scrollTop', 'Scroll to top')\n : t('ui.sidebar.chevron.scrollBottom', 'Scroll to bottom')\n }\n className=\"pointer-events-auto text-muted-foreground/70 hover:text-foreground\"\n onClick={() => handleSidebarChevronScroll(sidebarScrollState === 'up' ? 'top' : 'bottom')}\n >\n <span\n className={`inline-flex transition-transform duration-300 ${sidebarScrollState === 'up' ? 'rotate-180' : ''}`}\n >\n <ChevronDown className=\"size-4 animate-bounce\" />\n </span>\n </IconButton>\n </div>\n ) : null}\n </aside>\n\n {/* Desktop section sidebar (Option B two-level) \u2014 sits beside the main sidebar\n when the user is on settings/profile routes. Mobile drawer keeps the\n original swap behavior to fit the narrow width. */}\n {isSectionView ? (\n <aside\n className={`${asideClassesBase} px-3 hidden lg:block lg:sticky lg:top-0 lg:h-svh lg:self-start lg:overflow-hidden lg:relative`}\n style={{ width: '240px' }}\n data-testid=\"appshell-section-sidebar\"\n >\n {renderSectionAside()}\n {/* Static bottom fade \u2014 covers the native iOS scroll indicator and signals\n that the section list is scrollable. Same look as the main sidebar's\n affordance but without the chevron / scroll-state machinery. */}\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-x-0 bottom-0 h-10 bg-gradient-to-t from-background via-background/80 to-transparent\"\n />\n </aside>\n ) : null}\n\n <div className=\"flex min-h-svh flex-col min-w-0\">\n <header className=\"sticky top-0 z-sticky border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 px-3 sm:px-4 lg:px-6 py-3 flex items-center justify-between gap-2 sm:gap-3\">\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=\"ghost\" 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 {/* 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 if (items.length === 0) return null\n const home = items[0]\n const current = items.length > 1 ? items[items.length - 1] : null\n const mid = items.slice(1, -1)\n const hasMid = mid.length > 0\n return (\n <BreadcrumbNav divider=\"arrow\" className=\"ml-2 lg:ml-3 text-sm\">\n <BreadcrumbList className=\"[&_[data-slot=breadcrumb-separator]_svg]:size-4\">\n <BreadcrumbItem>\n {home.href && current ? (\n <BreadcrumbLink asChild aria-label={home.label}>\n <Link href={home.href}>\n <Home className=\"size-4\" aria-hidden=\"true\" />\n </Link>\n </BreadcrumbLink>\n ) : (\n <BreadcrumbPage aria-label={home.label}>\n <Home className=\"size-4\" aria-hidden=\"true\" />\n </BreadcrumbPage>\n )}\n </BreadcrumbItem>\n {current ? (\n <>\n {hasMid ? (\n <>\n <BreadcrumbSeparator className=\"md:hidden\" />\n <BreadcrumbItem className=\"md:hidden\">\n <BreadcrumbEllipsis aria-label={t('appShell.breadcrumb.collapsed', { count: mid.length })} />\n </BreadcrumbItem>\n {mid.map((b, i) => (\n <React.Fragment key={`mid-${i}`}>\n <BreadcrumbSeparator className=\"hidden md:inline-flex\" />\n <BreadcrumbItem className=\"hidden md:inline-flex\">\n {b.href ? (\n <BreadcrumbLink asChild title={b.label}>\n <Link href={b.href}>{b.label}</Link>\n </BreadcrumbLink>\n ) : (\n <BreadcrumbLink title={b.label} aria-disabled=\"true\" tabIndex={-1}>\n {b.label}\n </BreadcrumbLink>\n )}\n </BreadcrumbItem>\n </React.Fragment>\n ))}\n </>\n ) : null}\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage title={current.label}>{current.label}</BreadcrumbPage>\n </BreadcrumbItem>\n </>\n ) : null}\n </BreadcrumbList>\n </BreadcrumbNav>\n )\n })()}\n </div>\n <div className=\"flex items-center gap-1.5 sm:gap-2 md:gap-3 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 <AiAssistantLauncher variant=\"topbar\" />\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-sticky\" completedAutoHideMs={progressCompletedAutoHideMs} />\n <main className=\"flex-1 p-4 lg:p-6 mx-auto w-full max-w-screen-2xl\">\n <InjectionSpot spotId={BACKEND_LAYOUT_TOP_INJECTION_SPOT_ID} context={injectionContext} />\n <FlashMessages />\n <PartialIndexBanner />\n {canManageUpgradeActions ? <UpgradeActionBanner /> : null}\n <LastOperationBanner />\n <RecordConflictBanner />\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/80 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-modal\">\n <div className=\"absolute inset-0 bg-black/50 backdrop-blur-sm\" onClick={() => setMobileOpen(false)} aria-hidden=\"true\" />\n <aside className=\"absolute left-0 top-0 flex h-full w-[280px] max-w-[85vw] flex-col bg-background border-r shadow-lg overflow-hidden\">\n <div className=\"shrink-0 flex items-center justify-between gap-2 border-b px-4 py-3\">\n <Link href=\"/backend\" className=\"flex items-center gap-2 min-w-0 text-sm font-semibold\" onClick={() => setMobileOpen(false)} aria-label={t('appShell.goToDashboard')}>\n <Image src={resolvedLogo?.src ?? \"/open-mercato.svg\"} alt={resolvedLogo?.alt ?? resolvedBrandName} width={28} height={28} className=\"rounded shrink-0\" unoptimized={resolvedLogoBypassesOptimization ? true : undefined} />\n <span className=\"truncate\">{resolvedBrandName}</span>\n </Link>\n <IconButton variant=\"ghost\" size=\"sm\" onClick={() => setMobileOpen(false)} aria-label={t('appShell.closeMenu')}>\n <X className=\"size-4\" />\n </IconButton>\n </div>\n {mobileSidebarSlot && (\n <div className=\"shrink-0 border-b px-3 py-2\">\n {mobileSidebarSlot}\n </div>\n )}\n {sidebarMode !== 'main' ? (\n <div className=\"shrink-0 flex items-center gap-5 border-b px-4 pt-3 pb-0\" role=\"tablist\">\n {([\n { id: 'main' as const, label: t('backend.nav.main', 'Main') },\n {\n id: 'section' as const,\n label:\n sidebarMode === 'settings'\n ? settingsSectionTitle ?? t('backend.nav.settings', 'Settings')\n : profileSectionTitle ?? t('backend.nav.profile', 'Profile'),\n },\n ]).map((tab) => {\n const isActive =\n tab.id === 'main' ? mobileDrawerView === 'main' : mobileDrawerView === 'auto'\n const tabId = `mobile-drawer-tab-${tab.id}`\n return (\n <button\n key={tab.id}\n id={tabId}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n aria-controls=\"mobile-drawer-tabpanel\"\n onClick={() => setMobileDrawerView(tab.id === 'main' ? 'main' : 'auto')}\n className=\"relative inline-flex items-center pb-2 text-sm font-medium leading-5 tracking-tight transition-colors focus:outline-none data-[active=true]:text-foreground data-[active=false]:text-muted-foreground hover:text-foreground\"\n data-active={isActive}\n >\n <span>{tab.label}</span>\n {isActive ? (\n <span\n className=\"absolute -bottom-px left-0 right-0 h-0.5 bg-foreground\"\n aria-hidden=\"true\"\n />\n ) : null}\n </button>\n )\n })}\n </div>\n ) : null}\n <div\n id=\"mobile-drawer-tabpanel\"\n role={sidebarMode !== 'main' ? 'tabpanel' : undefined}\n aria-labelledby={\n sidebarMode !== 'main'\n ? `mobile-drawer-tab-${mobileDrawerView === 'main' ? 'main' : 'section'}`\n : undefined\n }\n className=\"min-h-0 flex-1 overflow-y-auto overflow-x-hidden p-3\"\n >\n {/* Force expanded sidebar in mobile drawer, hide its header and collapse toggle */}\n {renderSidebar(false, true, mobileDrawerView === 'main')}\n </div>\n </aside>\n </div>\n )}\n </div>\n <UmesDevToolsPanel />\n </HeaderContext.Provider>\n )\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 { ChevronDown, ChevronLeft, Home, PanelLeftClose, PanelLeftOpen, Search, X } from 'lucide-react'\nimport { Button } from '../primitives/button'\nimport {\n Breadcrumb as BreadcrumbNav,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from '../primitives/breadcrumb'\nimport { IconButton } from '../primitives/icon-button'\nimport { Input } from '../primitives/input'\nimport { SearchInput } from '../primitives/search-input'\nimport { Checkbox } from '../primitives/checkbox'\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 { RecordConflictBanner } from './conflicts/RecordConflictBanner'\nimport { dismissRecordConflict } from './conflicts/store'\nimport { ProgressTopBar } from './progress/ProgressTopBar'\nimport { UpgradeActionBanner } from './upgrades/UpgradeActionBanner'\nimport { PartialIndexBanner } from './indexes/PartialIndexBanner'\nimport { OrganizationScopeBoundary } from './OrganizationScopeBoundary'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { slugifySidebarId } from '@open-mercato/shared/modules/navigation/sidebarPreferences'\nimport { readVersionedPreference, writeVersionedPreference } from '@open-mercato/shared/lib/browser/versionedPreference'\nimport { cloneSidebarGroups } from './sidebar/customization-helpers'\nimport type { SectionNavGroup } from './section-page/types'\nimport { InjectionSpot } from './injection/InjectionSpot'\nimport {\n BackendRecordInjectionContextProvider,\n type RecordInjectionContext,\n} from './injection/recordContext'\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 { AiDockProvider } from '../ai/AiDock'\nimport { AiChatSessionsProvider } from '../ai/AiChatSessions'\nimport { AiAssistantLauncher } from '../ai/AiAssistantLauncher'\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\n// Versioned-envelope discriminator for the persisted sidebar open/closed group\n// map. This is a structured value (a record), so it carries a version so future\n// shape changes can migrate or safely discard stale data; legacy bare\n// `Record<string, boolean>` values are migrated forward on the next write. The\n// neighbouring `om:sidebarCollapsed` / `om:progress:expanded` flags are trivial\n// scalar booleans and deliberately stay raw (see their write sites). See\n// `@open-mercato/shared/lib/browser/versionedPreference`.\nconst SIDEBAR_OPEN_GROUPS_KEY = 'om:sidebarOpenGroups'\nconst SIDEBAR_OPEN_GROUPS_VERSION = 1\n\nfunction isBooleanRecord(value: unknown): value is Record<string, boolean> {\n return (\n !!value &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n Object.values(value as Record<string, unknown>).every((entry) => typeof entry === 'boolean')\n )\n}\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 canManageUpgradeActions?: boolean\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 * How long (ms) to keep successfully completed progress operations visible\n * before auto-hiding. Pass `false` or `0` to disable. Defaults to 10 000 ms.\n */\n progressCompletedAutoHideMs?: number | false\n}\n\ntype Breadcrumb = Array<{ label: string; href?: string }>\n\ntype SidebarGroup = AppShellProps['groups'][number]\ntype SidebarItem = SidebarGroup['items'][number]\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 shouldBypassLogoOptimization(src?: string | null): boolean {\n const value = src ?? ''\n return /^https?:\\/\\//.test(value) || /^\\/api\\/attachments\\/(?:image|file)\\//.test(value)\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 <AiChatSessionsProvider>\n <AiDockProvider>\n <AppShellBody {...props} />\n </AiDockProvider>\n </AiChatSessionsProvider>\n </BackendChromeProvider>\n </QueryProvider>\n )\n}\n\nfunction AppShellBody({ productName, logo, email, canManageUpgradeActions = false, groups, rightHeaderSlot, children, sidebarCollapsedDefault = false, currentTitle, breadcrumb, version, settingsSectionTitle, settingsPathPrefixes = [], settingsSections, profileSections, profileSectionTitle, profilePathPrefixes = [], mobileSidebarSlot, progressCompletedAutoHideMs }: 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 () => cloneSidebarGroups(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 resolvedLogo = chromePayload?.brand?.logo?.src ? chromePayload.brand.logo : logo\n const resolvedBrandName = chromePayload?.brand?.logo?.src\n ? chromePayload.brand.name ?? resolvedProductName\n : resolvedProductName\n const resolvedLogoBypassesOptimization = shouldBypassLogoOptimization(resolvedLogo?.src)\n const [mobileOpen, setMobileOpen] = React.useState(false)\n // When the mobile drawer opens on a settings/profile route, it follows the\n // section sidebar by default. Set to 'main' to force-show the main nav even\n // when the route is in a section context. Reset on close.\n const [mobileDrawerView, setMobileDrawerView] = React.useState<'auto' | 'main'>('auto')\n // Clear the persistent record-conflict bar when the route changes. The\n // conflict is scoped to the record the user was editing, so navigating to an\n // unrelated page should dismiss it instead of carrying a stale \"Record\n // changed\" bar across modules.\n React.useEffect(() => {\n dismissRecordConflict()\n }, [pathname])\n React.useEffect(() => {\n if (!mobileOpen) setMobileDrawerView('auto')\n }, [mobileOpen])\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 [headerTitle, setHeaderTitle] = React.useState<string | undefined>(currentTitle)\n const [headerBreadcrumb, setHeaderBreadcrumb] = React.useState<Breadcrumb | undefined>(breadcrumb)\n const [navQuery, setNavQuery] = React.useState('')\n const navQueryNorm = navQuery.trim().toLowerCase()\n const navQueryActive = navQueryNorm.length > 0\n const matchesQuery = React.useCallback((label: string | undefined) => {\n if (!navQueryActive) return true\n if (!label) return false\n return label.toLowerCase().includes(navQueryNorm)\n }, [navQueryActive, navQueryNorm])\n const effectiveCollapsed = collapsed\n const expandedSidebarWidth = '240px'\n\n // Track scroll position of the desktop sidebar's inner scroll container so we can\n // flip the affordance chevron between down/up (and hide it entirely when content\n // fits without scrolling). The inner div is rendered deep in renderSidebar /\n // renderSectionSidebar \u2014 we tag it with `data-sidebar-scroll=\"true\"` and look it\n // up via the aside ref so we don't have to thread refs through the JSX tree.\n const sidebarAsideRef = React.useRef<HTMLElement>(null)\n const [sidebarScrollState, setSidebarScrollState] = React.useState<'down' | 'up' | 'none'>('down')\n const sidebarScrollIntentRef = React.useRef<'top' | 'bottom' | null>(null)\n\n // Click-to-scroll handler for the sidebar affordance chevron (#1803). Resolves the\n // scroll target lazily through the aside ref so we don't have to thread refs into\n // renderSidebar; respects `prefers-reduced-motion` by falling back to instant\n // scrolling when the user has opted out of smooth motion.\n const handleSidebarChevronScroll = React.useCallback((target: 'top' | 'bottom') => {\n const aside = sidebarAsideRef.current\n if (!aside) return\n const scrollTarget = aside.querySelector<HTMLElement>('[data-sidebar-scroll=\"true\"]')\n if (!scrollTarget) return\n const prefersReducedMotion =\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches\n const behavior: ScrollBehavior = prefersReducedMotion ? 'auto' : 'smooth'\n const maxScrollTop = Math.max(0, scrollTarget.scrollHeight - scrollTarget.clientHeight)\n if (maxScrollTop <= 1) {\n sidebarScrollIntentRef.current = null\n setSidebarScrollState('none')\n return\n }\n sidebarScrollIntentRef.current = target\n setSidebarScrollState(target === 'bottom' ? 'up' : 'down')\n scrollTarget.scrollTo({\n top: target === 'top' ? 0 : maxScrollTop,\n behavior,\n })\n }, [])\n React.useEffect(() => {\n const aside = sidebarAsideRef.current\n if (!aside) return\n const target = aside.querySelector<HTMLElement>('[data-sidebar-scroll=\"true\"]')\n if (!target) return\n const update = () => {\n const { scrollTop, scrollHeight, clientHeight } = target\n const canScroll = scrollHeight > clientHeight + 1\n if (!canScroll) {\n sidebarScrollIntentRef.current = null\n setSidebarScrollState('none')\n return\n }\n const maxScrollTop = Math.max(0, scrollHeight - clientHeight)\n const atTop = scrollTop <= 8\n const atBottom = scrollTop >= maxScrollTop - 8\n const scrollIntent = sidebarScrollIntentRef.current\n if (scrollIntent === 'bottom') {\n if (atBottom) sidebarScrollIntentRef.current = null\n setSidebarScrollState('up')\n return\n }\n if (scrollIntent === 'top') {\n if (atTop) sidebarScrollIntentRef.current = null\n setSidebarScrollState('down')\n return\n }\n setSidebarScrollState(atBottom ? 'up' : 'down')\n }\n update()\n target.addEventListener('scroll', update, { passive: true })\n const ro = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(update) : null\n ro?.observe(target)\n return () => {\n target.removeEventListener('scroll', update)\n ro?.disconnect()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pathname, effectiveCollapsed])\n const injectionContext = React.useMemo(\n () => ({\n path: pathname ?? '',\n query: searchParams?.toString() ?? '',\n }),\n [pathname, searchParams],\n )\n\n // AppShell-owned transport for the current detail record (Phase 0 / S2).\n // Detail pages publish here; the merged context feeds the global\n // `backend:record:current` mount so the record_locks widget can resolve the\n // resource without a hardcoded path allowlist. Stale context (published for a\n // different path) is ignored so it never leaks across route transitions.\n const [currentRecordInjectionContext, setCurrentRecordInjectionContext] =\n React.useState<RecordInjectionContext | null>(null)\n\n const recordInjectionContext = React.useMemo(() => {\n if (!currentRecordInjectionContext) return injectionContext\n const publishedPath = currentRecordInjectionContext.path\n if (publishedPath && pathname && publishedPath !== pathname) return injectionContext\n return { ...injectionContext, ...currentRecordInjectionContext }\n }, [injectionContext, currentRecordInjectionContext, pathname])\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 const parsed = readVersionedPreference<Record<string, boolean>>(\n SIDEBAR_OPEN_GROUPS_KEY,\n SIDEBAR_OPEN_GROUPS_VERSION,\n isBooleanRecord,\n {},\n { legacyIsValid: isBooleanRecord },\n )\n if (Object.keys(parsed).length === 0) return\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 }, [resolvedGroups])\n\n const toggleGroup = (groupId: string) => setOpenGroups((prev) => ({ ...prev, [groupId]: prev[groupId] === false }))\n\n const asideWidth = effectiveCollapsed ? '80px' : 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 py-4`;\n\n // Persist collapse state to localStorage and cookie. Both writes can throw in\n // private/incognito mode (storage blocked) or when cookies are disabled \u2014\n // the persisted preference is purely a UX nice-to-have, never functional, so\n // swallow the failure and let the component fall back to the default state.\n // This is a trivial scalar flag ('1' | '0') with no schema to evolve, so it is\n // intentionally kept raw rather than wrapped in a versioned envelope (the\n // versioning threshold lives in `@open-mercato/shared/lib/browser/versionedPreference`).\n React.useEffect(() => {\n try { localStorage.setItem('om:sidebarCollapsed', collapsed ? '1' : '0') } catch { /* localStorage blocked (private mode) \u2014 non-critical */ }\n try {\n document.cookie = `om_sidebar_collapsed=${collapsed ? '1' : '0'}; path=/; max-age=31536000; samesite=lax`\n } catch { /* cookies disabled \u2014 non-critical */ }\n }, [collapsed])\n\n // Two-level sidebar (Option B): when entering settings/profile mode, force the\n // main sidebar to collapsed (icons only) so the section sub-nav can sit beside\n // it; restore the user's previous expansion when returning to the main mode.\n // Initial ref is 'main' so direct mounts on /backend/settings also auto-collapse.\n const collapsedBeforeSectionRef = React.useRef<boolean | null>(null)\n const previousSidebarModeRef = React.useRef<'main' | 'settings' | 'profile'>('main')\n React.useEffect(() => {\n const previous = previousSidebarModeRef.current\n if (previous === 'main' && sidebarMode !== 'main') {\n collapsedBeforeSectionRef.current = collapsed\n if (!collapsed) setCollapsed(true)\n } else if (previous !== 'main' && sidebarMode === 'main' && collapsedBeforeSectionRef.current !== null) {\n const restoreTo = collapsedBeforeSectionRef.current\n collapsedBeforeSectionRef.current = null\n if (collapsed !== restoreTo) setCollapsed(restoreTo)\n }\n previousSidebarModeRef.current = sidebarMode\n }, [sidebarMode, collapsed])\n React.useEffect(() => {\n writeVersionedPreference(SIDEBAR_OPEN_GROUPS_KEY, SIDEBAR_OPEN_GROUPS_VERSION, openGroups)\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 setNavGroups(cloneSidebarGroups(resolvedGroups))\n }, [resolvedGroups])\n\n function renderSectionSidebar(\n sections: SectionNavGroup[],\n title: string,\n compact: boolean,\n hideHeader?: boolean,\n hideSearch?: 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 h-full flex-col gap-3\">\n {!hideHeader && (\n <div className=\"mb-2\">\n <Link\n href=\"/backend\"\n className={`flex items-center gap-3 rounded-xl transition-colors hover:bg-muted ${compact ? 'p-2 justify-center' : 'p-3'}`}\n aria-label={t('appShell.goToDashboard')}\n >\n <Image src={resolvedLogo?.src ?? \"/open-mercato.svg\"} alt={resolvedLogo?.alt ?? resolvedBrandName} width={40} height={40} className=\"rounded-full shrink-0\" unoptimized={resolvedLogoBypassesOptimization ? true : undefined} />\n {!compact && <span className=\"truncate text-sm font-medium text-foreground\">{resolvedBrandName}</span>}\n </Link>\n </div>\n )}\n {!compact && !hideSearch && (\n <SearchInput\n value={navQuery}\n onChange={setNavQuery}\n placeholder={t('appShell.searchNavPlaceholder', 'Search...')}\n aria-label={t('appShell.searchNavAria', 'Search navigation')}\n clearLabel={t('appShell.searchNavClear', 'Clear search')}\n className=\"mb-2\"\n />\n )}\n <div data-sidebar-scroll=\"true\" className={`flex flex-1 flex-col gap-3 overflow-y-auto scrollbar-hide pr-1 ${compact ? '-ml-2 pl-2' : '-ml-3 pl-3'}`}>\n <nav className=\"flex flex-col gap-2\">\n {sortedSections.map((section, sectionIndex) => {\n const sectionNavQueryActive = hideSearch ? false : navQueryActive\n const matchesItemQuery = (item: typeof section.items[number]): boolean => {\n if (!sectionNavQueryActive) return true\n const label = item.labelKey ? t(item.labelKey, item.label) : item.label\n if (matchesQuery(label)) return true\n return Array.isArray(item.children) && item.children.some(matchesItemQuery)\n }\n const visibleItems = sectionNavQueryActive\n ? section.items.filter(matchesItemQuery)\n : 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 const filterChildren = (children: typeof section.items | undefined) => {\n if (!children) return [] as typeof section.items\n if (!sectionNavQueryActive) return [...children]\n return children.filter(matchesItemQuery)\n }\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(filterChildren(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 || sectionNavQueryActive)\n const isActive = isOnItemBranch || hasActiveChild\n const base = compact ? 'w-10 h-10 justify-center' : 'w-full py-2 gap-2'\n const spacingStyle = !compact\n ? {\n paddingLeft: `${12 + depth * 16}px`,\n paddingRight: '12px',\n }\n : undefined\n\n return (\n <React.Fragment key={item.id}>\n <Link\n href={item.href}\n className={`relative text-sm font-medium rounded-lg inline-flex items-center ${base} ${\n isActive\n ? 'bg-muted text-foreground'\n : 'text-muted-foreground hover:bg-muted'\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 aria-hidden className={`absolute ${compact ? 'left-[-20px]' : 'left-[-12px]'} top-2 w-1 h-5 rounded-r bg-foreground`} />\n )}\n <span className=\"flex items-center justify-center shrink-0\">\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 {!compact && (\n <Button\n variant=\"muted\"\n onClick={() => toggleGroup(sectionKey)}\n className=\"w-full px-1 justify-between flex text-xs font-medium uppercase tracking-wider text-muted-foreground/70 py-1\"\n aria-expanded={open}\n >\n <span>{sectionLabel}</span>\n <Chevron open={open} />\n </Button>\n )}\n {(open || compact) && (\n <div className={`flex flex-col ${compact ? 'items-center' : ''} gap-1`}>\n {sortedItems.map((item) => renderSectionItem(item))}\n </div>\n )}\n {sectionIndex !== lastVisibleIndex && <div className={`my-2 border-t ${compact ? '-ml-2 -mr-3' : '-ml-3 -mr-4'}`} />}\n </div>\n )\n })}\n </nav>\n </div>\n </div>\n )\n }\n\n function renderSidebar(compact: boolean, hideHeader?: boolean, forceMainOnly?: boolean) {\n if (!isChromeReady && isChromeLoading) {\n return (\n <div className=\"flex flex-col min-h-full gap-3\" data-testid=\"backend-chrome-loading\">\n {!hideHeader ? (\n <div className=\"mb-2\">\n <Link\n href=\"/backend\"\n className={`flex items-center gap-3 rounded-xl transition-colors hover:bg-muted ${compact ? 'p-2 justify-center' : 'p-3'}`}\n aria-label={t('appShell.goToDashboard')}\n >\n <Image src={resolvedLogo?.src ?? \"/open-mercato.svg\"} alt={resolvedLogo?.alt ?? resolvedBrandName} width={40} height={40} className=\"rounded-full shrink-0\" unoptimized={resolvedLogoBypassesOptimization ? true : undefined} />\n {!compact && <span className=\"truncate text-sm font-medium text-foreground\">{resolvedBrandName}</span>}\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/50\" />\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/50\" />\n <div className=\"h-8 rounded bg-muted/50\" />\n </div>\n </div>\n <div className=\"space-y-3\">\n <div className=\"h-8 rounded bg-muted/50\" />\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/50\" />\n </div>\n </div>\n </div>\n </div>\n )\n }\n\n if (!forceMainOnly && 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 (!forceMainOnly && 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\n return (\n <div className=\"flex h-full flex-col gap-3\">\n {!hideHeader && (\n <div className=\"mb-2\">\n <Link\n href=\"/backend\"\n className={`flex items-center gap-3 rounded-xl transition-colors hover:bg-muted ${compact ? 'p-2 justify-center' : 'p-3'}`}\n aria-label={t('appShell.goToDashboard')}\n >\n <Image src={resolvedLogo?.src ?? \"/open-mercato.svg\"} alt={resolvedLogo?.alt ?? resolvedBrandName} width={40} height={40} className=\"rounded-full shrink-0\" unoptimized={resolvedLogoBypassesOptimization ? true : undefined} />\n {!compact && <span className=\"truncate text-sm font-medium text-foreground\">{resolvedBrandName}</span>}\n </Link>\n </div>\n )}\n {shouldRenderSidebarInjectionSpots ? (\n <InjectionSpot\n spotId={BACKEND_SIDEBAR_TOP_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n {!compact && (\n <SearchInput\n value={navQuery}\n onChange={setNavQuery}\n placeholder={t('appShell.searchNavPlaceholder', 'Search...')}\n aria-label={t('appShell.searchNavAria', 'Search navigation')}\n clearLabel={t('appShell.searchNavClear', 'Clear search')}\n className=\"mb-2\"\n />\n )}\n <div data-sidebar-scroll=\"true\" className={`flex flex-1 flex-col gap-3 overflow-y-auto scrollbar-hide pr-1 ${compact ? '-ml-2 pl-2' : '-ml-3 pl-3'}`}>\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 = navQueryActive ? true : openGroups[groupId] !== false\n const visibleItems = g.items.filter((item) => {\n if (item.hidden === true) return false\n if (!navQueryActive) return true\n if (matchesQuery(item.title)) return true\n const itemChildren = (item.children ?? []).filter((c) => c.hidden !== true)\n return itemChildren.some((c) => matchesQuery(c.title))\n })\n if (visibleItems.length === 0) return null\n return (\n <div key={groupId}>\n {!compact && (\n <Button\n variant=\"muted\"\n onClick={() => toggleGroup(groupId)}\n className=\"w-full px-1 justify-between flex text-xs font-medium uppercase tracking-wider text-muted-foreground/70 py-1\"\n aria-expanded={open}\n >\n <span>{g.name}</span>\n <Chevron open={open} />\n </Button>\n )}\n {(open || compact) && (\n <div className={`flex flex-col ${compact ? 'items-center' : ''} gap-1`}>\n {visibleItems.map((i) => {\n const allChildItems = (i.children ?? []).filter((child) => child.hidden !== true)\n const matchingChildItems = navQueryActive\n ? allChildItems.filter((c) => matchesQuery(c.title))\n : allChildItems\n const childItems = navQueryActive ? matchingChildItems : allChildItems\n const showChildren = navQueryActive\n ? matchingChildItems.length > 0\n : (!!pathname && allChildItems.length > 0 && pathname.startsWith(i.href))\n const hasActiveChild = !!(pathname && allChildItems.some((c) => pathname.startsWith(c.href)))\n const isParentActive = (pathname === i.href) || (!navQueryActive && showChildren && !hasActiveChild)\n const base = compact ? 'w-10 h-10 justify-center' : 'w-full px-3 py-2 gap-2'\n return (\n <React.Fragment key={i.href}>\n <Link\n href={i.href}\n className={`relative text-sm font-medium rounded-lg inline-flex items-center ${base} ${\n isParentActive ? 'bg-muted text-foreground' : 'text-muted-foreground hover:bg-muted'\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 aria-hidden className={`absolute ${compact ? 'left-[-20px]' : 'left-[-12px]'} top-2 w-1 h-5 rounded-r bg-foreground`} />\n ) : null}\n <span className=\"flex items-center justify-center shrink-0\">\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={`relative flex flex-col ${compact ? 'items-center' : ''} gap-1`}>\n {!compact && (\n <span aria-hidden className=\"pointer-events-none absolute left-1.5 top-1 bottom-1 w-px bg-border\" />\n )}\n {childItems.map((c) => {\n const childActive = pathname?.startsWith(c.href)\n const childBase = compact ? 'w-10 h-8 justify-center' : 'w-full pl-5 pr-3 py-2 gap-2'\n return (\n <Link\n key={c.href}\n href={c.href}\n className={`relative text-sm font-medium rounded-lg inline-flex items-center ${childBase} ${\n childActive ? 'bg-muted text-foreground' : 'text-muted-foreground hover:bg-muted'\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 aria-hidden className={`absolute ${compact ? 'left-[-20px]' : 'left-[-12px]'} top-2 w-1 h-5 rounded-r bg-foreground`} />\n ) : null}\n <span className=\"flex items-center justify-center shrink-0\">\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 ${compact ? '-ml-2 -mr-3' : '-ml-3 -mr-4'}`} />}\n </div>\n )\n })}\n </nav>\n </>\n )\n })()}\n </div>\n <div className=\"sticky bottom-0 bg-background pb-1\">\n {shouldRenderSidebarInjectionSpots ? (\n <InjectionSpot\n spotId={BACKEND_SIDEBAR_NAV_FOOTER_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\n {shouldRenderSidebarInjectionSpots ? (\n <StatusBadgeInjectionSpot\n spotId={GLOBAL_SIDEBAR_STATUS_BADGES_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n ) : null}\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 function renderSectionAside() {\n let sections: SectionNavGroup[] | null = null\n let title = ''\n if (sidebarMode === 'settings' && resolvedSettingsSections && resolvedSettingsSections.length > 0) {\n sections = mergeSectionGroupsWithInjected(\n resolvedSettingsSections,\n settingsSidebarInjectedMenuItems,\n t,\n )\n title = settingsSectionTitle ?? t('backend.nav.settings', 'Settings')\n } else if (sidebarMode === 'profile' && resolvedProfileSections && resolvedProfileSections.length > 0) {\n sections = mergeSectionGroupsWithInjected(\n resolvedProfileSections,\n profileSidebarInjectedMenuItems,\n t,\n )\n title = profileSectionTitle ?? t('backend.nav.profile', 'Profile')\n }\n if (!sections) return null\n return (\n <div className=\"flex h-full flex-col gap-2\">\n <Link\n href=\"/backend\"\n className=\"inline-flex items-center gap-2 rounded-lg px-2 py-2 text-sm font-semibold text-foreground transition-colors hover:bg-muted\"\n data-testid=\"appshell-section-back-to-main\"\n aria-label={t('backend.nav.backToMain', 'Back to Main')}\n >\n <ChevronLeft className=\"size-4 shrink-0\" aria-hidden />\n <span className=\"truncate\">{title}</span>\n </Link>\n <div className=\"min-h-0 flex-1\">\n {renderSectionSidebar(sections, title, false, true, true)}\n </div>\n </div>\n )\n }\n\n const isSectionView =\n (sidebarMode === 'settings' && !!resolvedSettingsSections && resolvedSettingsSections.length > 0) ||\n (sidebarMode === 'profile' && !!resolvedProfileSections && resolvedProfileSections.length > 0)\n const gridColsClass = isSectionView\n ? (effectiveCollapsed ? 'lg:grid-cols-[80px_240px_1fr]' : 'lg:grid-cols-[240px_240px_1fr]')\n : (effectiveCollapsed ? 'lg:grid-cols-[80px_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 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\n className={`relative min-h-svh lg:grid transition-[grid-template-columns] duration-200 ease-out ${gridColsClass}`}\n style={{ '--topbar-height': '61px' } as React.CSSProperties}\n >\n {/* Desktop sidebar collapse/expand toggle \u2014 sits on the divider line between\n sidebar and content, like Notion/Vercel. Hidden on mobile (hamburger in\n topbar handles the drawer). */}\n <button\n type=\"button\"\n onClick={() => setCollapsed((c) => !c)}\n aria-label={t('appShell.toggleSidebar')}\n className=\"hidden lg:flex fixed top-4 z-dropdown size-7 items-center justify-center rounded-md border bg-background text-muted-foreground shadow-sm transition-all hover:text-foreground hover:bg-muted focus:outline-none focus-visible:shadow-focus\"\n style={{ left: `calc(${asideWidth} - 14px)` }}\n >\n {effectiveCollapsed ? <PanelLeftOpen className=\"size-4\" /> : <PanelLeftClose className=\"size-4\" />}\n </button>\n {/* Desktop main sidebar */}\n <aside ref={sidebarAsideRef} className={`${asideClassesBase} ${effectiveCollapsed ? 'px-2' : 'px-3'} hidden lg:block lg:sticky lg:top-0 lg:h-svh lg:self-start lg:overflow-hidden lg:relative transition-[width,padding] duration-200 ease-out`} style={{ width: asideWidth }}>\n {renderSidebar(effectiveCollapsed, false, isSectionView)}\n {/* Scroll affordance \u2014 gradient fade + clickable chevron that flips up when\n the user reaches the bottom and disappears when nothing is scrollable\n (#1803). Clicking the chevron scrolls the inner sidebar container to\n top/bottom (`prefers-reduced-motion: reduce` collapses to instant\n scrolling). The wrapper is `pointer-events-none` so the gradient fade\n doesn't block hover/click on the rendered nav items behind it; the\n IconButton restores `pointer-events-auto` so it stays interactive. */}\n {sidebarScrollState !== 'none' ? (\n <div\n className=\"pointer-events-none absolute inset-x-0 bottom-0 flex h-10 items-end justify-center bg-gradient-to-t from-background via-background/80 to-transparent pb-1.5\"\n >\n {/* The IconButton owns hover/focus affordance; the inner span owns the\n rotate transition so it doesn't fight with the animate-bounce\n keyframes (both target `transform`). */}\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n data-testid=\"sidebar-scroll-chevron\"\n data-sidebar-scroll-chevron={sidebarScrollState}\n aria-label={\n sidebarScrollState === 'up'\n ? t('ui.sidebar.chevron.scrollTop', 'Scroll to top')\n : t('ui.sidebar.chevron.scrollBottom', 'Scroll to bottom')\n }\n className=\"pointer-events-auto text-muted-foreground/70 hover:text-foreground\"\n onClick={() => handleSidebarChevronScroll(sidebarScrollState === 'up' ? 'top' : 'bottom')}\n >\n <span\n className={`inline-flex transition-transform duration-300 ${sidebarScrollState === 'up' ? 'rotate-180' : ''}`}\n >\n <ChevronDown className=\"size-4 animate-bounce\" />\n </span>\n </IconButton>\n </div>\n ) : null}\n </aside>\n\n {/* Desktop section sidebar (Option B two-level) \u2014 sits beside the main sidebar\n when the user is on settings/profile routes. Mobile drawer keeps the\n original swap behavior to fit the narrow width. */}\n {isSectionView ? (\n <aside\n className={`${asideClassesBase} px-3 hidden lg:block lg:sticky lg:top-0 lg:h-svh lg:self-start lg:overflow-hidden lg:relative`}\n style={{ width: '240px' }}\n data-testid=\"appshell-section-sidebar\"\n >\n {renderSectionAside()}\n {/* Static bottom fade \u2014 covers the native iOS scroll indicator and signals\n that the section list is scrollable. Same look as the main sidebar's\n affordance but without the chevron / scroll-state machinery. */}\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-x-0 bottom-0 h-10 bg-gradient-to-t from-background via-background/80 to-transparent\"\n />\n </aside>\n ) : null}\n\n <div className=\"flex min-h-svh flex-col min-w-0\">\n <header className=\"sticky top-0 z-sticky border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 px-3 sm:px-4 lg:px-6 py-3 flex items-center justify-between gap-2 sm:gap-3\">\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=\"ghost\" 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 {/* 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 if (items.length === 0) return null\n const home = items[0]\n const current = items.length > 1 ? items[items.length - 1] : null\n const mid = items.slice(1, -1)\n const hasMid = mid.length > 0\n return (\n <BreadcrumbNav divider=\"arrow\" className=\"ml-2 lg:ml-3 text-sm\">\n <BreadcrumbList className=\"[&_[data-slot=breadcrumb-separator]_svg]:size-4\">\n <BreadcrumbItem>\n {home.href && current ? (\n <BreadcrumbLink asChild aria-label={home.label}>\n <Link href={home.href}>\n <Home className=\"size-4\" aria-hidden=\"true\" />\n </Link>\n </BreadcrumbLink>\n ) : (\n <BreadcrumbPage aria-label={home.label}>\n <Home className=\"size-4\" aria-hidden=\"true\" />\n </BreadcrumbPage>\n )}\n </BreadcrumbItem>\n {current ? (\n <>\n {hasMid ? (\n <>\n <BreadcrumbSeparator className=\"md:hidden\" />\n <BreadcrumbItem className=\"md:hidden\">\n <BreadcrumbEllipsis aria-label={t('appShell.breadcrumb.collapsed', { count: mid.length })} />\n </BreadcrumbItem>\n {mid.map((b, i) => (\n <React.Fragment key={`mid-${i}`}>\n <BreadcrumbSeparator className=\"hidden md:inline-flex\" />\n <BreadcrumbItem className=\"hidden md:inline-flex\">\n {b.href ? (\n <BreadcrumbLink asChild title={b.label}>\n <Link href={b.href}>{b.label}</Link>\n </BreadcrumbLink>\n ) : (\n <BreadcrumbLink title={b.label} aria-disabled=\"true\" tabIndex={-1}>\n {b.label}\n </BreadcrumbLink>\n )}\n </BreadcrumbItem>\n </React.Fragment>\n ))}\n </>\n ) : null}\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage title={current.label}>{current.label}</BreadcrumbPage>\n </BreadcrumbItem>\n </>\n ) : null}\n </BreadcrumbList>\n </BreadcrumbNav>\n )\n })()}\n </div>\n <div className=\"flex items-center gap-1.5 sm:gap-2 md:gap-3 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 <AiAssistantLauncher variant=\"topbar\" />\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-sticky\" completedAutoHideMs={progressCompletedAutoHideMs} />\n <main className=\"flex-1 p-4 lg:p-6 mx-auto w-full max-w-screen-2xl\">\n <InjectionSpot spotId={BACKEND_LAYOUT_TOP_INJECTION_SPOT_ID} context={injectionContext} />\n <FlashMessages />\n <PartialIndexBanner />\n {canManageUpgradeActions ? <UpgradeActionBanner /> : null}\n <LastOperationBanner />\n <RecordConflictBanner />\n <InjectionSpot spotId={BACKEND_RECORD_CURRENT_INJECTION_SPOT_ID} context={recordInjectionContext} />\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 <OrganizationScopeBoundary active={isOnSettingsPath}>\n <BackendRecordInjectionContextProvider setCurrentRecordInjectionContext={setCurrentRecordInjectionContext}>\n {children}\n </BackendRecordInjectionContextProvider>\n </OrganizationScopeBoundary>\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/80 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-modal\">\n <div className=\"absolute inset-0 bg-black/50 backdrop-blur-sm\" onClick={() => setMobileOpen(false)} aria-hidden=\"true\" />\n <aside className=\"absolute left-0 top-0 flex h-full w-[280px] max-w-[85vw] flex-col bg-background border-r shadow-lg overflow-hidden\">\n <div className=\"shrink-0 flex items-center justify-between gap-2 border-b px-4 py-3\">\n <Link href=\"/backend\" className=\"flex items-center gap-2 min-w-0 text-sm font-semibold\" onClick={() => setMobileOpen(false)} aria-label={t('appShell.goToDashboard')}>\n <Image src={resolvedLogo?.src ?? \"/open-mercato.svg\"} alt={resolvedLogo?.alt ?? resolvedBrandName} width={28} height={28} className=\"rounded shrink-0\" unoptimized={resolvedLogoBypassesOptimization ? true : undefined} />\n <span className=\"truncate\">{resolvedBrandName}</span>\n </Link>\n <IconButton variant=\"ghost\" size=\"sm\" onClick={() => setMobileOpen(false)} aria-label={t('appShell.closeMenu')}>\n <X className=\"size-4\" />\n </IconButton>\n </div>\n {mobileSidebarSlot && (\n <div className=\"shrink-0 border-b px-3 py-2\">\n {mobileSidebarSlot}\n </div>\n )}\n {sidebarMode !== 'main' ? (\n <div className=\"shrink-0 flex items-center gap-5 border-b px-4 pt-3 pb-0\" role=\"tablist\">\n {([\n { id: 'main' as const, label: t('backend.nav.main', 'Main') },\n {\n id: 'section' as const,\n label:\n sidebarMode === 'settings'\n ? settingsSectionTitle ?? t('backend.nav.settings', 'Settings')\n : profileSectionTitle ?? t('backend.nav.profile', 'Profile'),\n },\n ]).map((tab) => {\n const isActive =\n tab.id === 'main' ? mobileDrawerView === 'main' : mobileDrawerView === 'auto'\n const tabId = `mobile-drawer-tab-${tab.id}`\n return (\n <button\n key={tab.id}\n id={tabId}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n aria-controls=\"mobile-drawer-tabpanel\"\n onClick={() => setMobileDrawerView(tab.id === 'main' ? 'main' : 'auto')}\n className=\"relative inline-flex items-center pb-2 text-sm font-medium leading-5 tracking-tight transition-colors focus:outline-none data-[active=true]:text-foreground data-[active=false]:text-muted-foreground hover:text-foreground\"\n data-active={isActive}\n >\n <span>{tab.label}</span>\n {isActive ? (\n <span\n className=\"absolute -bottom-px left-0 right-0 h-0.5 bg-foreground\"\n aria-hidden=\"true\"\n />\n ) : null}\n </button>\n )\n })}\n </div>\n ) : null}\n <div\n id=\"mobile-drawer-tabpanel\"\n role={sidebarMode !== 'main' ? 'tabpanel' : undefined}\n aria-labelledby={\n sidebarMode !== 'main'\n ? `mobile-drawer-tab-${mobileDrawerView === 'main' ? 'main' : 'section'}`\n : undefined\n }\n className=\"min-h-0 flex-1 overflow-y-auto overflow-x-hidden p-3\"\n >\n {/* Force expanded sidebar in mobile drawer, hide its header and collapse toggle */}\n {renderSidebar(false, true, mobileDrawerView === 'main')}\n </div>\n </aside>\n </div>\n )}\n </div>\n <UmesDevToolsPanel />\n </HeaderContext.Provider>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["children"]
|
|
7
7
|
}
|
package/dist/backend/CrudForm.js
CHANGED
|
@@ -69,6 +69,7 @@ import {
|
|
|
69
69
|
Coins
|
|
70
70
|
} from "lucide-react";
|
|
71
71
|
import { loadGeneratedFieldRegistrations } from "./fields/registry.js";
|
|
72
|
+
import { isDefVisible } from "./utils/customFieldDefs.js";
|
|
72
73
|
import { buildFormFieldFromCustomFieldDef } from "./utils/customFieldForms.js";
|
|
73
74
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
74
75
|
import { TagsInput } from "./inputs/TagsInput.js";
|
|
@@ -1116,7 +1117,7 @@ function CrudForm({
|
|
|
1116
1117
|
fieldsetGroupMap.set(group.code, { code: group.code, title: group.title, hint: group.hint });
|
|
1117
1118
|
});
|
|
1118
1119
|
}
|
|
1119
|
-
const sortedDefs = [...defList].sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0));
|
|
1120
|
+
const sortedDefs = [...defList].filter((definition) => isDefVisible(definition, "form")).sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0));
|
|
1120
1121
|
const ensureBucket = (code, def) => {
|
|
1121
1122
|
const key = code ?? "__default__";
|
|
1122
1123
|
let bucket = groupsMap.get(key);
|