@open-mercato/ui 0.5.1-develop.3036.f02c281f23 → 0.5.1-develop.3045.b4b3320cc2
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/AGENTS.md +2 -1
- package/__integration__/TC-AI-UI-003-aichat-registry.spec.tsx +204 -0
- package/dist/ai/AiAssistantLauncher.js +596 -0
- package/dist/ai/AiAssistantLauncher.js.map +7 -0
- package/dist/ai/AiChat.js +1092 -0
- package/dist/ai/AiChat.js.map +7 -0
- package/dist/ai/AiChatSessions.js +297 -0
- package/dist/ai/AiChatSessions.js.map +7 -0
- package/dist/ai/AiDock.js +347 -0
- package/dist/ai/AiDock.js.map +7 -0
- package/dist/ai/AiMessageContent.js +369 -0
- package/dist/ai/AiMessageContent.js.map +7 -0
- package/dist/ai/ChatPaneTabs.js +251 -0
- package/dist/ai/ChatPaneTabs.js.map +7 -0
- package/dist/ai/index.js +115 -0
- package/dist/ai/index.js.map +7 -0
- package/dist/ai/parts/ConfirmationCard.js +211 -0
- package/dist/ai/parts/ConfirmationCard.js.map +7 -0
- package/dist/ai/parts/FieldDiffCard.js +119 -0
- package/dist/ai/parts/FieldDiffCard.js.map +7 -0
- package/dist/ai/parts/MutationPreviewCard.js +224 -0
- package/dist/ai/parts/MutationPreviewCard.js.map +7 -0
- package/dist/ai/parts/MutationResultCard.js +240 -0
- package/dist/ai/parts/MutationResultCard.js.map +7 -0
- package/dist/ai/parts/approval-cards-map.js +15 -0
- package/dist/ai/parts/approval-cards-map.js.map +7 -0
- package/dist/ai/parts/index.js +24 -0
- package/dist/ai/parts/index.js.map +7 -0
- package/dist/ai/parts/pending-action-api.js +60 -0
- package/dist/ai/parts/pending-action-api.js.map +7 -0
- package/dist/ai/parts/types.js +1 -0
- package/dist/ai/parts/types.js.map +7 -0
- package/dist/ai/parts/useAiPendingActionPolling.js +126 -0
- package/dist/ai/parts/useAiPendingActionPolling.js.map +7 -0
- package/dist/ai/records/ActivityCard.js +83 -0
- package/dist/ai/records/ActivityCard.js.map +7 -0
- package/dist/ai/records/CompanyCard.js +81 -0
- package/dist/ai/records/CompanyCard.js.map +7 -0
- package/dist/ai/records/DealCard.js +76 -0
- package/dist/ai/records/DealCard.js.map +7 -0
- package/dist/ai/records/PersonCard.js +68 -0
- package/dist/ai/records/PersonCard.js.map +7 -0
- package/dist/ai/records/ProductCard.js +68 -0
- package/dist/ai/records/ProductCard.js.map +7 -0
- package/dist/ai/records/RecordCard.js +29 -0
- package/dist/ai/records/RecordCard.js.map +7 -0
- package/dist/ai/records/RecordCardShell.js +103 -0
- package/dist/ai/records/RecordCardShell.js.map +7 -0
- package/dist/ai/records/index.js +31 -0
- package/dist/ai/records/index.js.map +7 -0
- package/dist/ai/records/registry.js +51 -0
- package/dist/ai/records/registry.js.map +7 -0
- package/dist/ai/records/types.js +1 -0
- package/dist/ai/records/types.js.map +7 -0
- package/dist/ai/ui-part-registry.js +112 -0
- package/dist/ai/ui-part-registry.js.map +7 -0
- package/dist/ai/ui-part-slots.js +14 -0
- package/dist/ai/ui-part-slots.js.map +7 -0
- package/dist/ai/ui-parts/pending-phase3-placeholder.js +35 -0
- package/dist/ai/ui-parts/pending-phase3-placeholder.js.map +7 -0
- package/dist/ai/upload-adapter.js +256 -0
- package/dist/ai/upload-adapter.js.map +7 -0
- package/dist/ai/useAiChat.js +549 -0
- package/dist/ai/useAiChat.js.map +7 -0
- package/dist/ai/useAiChatUpload.js +127 -0
- package/dist/ai/useAiChatUpload.js.map +7 -0
- package/dist/ai/useAiShortcuts.js +43 -0
- package/dist/ai/useAiShortcuts.js.map +7 -0
- package/dist/backend/AppShell.js +8 -4
- package/dist/backend/AppShell.js.map +2 -2
- package/dist/backend/BackendChromeProvider.js +2 -0
- package/dist/backend/BackendChromeProvider.js.map +2 -2
- package/dist/backend/DataTable.js +19 -2
- package/dist/backend/DataTable.js.map +2 -2
- package/dist/backend/FilterBar.js +19 -15
- package/dist/backend/FilterBar.js.map +2 -2
- package/dist/backend/dashboard/DashboardScreen.js +31 -3
- package/dist/backend/dashboard/DashboardScreen.js.map +2 -2
- package/dist/backend/injection/spotIds.js +6 -0
- package/dist/backend/injection/spotIds.js.map +2 -2
- package/dist/backend/notifications/useNotificationEffect.js +38 -2
- package/dist/backend/notifications/useNotificationEffect.js.map +2 -2
- package/dist/index.js +1 -0
- package/dist/index.js.map +2 -2
- package/jest.config.cjs +7 -1
- package/jest.markdown-mock.tsx +7 -0
- package/package.json +10 -4
- package/src/ai/AiAssistantLauncher.tsx +805 -0
- package/src/ai/AiChat.tsx +1483 -0
- package/src/ai/AiChatSessions.tsx +429 -0
- package/src/ai/AiDock.tsx +505 -0
- package/src/ai/AiMessageContent.tsx +515 -0
- package/src/ai/ChatPaneTabs.tsx +310 -0
- package/src/ai/__tests__/AiChat.conversation.test.tsx +160 -0
- package/src/ai/__tests__/AiChat.debug.test.tsx +152 -0
- package/src/ai/__tests__/AiChat.registry.test.tsx +213 -0
- package/src/ai/__tests__/AiChat.test.tsx +257 -0
- package/src/ai/__tests__/AiDock.test.tsx +124 -0
- package/src/ai/__tests__/AiMessageContent.test.ts +111 -0
- package/src/ai/__tests__/ui-part-registry.test.ts +199 -0
- package/src/ai/__tests__/ui-part-slots.test.ts +43 -0
- package/src/ai/__tests__/upload-adapter.test.ts +213 -0
- package/src/ai/__tests__/useAiChatUpload.test.tsx +163 -0
- package/src/ai/__tests__/useAiShortcuts.test.tsx +100 -0
- package/src/ai/index.ts +125 -0
- package/src/ai/parts/ConfirmationCard.tsx +310 -0
- package/src/ai/parts/FieldDiffCard.tsx +173 -0
- package/src/ai/parts/MutationPreviewCard.tsx +302 -0
- package/src/ai/parts/MutationResultCard.tsx +360 -0
- package/src/ai/parts/__tests__/ConfirmationCard.test.tsx +169 -0
- package/src/ai/parts/__tests__/FieldDiffCard.test.tsx +74 -0
- package/src/ai/parts/__tests__/MutationPreviewCard.test.tsx +177 -0
- package/src/ai/parts/__tests__/MutationResultCard.test.tsx +127 -0
- package/src/ai/parts/__tests__/useAiPendingActionPolling.test.tsx +151 -0
- package/src/ai/parts/approval-cards-map.ts +24 -0
- package/src/ai/parts/index.ts +27 -0
- package/src/ai/parts/pending-action-api.ts +123 -0
- package/src/ai/parts/types.ts +84 -0
- package/src/ai/parts/useAiPendingActionPolling.ts +210 -0
- package/src/ai/records/ActivityCard.tsx +102 -0
- package/src/ai/records/CompanyCard.tsx +89 -0
- package/src/ai/records/DealCard.tsx +85 -0
- package/src/ai/records/PersonCard.tsx +77 -0
- package/src/ai/records/ProductCard.tsx +83 -0
- package/src/ai/records/RecordCard.tsx +37 -0
- package/src/ai/records/RecordCardShell.tsx +169 -0
- package/src/ai/records/index.ts +30 -0
- package/src/ai/records/registry.tsx +80 -0
- package/src/ai/records/types.ts +90 -0
- package/src/ai/ui-part-registry.ts +233 -0
- package/src/ai/ui-part-slots.ts +32 -0
- package/src/ai/ui-parts/pending-phase3-placeholder.tsx +50 -0
- package/src/ai/upload-adapter.ts +421 -0
- package/src/ai/useAiChat.ts +865 -0
- package/src/ai/useAiChatUpload.ts +180 -0
- package/src/ai/useAiShortcuts.ts +79 -0
- package/src/backend/AppShell.tsx +12 -5
- package/src/backend/BackendChromeProvider.tsx +2 -0
- package/src/backend/DataTable.tsx +20 -1
- package/src/backend/FilterBar.tsx +26 -13
- package/src/backend/__tests__/BackendChromeProvider.test.tsx +45 -0
- package/src/backend/dashboard/DashboardScreen.tsx +38 -3
- package/src/backend/dashboard/__tests__/DashboardScreen.test.tsx +24 -1
- package/src/backend/injection/spotIds.ts +6 -0
- package/src/backend/notifications/__tests__/useNotificationEffect.test.tsx +77 -0
- package/src/backend/notifications/useNotificationEffect.ts +47 -2
- package/src/index.ts +1 -0
|
@@ -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, Search, X } from 'lucide-react'\nimport { Button } from '../primitives/button'\nimport { IconButton } from '../primitives/icon-button'\nimport { Input } from '../primitives/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 { 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 { 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 { BackendChromeProvider, useBackendChrome } from './BackendChromeProvider'\nimport {\n BACKEND_LAYOUT_FOOTER_INJECTION_SPOT_ID,\n BACKEND_LAYOUT_TOP_INJECTION_SPOT_ID,\n BACKEND_RECORD_CURRENT_INJECTION_SPOT_ID,\n BACKEND_SIDEBAR_FOOTER_INJECTION_SPOT_ID,\n BACKEND_SIDEBAR_TOP_INJECTION_SPOT_ID,\n BACKEND_SIDEBAR_NAV_FOOTER_INJECTION_SPOT_ID,\n BACKEND_SIDEBAR_NAV_INJECTION_SPOT_ID,\n BACKEND_TOPBAR_ACTIONS_INJECTION_SPOT_ID,\n GLOBAL_HEADER_STATUS_INDICATORS_INJECTION_SPOT_ID,\n GLOBAL_SIDEBAR_STATUS_BADGES_INJECTION_SPOT_ID,\n} from './injection/spotIds'\n\nexport type ShellLogo = {\n src: string\n alt?: string\n}\n\nexport type AppShellProps = {\n productName?: string\n logo?: ShellLogo\n email?: string\n groups: {\n id?: string\n name: string\n defaultName?: string\n items: {\n id?: string\n href: string\n title: string\n defaultTitle?: string\n icon?: React.ReactNode\n iconName?: string\n iconMarkup?: string\n enabled?: boolean\n hidden?: boolean\n pageContext?: 'main' | 'admin' | 'settings' | 'profile'\n children?: {\n id?: string\n href: string\n title: string\n defaultTitle?: string\n icon?: React.ReactNode\n iconName?: string\n iconMarkup?: string\n enabled?: boolean\n hidden?: boolean\n pageContext?: 'main' | 'admin' | 'settings' | 'profile'\n }[]\n }[]\n }[]\n children: React.ReactNode\n rightHeaderSlot?: React.ReactNode\n sidebarCollapsedDefault?: boolean\n currentTitle?: string\n breadcrumb?: Array<{ label: string; href?: string }>\n // Optional: full admin nav API to refresh sidebar client-side\n adminNavApi?: string\n version?: string\n settingsSectionTitle?: string\n settingsPathPrefixes?: string[]\n settingsSections?: SectionNavGroup[]\n profileSections?: SectionNavGroup[]\n profileSectionTitle?: string\n profilePathPrefixes?: string[]\n mobileSidebarSlot?: React.ReactNode\n}\n\ntype Breadcrumb = Array<{ label: string; href?: string }>\n\ntype 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 mergeSidebarItemsWithInjected(\n items: SidebarItem[],\n injectedItems: InjectionMenuItem[],\n t: (key: string, fallback?: string) => string,\n): SidebarItem[] {\n if (injectedItems.length === 0) return items\n\n const builtInById = new Map<string, SidebarItem>()\n for (const item of items) {\n builtInById.set(item.id ?? item.href, item)\n }\n\n const merged = mergeMenuItems(\n items.map((item) => ({\n id: item.id ?? item.href,\n })),\n injectedItems,\n )\n\n const result: SidebarItem[] = []\n for (const entry of merged) {\n if (entry.source === 'built-in') {\n const original = builtInById.get(entry.id)\n if (original) result.push(original)\n continue\n }\n const translatedLabel = resolveInjectedMenuLabel(\n { id: entry.id, label: entry.label, labelKey: entry.labelKey },\n t,\n )\n const converted = convertInjectedMenuItemToSidebarItem(\n {\n id: entry.id,\n label: translatedLabel,\n icon: entry.icon,\n href: entry.href,\n },\n translatedLabel,\n )\n if (converted) result.push(converted)\n }\n\n return result\n}\n\nfunction mergeSidebarGroupsWithInjected(\n groups: SidebarGroup[],\n injectedItems: InjectionMenuItem[],\n t: (key: string, fallback?: string) => string,\n): SidebarGroup[] {\n if (injectedItems.length === 0) return groups\n\n const injectedByGroup = new Map<string, InjectionMenuItem[]>()\n const ungrouped: InjectionMenuItem[] = []\n\n for (const item of injectedItems) {\n if (item.groupId && item.groupId.trim().length > 0) {\n const groupItems = injectedByGroup.get(item.groupId) ?? []\n groupItems.push(item)\n injectedByGroup.set(item.groupId, groupItems)\n continue\n }\n ungrouped.push(item)\n }\n\n const nextGroups = groups.map((group, index) => {\n const groupId = group.id || resolveGroupKey(group)\n const groupInjected = [\n ...(injectedByGroup.get(groupId) ?? []),\n ...(index === 0 ? ungrouped : []),\n ]\n return {\n ...group,\n items: mergeSidebarItemsWithInjected(group.items, groupInjected, t),\n }\n })\n\n const existingIds = new Set(nextGroups.map((group) => group.id || resolveGroupKey(group)))\n for (const [groupId, items] of injectedByGroup.entries()) {\n if (existingIds.has(groupId)) continue\n const first = items[0]\n const label = first.groupLabelKey\n ? t(first.groupLabelKey, first.groupLabel ?? groupId)\n : (first.groupLabel ?? groupId)\n const groupItems = mergeSidebarItemsWithInjected([], items, t)\n if (groupItems.length === 0) continue\n nextGroups.push({\n id: groupId,\n name: label,\n defaultName: label,\n items: groupItems,\n })\n }\n\n return nextGroups\n}\n\nfunction mergeSectionGroupsWithInjected(\n sections: SectionNavGroup[],\n injectedItems: InjectionMenuItem[],\n t: (key: string, fallback?: string) => string,\n): SectionNavGroup[] {\n if (injectedItems.length === 0) return sections\n const byGroup = new Map<string, InjectionMenuItem[]>()\n for (const item of injectedItems) {\n const groupId = item.groupId && item.groupId.trim().length > 0 ? item.groupId : 'injected'\n const bucket = byGroup.get(groupId) ?? []\n bucket.push(item)\n byGroup.set(groupId, bucket)\n }\n\n const nextSections = sections.map((section) => {\n const sectionItems = byGroup.get(section.id) ?? []\n if (sectionItems.length === 0) return section\n const mergedItems = mergeMenuItems(\n section.items.map((item) => ({ id: item.id, item })),\n sectionItems,\n ).flatMap((item) => {\n if (item.source === 'built-in') {\n const original = section.items.find((entry) => entry.id === item.id)\n return original ? [original] : []\n }\n if (!item.href) return []\n const label = resolveInjectedMenuLabel(item, t)\n return [{\n id: item.id,\n label,\n href: item.href,\n icon: resolveInjectedIcon(item.icon) ?? undefined,\n }]\n })\n return {\n ...section,\n items: mergedItems,\n }\n })\n\n for (const [sectionId, sectionItems] of byGroup.entries()) {\n const exists = nextSections.some((section) => section.id === sectionId)\n if (exists) continue\n const first = sectionItems[0]\n const label = first.groupLabelKey\n ? t(first.groupLabelKey, first.groupLabel ?? sectionId)\n : (first.groupLabel ?? sectionId)\n const items = sectionItems.flatMap((item) => {\n if (!item.href) return []\n const itemLabel = resolveInjectedMenuLabel(item, t)\n return [{\n id: item.id,\n label: itemLabel,\n href: item.href,\n icon: resolveInjectedIcon(item.icon) ?? undefined,\n }]\n })\n if (items.length === 0) continue\n nextSections.push({ id: sectionId, label, items })\n }\n\n return nextSections\n}\n\nfunction resolveGroupKey(group: SidebarGroup): string {\n if (group.id && group.id.length) return group.id\n if (group.defaultName && group.defaultName.length) return slugifySidebarId(group.defaultName)\n return slugifySidebarId(group.name)\n}\n\nfunction resolveItemKey(item: { id?: string; href: string }): string {\n const candidate = item.id?.trim()\n if (candidate && candidate.length > 0) return candidate\n return item.href\n}\n\nfunction SerializedIcon({ markup }: { markup: string }) {\n return <span aria-hidden=\"true\" dangerouslySetInnerHTML={{ __html: markup }} />\n}\n\nfunction renderIcon(\n icon: React.ReactNode | undefined,\n iconName: string | undefined,\n iconMarkup: string | undefined,\n fallback: React.ReactNode,\n) {\n if (icon) return icon\n if (iconName) {\n const resolved = resolveInjectedIcon(iconName)\n if (resolved) return resolved\n }\n if (iconMarkup) return <SerializedIcon markup={iconMarkup} />\n return fallback\n}\n\nconst HeaderContext = createContext<{\n setBreadcrumb: (b?: Breadcrumb) => void\n setTitle: (t?: string) => void\n} | null>(null)\n\nexport function ApplyBreadcrumb({ breadcrumb, title, titleKey }: { breadcrumb?: Array<{ label: string; href?: string; labelKey?: string }>; title?: string; titleKey?: string }) {\n const ctx = useContext(HeaderContext)\n const t = useT()\n const resolvedBreadcrumb = React.useMemo<Breadcrumb | undefined>(() => {\n if (!breadcrumb) return undefined\n return breadcrumb.map(({ label, labelKey, href }) => {\n const translated = labelKey ? t(labelKey) : undefined\n const finalLabel = translated && translated !== labelKey ? translated : label\n return {\n href,\n label: finalLabel,\n }\n })\n }, [breadcrumb, t])\n const resolvedTitle = React.useMemo(() => {\n if (!titleKey) return title\n const translated = t(titleKey)\n if (translated && translated !== titleKey) return translated\n return title\n }, [titleKey, title, t])\n React.useEffect(() => {\n ctx?.setBreadcrumb(resolvedBreadcrumb)\n if (resolvedTitle !== undefined) ctx?.setTitle(resolvedTitle)\n }, [ctx, resolvedBreadcrumb, resolvedTitle])\n return null\n}\n\nconst DefaultIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M8 6h13M8 12h13M8 18h13\"/>\n <path d=\"M3 6h.01M3 12h.01M3 18h.01\"/>\n </svg>\n)\n\n// DataTable icon used for dynamic custom entity records links\nconst DataTableIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\" ry=\"2\"/>\n <line x1=\"3\" y1=\"8\" x2=\"21\" y2=\"8\"/>\n <line x1=\"9\" y1=\"8\" x2=\"9\" y2=\"20\"/>\n <line x1=\"15\" y1=\"8\" x2=\"15\" y2=\"20\"/>\n </svg>\n)\n\nconst CustomizeIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.05.05a2 2 0 1 1-2.83 2.83l-.05-.05A1.65 1.65 0 0 0 15 19.4a1.65 1.65 0 0 0-1 .6 1.65 1.65 0 0 0-.33 1.82l-.05.05a2 2 0 1 1-2.83-2.83l.05-.05A1.65 1.65 0 0 0 9 15a1.65 1.65 0 0 0-1-.6 1.65 1.65 0 0 0-1.82.33l-.05.05a2 2 0 1 1-2.83-2.83l.05-.05A1.65 1.65 0 0 0 4.6 9 1.65 1.65 0 0 0 4 8a1.65 1.65 0 0 0-.6-1.82l-.05-.05a2 2 0 1 1 2.83-2.83l.05.05A1.65 1.65 0 0 0 9 4.6a1.65 1.65 0 0 0 1-.6 1.65 1.65 0 0 0 .33-1.82l.05-.05a2 2 0 1 1 2.83 2.83l-.05.05A1.65 1.65 0 0 0 15 9a1.65 1.65 0 0 0 1 .6 1.65 1.65 0 0 0 1.82-.33l.05-.05a2 2 0 1 1 2.83 2.83l-.05.05A1.65 1.65 0 0 0 19.4 15z\" />\n </svg>\n)\n\nconst BackArrowIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M19 12H5M12 19l-7-7 7-7\" />\n </svg>\n)\n\nfunction Chevron({ open }: { open: boolean }) {\n return (\n <svg className={`transition-transform ${open ? 'rotate-180' : ''}`} width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><path d=\"M6 9l6 6 6-6\"/></svg>\n )\n}\n\nexport function AppShell(props: AppShellProps) {\n return (\n <QueryProvider>\n <BackendChromeProvider adminNavApi={props.adminNavApi}>\n <AppShellBody {...props} />\n </BackendChromeProvider>\n </QueryProvider>\n )\n}\n\nfunction AppShellBody({ productName, logo, email, groups, rightHeaderSlot, children, sidebarCollapsedDefault = false, currentTitle, breadcrumb, version, settingsSectionTitle, settingsPathPrefixes = [], settingsSections, profileSections, profileSectionTitle, profilePathPrefixes = [], mobileSidebarSlot }: AppShellProps) {\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const t = useT()\n const locale = useLocale()\n const { payload: chromePayload, isReady: isChromeReady, isLoading: isChromeLoading } = useBackendChrome()\n const resolvedGroups = React.useMemo(\n () => 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 [mobileOpen, setMobileOpen] = React.useState(false)\n // Initialize from server-provided prop only to avoid hydration flicker\n const [collapsed, setCollapsed] = React.useState(sidebarCollapsedDefault)\n // Maintain internal nav state so we can augment it client-side\n const [navGroups, setNavGroups] = React.useState(resolvedGroups)\n const [openGroups, setOpenGroups] = React.useState<Record<string, boolean>>(() =>\n Object.fromEntries(resolvedGroups.map((g) => [resolveGroupKey(g), true])) as Record<string, boolean>\n )\n const [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 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 setSidebarScrollState('none')\n return\n }\n const atBottom = scrollTop + clientHeight >= scrollHeight - 8\n setSidebarScrollState(atBottom ? 'up' : 'down')\n }\n update()\n target.addEventListener('scroll', update, { passive: true })\n const ro = new ResizeObserver(update)\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 try {\n const savedOpen = typeof window !== 'undefined' ? localStorage.getItem('om:sidebarOpenGroups') : null\n if (!savedOpen) return\n const parsed = JSON.parse(savedOpen) as Record<string, boolean>\n setOpenGroups((prev) => {\n const next = { ...prev }\n for (const group of resolvedGroups) {\n const key = resolveGroupKey(group)\n if (key in parsed) next[key] = !!parsed[key]\n else if (group.name in parsed) next[key] = !!parsed[group.name]\n }\n return next\n })\n } catch {\n // ignore localStorage errors to avoid breaking hydration\n }\n }, [resolvedGroups])\n\n const toggleGroup = (groupId: string) => setOpenGroups((prev) => ({ ...prev, [groupId]: prev[groupId] === false }))\n\n const 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 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 try { localStorage.setItem('om:sidebarOpenGroups', JSON.stringify(openGroups)) } catch { /* localStorage blocked (private mode) \u2014 non-critical */ }\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={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? resolvedProductName} width={40} height={40} className=\"rounded-full shrink-0\" />\n {!compact && <span className=\"text-sm font-medium text-foreground\">{resolvedProductName}</span>}\n </Link>\n </div>\n )}\n {!compact && !hideSearch && (\n <Input\n type=\"text\"\n value={navQuery}\n onChange={(e) => setNavQuery(e.target.value)}\n placeholder={t('appShell.searchNavPlaceholder', 'Search...')}\n aria-label={t('appShell.searchNavAria', 'Search navigation')}\n leftIcon={<Search aria-hidden />}\n rightIcon={navQueryActive ? (\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"xs\"\n onClick={() => setNavQuery('')}\n aria-label={t('appShell.searchNavClear', 'Clear search')}\n >\n <X className=\"size-3.5\" aria-hidden />\n </IconButton>\n ) : undefined}\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 && resolvedGroups.length === 0) {\n return (\n <div className=\"flex flex-col min-h-full gap-3\" data-testid=\"backend-chrome-loading\">\n {!hideHeader ? (\n <div className=\"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={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? resolvedProductName} width={40} height={40} className=\"rounded-full shrink-0\" />\n {!compact && <span className=\"text-sm font-medium text-foreground\">{resolvedProductName}</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={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? resolvedProductName} width={40} height={40} className=\"rounded-full shrink-0\" />\n {!compact && <span className=\"text-sm font-medium text-foreground\">{resolvedProductName}</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 <Input\n type=\"text\"\n value={navQuery}\n onChange={(e) => setNavQuery(e.target.value)}\n placeholder={t('appShell.searchNavPlaceholder', 'Search...')}\n aria-label={t('appShell.searchNavAria', 'Search navigation')}\n leftIcon={<Search aria-hidden />}\n rightIcon={navQueryActive ? (\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"xs\"\n onClick={() => setNavQuery('')}\n aria-label={t('appShell.searchNavClear', 'Clear search')}\n >\n <X className=\"size-3.5\" aria-hidden />\n </IconButton>\n ) : undefined}\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 className=\"h-7 text-xs\"\n data-menu-item-id={item.id}\n onClick={() => item.onClick?.()}\n >\n {label}\n </Button>\n )\n }),\n [t, topbarInjectedMenuItems],\n )\n\n return (\n <HeaderContext.Provider value={headerCtxValue}>\n <div className={`min-h-svh lg:grid transition-[grid-template-columns] duration-200 ease-out ${gridColsClass}`}>\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 + chevron that flips up when the user\n reaches the bottom and disappears when nothing is scrollable. */}\n {sidebarScrollState !== 'none' ? (\n <div\n aria-hidden\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 {/* Outer div owns the rotate transition so it doesn't fight with the\n animate-bounce keyframes (both target `transform`). */}\n <span\n className={`inline-flex transition-transform duration-300 ${sidebarScrollState === 'up' ? 'rotate-180' : ''}`}\n >\n <ChevronDown className=\"size-4 animate-bounce text-muted-foreground/70\" />\n </span>\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=\"border-b bg-background/80 px-3 lg:px-4 py-2 lg:py-3 flex items-center justify-between gap-2\">\n <div\n data-testid=\"backend-chrome-ready\"\n data-ready={isChromeReady ? 'true' : 'false'}\n className=\"hidden\"\n />\n <div className=\"flex items-center gap-2 min-w-0\">\n {/* Mobile menu button */}\n <IconButton variant=\"outline\" size=\"sm\" className=\"lg:hidden\" aria-label={t('appShell.openMenu')} onClick={() => setMobileOpen(true)}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><path d=\"M3 6h18M3 12h18M3 18h18\"/></svg>\n </IconButton>\n {/* Desktop collapse toggle */}\n <IconButton\n variant=\"outline\"\n size=\"sm\"\n className=\"hidden lg:inline-flex\"\n aria-label={t('appShell.toggleSidebar')}\n onClick={() => setCollapsed((c) => !c)}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\"/>\n <path d=\"M9 4v16\"/>\n </svg>\n </IconButton>\n {/* Header breadcrumb: always starts with Dashboard */}\n {(() => {\n const dashboardLabel = t('dashboard.title')\n const root: Breadcrumb = [{ label: dashboardLabel, href: '/backend' }]\n let rest: Breadcrumb = []\n if (headerBreadcrumb && headerBreadcrumb.length) {\n const first = headerBreadcrumb[0]\n const dup = first && (first.href === '/backend' || first.label === dashboardLabel || first.label?.toLowerCase() === 'dashboard')\n rest = dup ? headerBreadcrumb.slice(1) : headerBreadcrumb\n } else if (headerTitle) {\n rest = [{ label: headerTitle }]\n }\n const items = [...root, ...rest]\n const lastIndex = items.length - 1\n return (\n <nav className=\"flex items-center gap-2 text-sm min-w-0\">\n {items.map((b, i) => {\n const isLast = i === lastIndex\n const hiddenOnMobile = !isLast ? 'hidden md:inline' : ''\n return (\n <React.Fragment key={i}>\n {i > 0 && <span className={`text-muted-foreground hidden md:inline`}>/</span>}\n {b.href ? (\n <Link href={b.href} className={`text-muted-foreground hover:text-foreground ${hiddenOnMobile}`}>\n {b.label}\n </Link>\n ) : (\n <span className={`font-medium truncate max-w-[45vw] md:max-w-[60vw]`}>{b.label}</span>\n )}\n </React.Fragment>\n )\n })}\n </nav>\n )\n })()}\n </div>\n <div className=\"flex items-center gap-1 md:gap-2 text-sm shrink-0\">\n <StatusBadgeInjectionSpot\n spotId={GLOBAL_HEADER_STATUS_INDICATORS_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n <InjectionSpot\n spotId={BACKEND_TOPBAR_ACTIONS_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n {renderedTopbarInjectedActions}\n {rightHeaderSlot ? (\n rightHeaderSlot\n ) : (\n <span className=\"opacity-80\">{email || t('appShell.userFallback')}</span>\n )}\n </div>\n </header>\n <ProgressTopBar t={t} className=\"sticky top-0 z-sticky\" />\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 <UpgradeActionBanner />\n <LastOperationBanner />\n <InjectionSpot spotId={BACKEND_RECORD_CURRENT_INJECTION_SPOT_ID} context={injectionContext} />\n <InjectionSpot\n spotId={LEGACY_GLOBAL_MUTATION_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n <div id=\"om-top-banners\" className=\"mb-3 space-y-2\" />\n {children}\n <InjectionSpot spotId={BACKEND_LAYOUT_FOOTER_INJECTION_SPOT_ID} context={injectionContext} />\n </main>\n <footer className=\"border-t bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/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/20\" onClick={() => setMobileOpen(false)} aria-hidden=\"true\" />\n <aside className=\"absolute left-0 top-0 flex h-full w-[260px] flex-col bg-background border-r overflow-hidden\">\n <div className=\"shrink-0 p-3 pb-2 flex items-center justify-between border-b\">\n <Link href=\"/backend\" className=\"flex items-center gap-2 text-sm font-semibold\" onClick={() => setMobileOpen(false)} aria-label={t('appShell.goToDashboard')}>\n <Image src={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? resolvedProductName} width={28} height={28} className=\"rounded\" />\n {resolvedProductName}\n </Link>\n <IconButton variant=\"outline\" size=\"sm\" onClick={() => setMobileOpen(false)} aria-label={t('appShell.closeMenu')}>\u2715</IconButton>\n </div>\n {mobileSidebarSlot && (\n <div className=\"shrink-0 border-b px-3 py-2\">\n {mobileSidebarSlot}\n </div>\n )}\n <div className=\"min-h-0 flex-1 overflow-y-auto overflow-x-hidden p-3\">\n {/* Force expanded sidebar in mobile drawer, hide its header and collapse toggle */}\n {renderSidebar(false, true)}\n </div>\n </aside>\n </div>\n )}\n </div>\n <UmesDevToolsPanel />\n </HeaderContext.Provider>\n )\n}\n\n"],
|
|
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, Search, X } from 'lucide-react'\nimport { Button } from '../primitives/button'\nimport { IconButton } from '../primitives/icon-button'\nimport { Input } from '../primitives/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 { 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 { 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\nexport type ShellLogo = {\n src: string\n alt?: string\n}\n\nexport type AppShellProps = {\n productName?: string\n logo?: ShellLogo\n email?: string\n groups: {\n id?: string\n name: string\n defaultName?: string\n items: {\n id?: string\n href: string\n title: string\n defaultTitle?: string\n icon?: React.ReactNode\n iconName?: string\n iconMarkup?: string\n enabled?: boolean\n hidden?: boolean\n pageContext?: 'main' | 'admin' | 'settings' | 'profile'\n children?: {\n id?: string\n href: string\n title: string\n defaultTitle?: string\n icon?: React.ReactNode\n iconName?: string\n iconMarkup?: string\n enabled?: boolean\n hidden?: boolean\n pageContext?: 'main' | 'admin' | 'settings' | 'profile'\n }[]\n }[]\n }[]\n children: React.ReactNode\n rightHeaderSlot?: React.ReactNode\n sidebarCollapsedDefault?: boolean\n currentTitle?: string\n breadcrumb?: Array<{ label: string; href?: string }>\n // Optional: full admin nav API to refresh sidebar client-side\n adminNavApi?: string\n version?: string\n settingsSectionTitle?: string\n settingsPathPrefixes?: string[]\n settingsSections?: SectionNavGroup[]\n profileSections?: SectionNavGroup[]\n profileSectionTitle?: string\n profilePathPrefixes?: string[]\n mobileSidebarSlot?: React.ReactNode\n}\n\ntype Breadcrumb = Array<{ label: string; href?: string }>\n\ntype 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 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, groups, rightHeaderSlot, children, sidebarCollapsedDefault = false, currentTitle, breadcrumb, version, settingsSectionTitle, settingsPathPrefixes = [], settingsSections, profileSections, profileSectionTitle, profilePathPrefixes = [], mobileSidebarSlot }: AppShellProps) {\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const t = useT()\n const locale = useLocale()\n const { payload: chromePayload, isReady: isChromeReady, isLoading: isChromeLoading } = useBackendChrome()\n const resolvedGroups = React.useMemo(\n () => 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 [mobileOpen, setMobileOpen] = React.useState(false)\n // Initialize from server-provided prop only to avoid hydration flicker\n const [collapsed, setCollapsed] = React.useState(sidebarCollapsedDefault)\n // Maintain internal nav state so we can augment it client-side\n const [navGroups, setNavGroups] = React.useState(resolvedGroups)\n const [openGroups, setOpenGroups] = React.useState<Record<string, boolean>>(() =>\n Object.fromEntries(resolvedGroups.map((g) => [resolveGroupKey(g), true])) as Record<string, boolean>\n )\n const [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 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 setSidebarScrollState('none')\n return\n }\n const atBottom = scrollTop + clientHeight >= scrollHeight - 8\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 try {\n const savedOpen = typeof window !== 'undefined' ? localStorage.getItem('om:sidebarOpenGroups') : null\n if (!savedOpen) return\n const parsed = JSON.parse(savedOpen) as Record<string, boolean>\n setOpenGroups((prev) => {\n const next = { ...prev }\n for (const group of resolvedGroups) {\n const key = resolveGroupKey(group)\n if (key in parsed) next[key] = !!parsed[key]\n else if (group.name in parsed) next[key] = !!parsed[group.name]\n }\n return next\n })\n } catch {\n // ignore localStorage errors to avoid breaking hydration\n }\n }, [resolvedGroups])\n\n const toggleGroup = (groupId: string) => setOpenGroups((prev) => ({ ...prev, [groupId]: prev[groupId] === false }))\n\n const 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 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 try { localStorage.setItem('om:sidebarOpenGroups', JSON.stringify(openGroups)) } catch { /* localStorage blocked (private mode) \u2014 non-critical */ }\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={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? resolvedProductName} width={40} height={40} className=\"rounded-full shrink-0\" />\n {!compact && <span className=\"text-sm font-medium text-foreground\">{resolvedProductName}</span>}\n </Link>\n </div>\n )}\n {!compact && !hideSearch && (\n <Input\n type=\"text\"\n value={navQuery}\n onChange={(e) => setNavQuery(e.target.value)}\n placeholder={t('appShell.searchNavPlaceholder', 'Search...')}\n aria-label={t('appShell.searchNavAria', 'Search navigation')}\n leftIcon={<Search aria-hidden />}\n rightIcon={navQueryActive ? (\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"xs\"\n onClick={() => setNavQuery('')}\n aria-label={t('appShell.searchNavClear', 'Clear search')}\n >\n <X className=\"size-3.5\" aria-hidden />\n </IconButton>\n ) : undefined}\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 && resolvedGroups.length === 0) {\n return (\n <div className=\"flex flex-col min-h-full gap-3\" data-testid=\"backend-chrome-loading\">\n {!hideHeader ? (\n <div className=\"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={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? resolvedProductName} width={40} height={40} className=\"rounded-full shrink-0\" />\n {!compact && <span className=\"text-sm font-medium text-foreground\">{resolvedProductName}</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={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? resolvedProductName} width={40} height={40} className=\"rounded-full shrink-0\" />\n {!compact && <span className=\"text-sm font-medium text-foreground\">{resolvedProductName}</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 <Input\n type=\"text\"\n value={navQuery}\n onChange={(e) => setNavQuery(e.target.value)}\n placeholder={t('appShell.searchNavPlaceholder', 'Search...')}\n aria-label={t('appShell.searchNavAria', 'Search navigation')}\n leftIcon={<Search aria-hidden />}\n rightIcon={navQueryActive ? (\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"xs\"\n onClick={() => setNavQuery('')}\n aria-label={t('appShell.searchNavClear', 'Clear search')}\n >\n <X className=\"size-3.5\" aria-hidden />\n </IconButton>\n ) : undefined}\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 className=\"h-7 text-xs\"\n data-menu-item-id={item.id}\n onClick={() => item.onClick?.()}\n >\n {label}\n </Button>\n )\n }),\n [t, topbarInjectedMenuItems],\n )\n\n return (\n <HeaderContext.Provider value={headerCtxValue}>\n <div className={`min-h-svh lg:grid transition-[grid-template-columns] duration-200 ease-out ${gridColsClass}`}>\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 + chevron that flips up when the user\n reaches the bottom and disappears when nothing is scrollable. */}\n {sidebarScrollState !== 'none' ? (\n <div\n aria-hidden\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 {/* Outer div owns the rotate transition so it doesn't fight with the\n animate-bounce keyframes (both target `transform`). */}\n <span\n className={`inline-flex transition-transform duration-300 ${sidebarScrollState === 'up' ? 'rotate-180' : ''}`}\n >\n <ChevronDown className=\"size-4 animate-bounce text-muted-foreground/70\" />\n </span>\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=\"border-b bg-background/80 px-3 lg:px-4 py-2 lg:py-3 flex items-center justify-between gap-2\">\n <div\n data-testid=\"backend-chrome-ready\"\n data-ready={isChromeReady ? 'true' : 'false'}\n className=\"hidden\"\n />\n <div className=\"flex items-center gap-2 min-w-0\">\n {/* Mobile menu button */}\n <IconButton variant=\"outline\" size=\"sm\" className=\"lg:hidden\" aria-label={t('appShell.openMenu')} onClick={() => setMobileOpen(true)}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><path d=\"M3 6h18M3 12h18M3 18h18\"/></svg>\n </IconButton>\n {/* Desktop collapse toggle */}\n <IconButton\n variant=\"outline\"\n size=\"sm\"\n className=\"hidden lg:inline-flex\"\n aria-label={t('appShell.toggleSidebar')}\n onClick={() => setCollapsed((c) => !c)}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\"/>\n <path d=\"M9 4v16\"/>\n </svg>\n </IconButton>\n {/* Header breadcrumb: always starts with Dashboard */}\n {(() => {\n const dashboardLabel = t('dashboard.title')\n const root: Breadcrumb = [{ label: dashboardLabel, href: '/backend' }]\n let rest: Breadcrumb = []\n if (headerBreadcrumb && headerBreadcrumb.length) {\n const first = headerBreadcrumb[0]\n const dup = first && (first.href === '/backend' || first.label === dashboardLabel || first.label?.toLowerCase() === 'dashboard')\n rest = dup ? headerBreadcrumb.slice(1) : headerBreadcrumb\n } else if (headerTitle) {\n rest = [{ label: headerTitle }]\n }\n const items = [...root, ...rest]\n const lastIndex = items.length - 1\n return (\n <nav className=\"flex items-center gap-2 text-sm min-w-0\">\n {items.map((b, i) => {\n const isLast = i === lastIndex\n const hiddenOnMobile = !isLast ? 'hidden md:inline' : ''\n return (\n <React.Fragment key={i}>\n {i > 0 && <span className={`text-muted-foreground hidden md:inline`}>/</span>}\n {b.href ? (\n <Link href={b.href} className={`text-muted-foreground hover:text-foreground ${hiddenOnMobile}`}>\n {b.label}\n </Link>\n ) : (\n <span className={`font-medium truncate max-w-[45vw] md:max-w-[60vw]`}>{b.label}</span>\n )}\n </React.Fragment>\n )\n })}\n </nav>\n )\n })()}\n </div>\n <div className=\"flex items-center gap-1 md:gap-2 text-sm shrink-0\">\n <StatusBadgeInjectionSpot\n spotId={GLOBAL_HEADER_STATUS_INDICATORS_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n <InjectionSpot\n spotId={BACKEND_TOPBAR_ACTIONS_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n {renderedTopbarInjectedActions}\n <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\" />\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 <UpgradeActionBanner />\n <LastOperationBanner />\n <InjectionSpot spotId={BACKEND_RECORD_CURRENT_INJECTION_SPOT_ID} context={injectionContext} />\n <InjectionSpot\n spotId={LEGACY_GLOBAL_MUTATION_INJECTION_SPOT_ID}\n context={injectionContext}\n />\n <div id=\"om-top-banners\" className=\"mb-3 space-y-2\" />\n {children}\n <InjectionSpot spotId={BACKEND_LAYOUT_FOOTER_INJECTION_SPOT_ID} context={injectionContext} />\n </main>\n <footer className=\"border-t bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/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/20\" onClick={() => setMobileOpen(false)} aria-hidden=\"true\" />\n <aside className=\"absolute left-0 top-0 flex h-full w-[260px] flex-col bg-background border-r overflow-hidden\">\n <div className=\"shrink-0 p-3 pb-2 flex items-center justify-between border-b\">\n <Link href=\"/backend\" className=\"flex items-center gap-2 text-sm font-semibold\" onClick={() => setMobileOpen(false)} aria-label={t('appShell.goToDashboard')}>\n <Image src={logo?.src ?? \"/open-mercato.svg\"} alt={logo?.alt ?? resolvedProductName} width={28} height={28} className=\"rounded\" />\n {resolvedProductName}\n </Link>\n <IconButton variant=\"outline\" size=\"sm\" onClick={() => setMobileOpen(false)} aria-label={t('appShell.closeMenu')}>\u2715</IconButton>\n </div>\n {mobileSidebarSlot && (\n <div className=\"shrink-0 border-b px-3 py-2\">\n {mobileSidebarSlot}\n </div>\n )}\n <div className=\"min-h-0 flex-1 overflow-y-auto overflow-x-hidden p-3\">\n {/* Force expanded sidebar in mobile drawer, hide its header and collapse toggle */}\n {renderSidebar(false, true)}\n </div>\n </aside>\n </div>\n )}\n </div>\n <UmesDevToolsPanel />\n </HeaderContext.Provider>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["children"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/backend/BackendChromeProvider.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { apiCall } from './utils/apiCall'\nimport { subscribeOrganizationScopeChanged, getCurrentOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/organizationEvents'\nimport type { BackendChromePayload } from '@open-mercato/shared/modules/navigation/backendChrome'\n\ntype BackendChromeContextValue = {\n payload: BackendChromePayload | null\n isLoading: boolean\n isReady: boolean\n refresh: () => Promise<void>\n}\n\ntype BackendChromeProviderProps = {\n adminNavApi?: string\n children: React.ReactNode\n}\n\nconst chromeCache = new Map<string, BackendChromePayload>()\nconst BackendChromeContext = React.createContext<BackendChromeContextValue | null>(null)\n\nfunction buildCacheKey(api: string): string {\n return `${api}::scope:${getCurrentOrganizationScopeVersion()}`\n}\n\nexport function BackendChromeProvider({ adminNavApi, children }: BackendChromeProviderProps) {\n const cachedPayload = React.useMemo(() => {\n if (!adminNavApi) return null\n return chromeCache.get(buildCacheKey(adminNavApi)) ?? null\n }, [adminNavApi])\n const [payload, setPayload] = React.useState<BackendChromePayload | null>(cachedPayload)\n const [isLoading, setIsLoading] = React.useState(Boolean(adminNavApi && !cachedPayload))\n\n const refresh = React.useCallback(async () => {\n if (!adminNavApi) return\n setIsLoading(true)\n try {\n const call = await apiCall<BackendChromePayload>(adminNavApi, { credentials: 'include' as never })\n if (!call.ok || !call.result) return\n const nextPayload = call.result\n chromeCache.set(buildCacheKey(adminNavApi), nextPayload)\n setPayload(nextPayload)\n } finally {\n setIsLoading(false)\n }\n }, [adminNavApi])\n\n React.useEffect(() => {\n if (!adminNavApi) {\n setPayload(null)\n setIsLoading(false)\n return\n }\n const cached = chromeCache.get(buildCacheKey(adminNavApi)) ?? null\n setPayload(cached)\n if (!cached) {\n void refresh()\n }\n }, [adminNavApi, refresh])\n\n React.useEffect(() => {\n if (!adminNavApi) return\n const onFocus = () => { void refresh() }\n const onManualRefresh = () => { void refresh() }\n const unsubscribeScope = subscribeOrganizationScopeChanged(() => {\n void refresh()\n })\n window.addEventListener('focus', onFocus)\n window.addEventListener('om:refresh-sidebar', onManualRefresh as EventListener)\n return () => {\n unsubscribeScope()\n window.removeEventListener('focus', onFocus)\n window.removeEventListener('om:refresh-sidebar', onManualRefresh as EventListener)\n }\n }, [adminNavApi, refresh])\n\n const value = React.useMemo<BackendChromeContextValue>(() => ({\n payload,\n isLoading,\n isReady: !adminNavApi || payload !== null,\n refresh,\n }), [adminNavApi, isLoading, payload, refresh])\n\n return (\n <BackendChromeContext.Provider value={value}>\n {children}\n </BackendChromeContext.Provider>\n )\n}\n\nexport function useBackendChrome(): BackendChromeContextValue {\n return React.useContext(BackendChromeContext) ?? {\n payload: null,\n isLoading: false,\n isReady: true,\n refresh: async () => {},\n }\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { apiCall } from './utils/apiCall'\nimport { subscribeOrganizationScopeChanged, getCurrentOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/organizationEvents'\nimport type { BackendChromePayload } from '@open-mercato/shared/modules/navigation/backendChrome'\n\ntype BackendChromeContextValue = {\n payload: BackendChromePayload | null\n isLoading: boolean\n isReady: boolean\n refresh: () => Promise<void>\n}\n\ntype BackendChromeProviderProps = {\n adminNavApi?: string\n children: React.ReactNode\n}\n\nconst chromeCache = new Map<string, BackendChromePayload>()\nconst BackendChromeContext = React.createContext<BackendChromeContextValue | null>(null)\n\nfunction buildCacheKey(api: string): string {\n return `${api}::scope:${getCurrentOrganizationScopeVersion()}`\n}\n\nexport function BackendChromeProvider({ adminNavApi, children }: BackendChromeProviderProps) {\n const cachedPayload = React.useMemo(() => {\n if (!adminNavApi) return null\n return chromeCache.get(buildCacheKey(adminNavApi)) ?? null\n }, [adminNavApi])\n const [payload, setPayload] = React.useState<BackendChromePayload | null>(cachedPayload)\n const [isLoading, setIsLoading] = React.useState(Boolean(adminNavApi && !cachedPayload))\n\n const refresh = React.useCallback(async () => {\n if (!adminNavApi) return\n setIsLoading(true)\n try {\n const call = await apiCall<BackendChromePayload>(adminNavApi, { credentials: 'include' as never })\n if (!call.ok || !call.result) return\n const nextPayload = call.result\n chromeCache.set(buildCacheKey(adminNavApi), nextPayload)\n setPayload(nextPayload)\n } catch {\n return\n } finally {\n setIsLoading(false)\n }\n }, [adminNavApi])\n\n React.useEffect(() => {\n if (!adminNavApi) {\n setPayload(null)\n setIsLoading(false)\n return\n }\n const cached = chromeCache.get(buildCacheKey(adminNavApi)) ?? null\n setPayload(cached)\n if (!cached) {\n void refresh()\n }\n }, [adminNavApi, refresh])\n\n React.useEffect(() => {\n if (!adminNavApi) return\n const onFocus = () => { void refresh() }\n const onManualRefresh = () => { void refresh() }\n const unsubscribeScope = subscribeOrganizationScopeChanged(() => {\n void refresh()\n })\n window.addEventListener('focus', onFocus)\n window.addEventListener('om:refresh-sidebar', onManualRefresh as EventListener)\n return () => {\n unsubscribeScope()\n window.removeEventListener('focus', onFocus)\n window.removeEventListener('om:refresh-sidebar', onManualRefresh as EventListener)\n }\n }, [adminNavApi, refresh])\n\n const value = React.useMemo<BackendChromeContextValue>(() => ({\n payload,\n isLoading,\n isReady: !adminNavApi || payload !== null,\n refresh,\n }), [adminNavApi, isLoading, payload, refresh])\n\n return (\n <BackendChromeContext.Provider value={value}>\n {children}\n </BackendChromeContext.Provider>\n )\n}\n\nexport function useBackendChrome(): BackendChromeContextValue {\n return React.useContext(BackendChromeContext) ?? {\n payload: null,\n isLoading: false,\n isReady: true,\n refresh: async () => {},\n }\n}\n"],
|
|
5
|
+
"mappings": ";AAuFI;AArFJ,YAAY,WAAW;AACvB,SAAS,eAAe;AACxB,SAAS,mCAAmC,0CAA0C;AAetF,MAAM,cAAc,oBAAI,IAAkC;AAC1D,MAAM,uBAAuB,MAAM,cAAgD,IAAI;AAEvF,SAAS,cAAc,KAAqB;AAC1C,SAAO,GAAG,GAAG,WAAW,mCAAmC,CAAC;AAC9D;AAEO,SAAS,sBAAsB,EAAE,aAAa,SAAS,GAA+B;AAC3F,QAAM,gBAAgB,MAAM,QAAQ,MAAM;AACxC,QAAI,CAAC,YAAa,QAAO;AACzB,WAAO,YAAY,IAAI,cAAc,WAAW,CAAC,KAAK;AAAA,EACxD,GAAG,CAAC,WAAW,CAAC;AAChB,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAsC,aAAa;AACvF,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,QAAQ,eAAe,CAAC,aAAa,CAAC;AAEvF,QAAM,UAAU,MAAM,YAAY,YAAY;AAC5C,QAAI,CAAC,YAAa;AAClB,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,OAAO,MAAM,QAA8B,aAAa,EAAE,aAAa,UAAmB,CAAC;AACjG,UAAI,CAAC,KAAK,MAAM,CAAC,KAAK,OAAQ;AAC9B,YAAM,cAAc,KAAK;AACzB,kBAAY,IAAI,cAAc,WAAW,GAAG,WAAW;AACvD,iBAAW,WAAW;AAAA,IACxB,QAAQ;AACN;AAAA,IACF,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,aAAa;AAChB,iBAAW,IAAI;AACf,mBAAa,KAAK;AAClB;AAAA,IACF;AACA,UAAM,SAAS,YAAY,IAAI,cAAc,WAAW,CAAC,KAAK;AAC9D,eAAW,MAAM;AACjB,QAAI,CAAC,QAAQ;AACX,WAAK,QAAQ;AAAA,IACf;AAAA,EACF,GAAG,CAAC,aAAa,OAAO,CAAC;AAEzB,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,YAAa;AAClB,UAAM,UAAU,MAAM;AAAE,WAAK,QAAQ;AAAA,IAAE;AACvC,UAAM,kBAAkB,MAAM;AAAE,WAAK,QAAQ;AAAA,IAAE;AAC/C,UAAM,mBAAmB,kCAAkC,MAAM;AAC/D,WAAK,QAAQ;AAAA,IACf,CAAC;AACD,WAAO,iBAAiB,SAAS,OAAO;AACxC,WAAO,iBAAiB,sBAAsB,eAAgC;AAC9E,WAAO,MAAM;AACX,uBAAiB;AACjB,aAAO,oBAAoB,SAAS,OAAO;AAC3C,aAAO,oBAAoB,sBAAsB,eAAgC;AAAA,IACnF;AAAA,EACF,GAAG,CAAC,aAAa,OAAO,CAAC;AAEzB,QAAM,QAAQ,MAAM,QAAmC,OAAO;AAAA,IAC5D;AAAA,IACA;AAAA,IACA,SAAS,CAAC,eAAe,YAAY;AAAA,IACrC;AAAA,EACF,IAAI,CAAC,aAAa,WAAW,SAAS,OAAO,CAAC;AAE9C,SACE,oBAAC,qBAAqB,UAArB,EAA8B,OAC5B,UACH;AAEJ;AAEO,SAAS,mBAA8C;AAC5D,SAAO,MAAM,WAAW,oBAAoB,KAAK;AAAA,IAC/C,SAAS;AAAA,IACT,WAAW;AAAA,IACX,SAAS;AAAA,IACT,SAAS,YAAY;AAAA,IAAC;AAAA,EACxB;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -769,7 +769,7 @@ function DataTable({
|
|
|
769
769
|
}, [injectionSpotId, perspective?.tableId]);
|
|
770
770
|
const resolvedInjectionSpotId = injectionSpotId ?? (perspective?.tableId ? `data-table:${perspective.tableId}` : null);
|
|
771
771
|
const resolvedReplacementHandle = replacementHandle ?? ComponentReplacementHandles.dataTable(extensionTableId ?? "unknown");
|
|
772
|
-
const
|
|
772
|
+
const baseInjectionContext = React.useMemo(
|
|
773
773
|
() => injectionContext ?? { tableId: perspective?.tableId ?? null, title: typeof title === "string" ? title : void 0 },
|
|
774
774
|
[injectionContext, perspective?.tableId, title]
|
|
775
775
|
);
|
|
@@ -781,6 +781,10 @@ function DataTable({
|
|
|
781
781
|
() => resolvedInjectionSpotId ? `${resolvedInjectionSpotId}:toolbar` : null,
|
|
782
782
|
[resolvedInjectionSpotId]
|
|
783
783
|
);
|
|
784
|
+
const searchTrailingInjectionSpotId = React.useMemo(
|
|
785
|
+
() => resolvedInjectionSpotId ? `${resolvedInjectionSpotId}:search-trailing` : null,
|
|
786
|
+
[resolvedInjectionSpotId]
|
|
787
|
+
);
|
|
784
788
|
const footerInjectionSpotId = React.useMemo(
|
|
785
789
|
() => resolvedInjectionSpotId ? `${resolvedInjectionSpotId}:footer` : null,
|
|
786
790
|
[resolvedInjectionSpotId]
|
|
@@ -1038,6 +1042,15 @@ function DataTable({
|
|
|
1038
1042
|
if (Object.keys(rowSelection).length === 0) return;
|
|
1039
1043
|
setRowSelection({});
|
|
1040
1044
|
}, [hasInjectedBulkActions, rowSelection]);
|
|
1045
|
+
const resolvedInjectionContext = React.useMemo(
|
|
1046
|
+
() => {
|
|
1047
|
+
if (!hasInjectedBulkActions) return baseInjectionContext;
|
|
1048
|
+
const selectedIds = Object.keys(rowSelection).filter((key) => rowSelection[key]);
|
|
1049
|
+
if (selectedIds.length === 0) return baseInjectionContext;
|
|
1050
|
+
return { ...baseInjectionContext, _selectedRowIds: selectedIds, _selectedCount: selectedIds.length };
|
|
1051
|
+
},
|
|
1052
|
+
[baseInjectionContext, hasInjectedBulkActions, rowSelection]
|
|
1053
|
+
);
|
|
1041
1054
|
React.useEffect(() => {
|
|
1042
1055
|
const ids = table.getAllLeafColumns().map((column) => column.id);
|
|
1043
1056
|
if (!ids.length) return;
|
|
@@ -1783,6 +1796,7 @@ function DataTable({
|
|
|
1783
1796
|
);
|
|
1784
1797
|
}) : null
|
|
1785
1798
|
] }) : null;
|
|
1799
|
+
const searchTrailingNode = searchTrailingInjectionSpotId && onSearchChange ? /* @__PURE__ */ jsx(InjectionSpot, { spotId: searchTrailingInjectionSpotId, context: resolvedInjectionContext }) : null;
|
|
1786
1800
|
return /* @__PURE__ */ jsx(
|
|
1787
1801
|
FilterBar,
|
|
1788
1802
|
{
|
|
@@ -1796,6 +1810,7 @@ function DataTable({
|
|
|
1796
1810
|
onClear: onFiltersClear,
|
|
1797
1811
|
leadingItems,
|
|
1798
1812
|
trailingItems,
|
|
1813
|
+
searchTrailing: searchTrailingNode,
|
|
1799
1814
|
filtersExtraContent: fieldsetSelector,
|
|
1800
1815
|
layout: embedded ? "inline" : "stacked",
|
|
1801
1816
|
className: embedded ? "min-h-[2.25rem]" : void 0
|
|
@@ -1827,7 +1842,9 @@ function DataTable({
|
|
|
1827
1842
|
selectedRows.length,
|
|
1828
1843
|
selectedRows,
|
|
1829
1844
|
runBulkAction,
|
|
1830
|
-
runPropBulkAction
|
|
1845
|
+
runPropBulkAction,
|
|
1846
|
+
searchTrailingInjectionSpotId,
|
|
1847
|
+
resolvedInjectionContext
|
|
1831
1848
|
]);
|
|
1832
1849
|
const hasTitle = title != null;
|
|
1833
1850
|
const hasActions = actions !== void 0 && actions !== null && actions !== false;
|