@fayz-ai/admin 0.22.1 → 0.23.0

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.
Files changed (124) hide show
  1. package/dist/{CommandPalette-GQ6SPITD.js → CommandPalette-ANZWU27U.js} +5 -5
  2. package/dist/CommandPalette-ANZWU27U.js.map +1 -0
  3. package/dist/ScheduleEditor-KU4UUG6Q.js +7 -0
  4. package/dist/ScheduleEditor-KU4UUG6Q.js.map +1 -0
  5. package/dist/SubscriptionPage-4EJCCS4I.js +8 -0
  6. package/dist/{SubscriptionPage-Y23PH6US.js.map → SubscriptionPage-4EJCCS4I.js.map} +1 -1
  7. package/dist/app/AdminShell.d.ts +2 -0
  8. package/dist/app/AdminShell.d.ts.map +1 -1
  9. package/dist/app/WrongAppGate.d.ts +46 -0
  10. package/dist/app/WrongAppGate.d.ts.map +1 -0
  11. package/dist/app/admin-app.d.ts.map +1 -1
  12. package/dist/app/app-config-cache.d.ts +13 -0
  13. package/dist/app/app-config-cache.d.ts.map +1 -0
  14. package/dist/app/contextual-nav.store.d.ts +7 -5
  15. package/dist/app/contextual-nav.store.d.ts.map +1 -1
  16. package/dist/app/nav-serving.d.ts +40 -0
  17. package/dist/app/nav-serving.d.ts.map +1 -0
  18. package/dist/app/nav-waiting.d.ts +23 -0
  19. package/dist/app/nav-waiting.d.ts.map +1 -0
  20. package/dist/app/rail-preset.d.ts +38 -0
  21. package/dist/app/rail-preset.d.ts.map +1 -0
  22. package/dist/app/scaffold.d.ts.map +1 -1
  23. package/dist/app/useAppPreset.d.ts +81 -0
  24. package/dist/app/useAppPreset.d.ts.map +1 -0
  25. package/dist/app/useDomainTenant.d.ts +32 -0
  26. package/dist/app/useDomainTenant.d.ts.map +1 -0
  27. package/dist/app/useTenantShell.d.ts +35 -0
  28. package/dist/app/useTenantShell.d.ts.map +1 -0
  29. package/dist/billing/index.js +2 -2
  30. package/dist/{chunk-YBLLTHYP.js → chunk-LB5SV4ZZ.js} +6 -6
  31. package/dist/{chunk-YBLLTHYP.js.map → chunk-LB5SV4ZZ.js.map} +1 -1
  32. package/dist/{ScheduleEditor-B7PLFGVM.js → chunk-NXFFJY2X.js} +44 -8
  33. package/dist/chunk-NXFFJY2X.js.map +1 -0
  34. package/dist/{chunk-NB6X5O5L.js → chunk-R4HQ2HS2.js} +22 -6
  35. package/dist/chunk-R4HQ2HS2.js.map +1 -0
  36. package/dist/{chunk-CTCK5JUQ.js → chunk-U3VX52SE.js} +4 -5
  37. package/dist/chunk-U3VX52SE.js.map +1 -0
  38. package/dist/{chunk-WJ3H3RJN.js → chunk-UQ2NTFQC.js} +4 -2
  39. package/dist/chunk-UQ2NTFQC.js.map +1 -0
  40. package/dist/{chunk-5GWUM4SM.js → chunk-W5IBKM3K.js} +3 -2
  41. package/dist/chunk-W5IBKM3K.js.map +1 -0
  42. package/dist/{chunk-ZKOWNGZT.js → chunk-XJB76FHA.js} +216 -72
  43. package/dist/chunk-XJB76FHA.js.map +1 -0
  44. package/dist/components/RightRail.d.ts.map +1 -1
  45. package/dist/components/chat/AgentAvatar.d.ts +6 -1
  46. package/dist/components/chat/AgentAvatar.d.ts.map +1 -1
  47. package/dist/components/chat/AssistantInvite.d.ts.map +1 -1
  48. package/dist/components/chat/ChatConversation.d.ts.map +1 -1
  49. package/dist/components/chat/ChatFab.d.ts.map +1 -1
  50. package/dist/components/layout/CommandPalette.d.ts +5 -1
  51. package/dist/components/layout/CommandPalette.d.ts.map +1 -1
  52. package/dist/components/layout/PrintChrome.d.ts.map +1 -1
  53. package/dist/components/right-rail.d.ts +2 -0
  54. package/dist/components/right-rail.d.ts.map +1 -1
  55. package/dist/components/settings/AddModulesPanel.d.ts +45 -0
  56. package/dist/components/settings/AddModulesPanel.d.ts.map +1 -0
  57. package/dist/components/settings/BrandingSettings.d.ts.map +1 -1
  58. package/dist/components/settings/ConnectedModulesSettings.d.ts +5 -0
  59. package/dist/components/settings/ConnectedModulesSettings.d.ts.map +1 -0
  60. package/dist/components/settings/ModuleCard.d.ts +26 -0
  61. package/dist/components/settings/ModuleCard.d.ts.map +1 -0
  62. package/dist/components/settings/ModulesSettings.d.ts +48 -0
  63. package/dist/components/settings/ModulesSettings.d.ts.map +1 -0
  64. package/dist/components/settings/SettingsPage.d.ts.map +1 -1
  65. package/dist/components/settings/module-catalog.d.ts +58 -0
  66. package/dist/components/settings/module-catalog.d.ts.map +1 -0
  67. package/dist/crud/CrudFormPage.d.ts.map +1 -1
  68. package/dist/crud/archetypes/OrderDetailView.d.ts +44 -0
  69. package/dist/crud/archetypes/OrderDetailView.d.ts.map +1 -1
  70. package/dist/directory/AppSwitcher.d.ts +6 -2
  71. package/dist/directory/AppSwitcher.d.ts.map +1 -1
  72. package/dist/hooks/useAppConfig.d.ts +8 -0
  73. package/dist/hooks/useAppConfig.d.ts.map +1 -1
  74. package/dist/hooks/useChat.d.ts.map +1 -1
  75. package/dist/hooks/useLayout.d.ts +4 -1
  76. package/dist/hooks/useLayout.d.ts.map +1 -1
  77. package/dist/index.d.ts +4 -1
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +2069 -980
  80. package/dist/index.js.map +1 -1
  81. package/dist/lib/agent-surface.d.ts +8 -1
  82. package/dist/lib/agent-surface.d.ts.map +1 -1
  83. package/dist/lib/ai-tool-handlers.d.ts.map +1 -1
  84. package/dist/lib/brand.d.ts +45 -0
  85. package/dist/lib/brand.d.ts.map +1 -1
  86. package/dist/lib/search-targets.d.ts.map +1 -1
  87. package/dist/org/OrgMark.d.ts +41 -0
  88. package/dist/org/OrgMark.d.ts.map +1 -0
  89. package/dist/org/WorkspaceChooser.d.ts +1 -0
  90. package/dist/org/WorkspaceChooser.d.ts.map +1 -1
  91. package/dist/org/WorkspaceChooserGate.d.ts.map +1 -1
  92. package/dist/org/WorkspaceSwitching.d.ts.map +1 -1
  93. package/dist/org/context.d.ts +13 -1
  94. package/dist/org/context.d.ts.map +1 -1
  95. package/dist/org/index.d.ts +2 -0
  96. package/dist/org/index.d.ts.map +1 -1
  97. package/dist/org/index.js +4 -4
  98. package/dist/org/switching.store.d.ts.map +1 -1
  99. package/dist/org/workspace-search.d.ts +27 -0
  100. package/dist/org/workspace-search.d.ts.map +1 -0
  101. package/dist/permissions/index.js +1 -1
  102. package/dist/permissions/store.d.ts +12 -0
  103. package/dist/permissions/store.d.ts.map +1 -1
  104. package/dist/setup/SetupAgentSurface.d.ts.map +1 -1
  105. package/dist/stores/app-config.store.d.ts +5 -1
  106. package/dist/stores/app-config.store.d.ts.map +1 -1
  107. package/dist/theme/dark.d.ts.map +1 -1
  108. package/dist/theme/light.d.ts.map +1 -1
  109. package/dist/theme/tokens.d.ts +13 -0
  110. package/dist/theme/tokens.d.ts.map +1 -1
  111. package/dist/theme/utils.d.ts.map +1 -1
  112. package/dist/units/UnitSwitcher.d.ts +10 -1
  113. package/dist/units/UnitSwitcher.d.ts.map +1 -1
  114. package/package.json +6 -6
  115. package/dist/CommandPalette-GQ6SPITD.js.map +0 -1
  116. package/dist/ScheduleEditor-B7PLFGVM.js.map +0 -1
  117. package/dist/SubscriptionPage-Y23PH6US.js +0 -8
  118. package/dist/chunk-5GWUM4SM.js.map +0 -1
  119. package/dist/chunk-CTCK5JUQ.js.map +0 -1
  120. package/dist/chunk-NB6X5O5L.js.map +0 -1
  121. package/dist/chunk-RKXZ7RUG.js +0 -20
  122. package/dist/chunk-RKXZ7RUG.js.map +0 -1
  123. package/dist/chunk-WJ3H3RJN.js.map +0 -1
  124. package/dist/chunk-ZKOWNGZT.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/schedule-service.ts","../src/crud/archetypes/BlockSettingsPopover.tsx","../src/crud/archetypes/ScheduleEditor.tsx"],"names":["useTranslation","useRef","jsx","jsxs","X","useState","useEffect"],"mappings":"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","file":"ScheduleEditor-B7PLFGVM.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Standalone Schedule CRUD Service\n// Works outside the agenda plugin context — uses Supabase directly.\n// ---------------------------------------------------------------------------\n\n// Core tables now live in the public schema — use the plain client directly.\nimport { getFayzSupabaseClient as getCoreClient } from '../data/client'\nimport { useOrganizationStore } from '../org'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ScheduleRecord {\n id: string\n tenantId: string\n kind: string\n assigneeId: string | null\n locationId: string | null\n dayOfWeek: number | null\n specificDate: string | null\n startsAt: string\n endsAt: string\n isActive: boolean\n metadata: Record<string, unknown>\n}\n\nexport interface SaveScheduleInput {\n assigneeId: string\n locationId?: string\n dayOfWeek?: number\n specificDate?: string\n startsAt: string\n endsAt: string\n isActive?: boolean\n kind?: string\n}\n\n/** Advanced settings stored per schedule block in the metadata jsonb column. */\nexport interface BlockSettings {\n bufferMinutes?: number\n allowedServiceIds?: string[]\n maxConcurrent?: number\n minAdvanceHours?: number\n maxAdvanceDays?: number\n label?: string\n locationId?: string\n}\n\n/** Extract BlockSettings from a schedule record's metadata. */\nexport function parseBlockSettings(metadata: Record<string, unknown>): BlockSettings {\n return {\n bufferMinutes: typeof metadata.bufferMinutes === 'number' ? metadata.bufferMinutes : undefined,\n allowedServiceIds: Array.isArray(metadata.allowedServiceIds) ? metadata.allowedServiceIds : undefined,\n maxConcurrent: typeof metadata.maxConcurrent === 'number' ? metadata.maxConcurrent : undefined,\n minAdvanceHours: typeof metadata.minAdvanceHours === 'number' ? metadata.minAdvanceHours : undefined,\n maxAdvanceDays: typeof metadata.maxAdvanceDays === 'number' ? metadata.maxAdvanceDays : undefined,\n label: typeof metadata.label === 'string' ? metadata.label : undefined,\n locationId: typeof metadata.locationId === 'string' ? metadata.locationId : undefined,\n }\n}\n\n/** Merge BlockSettings into existing metadata object. */\nexport function mergeBlockSettings(metadata: Record<string, unknown>, settings: BlockSettings): Record<string, unknown> {\n const merged = { ...metadata }\n // Only set defined values, remove undefined ones to keep metadata clean\n for (const [key, value] of Object.entries(settings)) {\n if (value !== undefined && value !== null && !(Array.isArray(value) && value.length === 0)) {\n merged[key] = value\n } else {\n delete merged[key]\n }\n }\n return merged\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getTenantId(): string {\n const id = useOrganizationStore.getState().currentOrg?.id\n if (!id) throw new Error('No active tenant')\n return id\n}\n\nfunction mapRow(row: Record<string, unknown>): ScheduleRecord {\n const r: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(row)) {\n r[key.replace(/_([a-z])/g, (_, c) => c.toUpperCase())] = value\n }\n return r as unknown as ScheduleRecord\n}\n\n// ---------------------------------------------------------------------------\n// Service functions\n// ---------------------------------------------------------------------------\n\nexport async function getSchedules(\n assigneeId: string,\n kind = 'working_hours',\n): Promise<ScheduleRecord[]> {\n const core = getCoreClient()\n const { data, error } = await core\n .from('schedules')\n .select('*')\n .eq('kind', kind)\n .eq('assignee_id', assigneeId)\n .order('day_of_week')\n .order('starts_at')\n\n if (error) throw error\n return (data ?? []).map(mapRow)\n}\n\nexport async function saveSchedule(input: SaveScheduleInput): Promise<ScheduleRecord> {\n const core = getCoreClient()\n const tenantId = getTenantId()\n\n const { data, error } = await core\n .from('schedules')\n .insert({\n tenant_id: tenantId,\n kind: input.kind ?? 'working_hours',\n assignee_id: input.assigneeId,\n location_id: input.locationId ?? null,\n day_of_week: input.dayOfWeek ?? null,\n specific_date: input.specificDate ?? null,\n starts_at: input.startsAt,\n ends_at: input.endsAt,\n is_active: input.isActive ?? true,\n })\n .select('*')\n .single()\n\n if (error) throw error\n return mapRow(data as Record<string, unknown>)\n}\n\nexport async function deleteSchedule(id: string): Promise<void> {\n const core = getCoreClient()\n const { error } = await core.from('schedules').delete().eq('id', id)\n if (error) throw error\n}\n\n/**\n * Replace all weekly schedules (day_of_week based) for an assignee.\n * Deletes existing weekly entries and creates new ones in a single flow.\n */\nexport async function replaceWeeklySchedules(\n assigneeId: string,\n week: Record<number, { enabled: boolean; periods: { startsAt: string; endsAt: string; settings?: BlockSettings }[] }>,\n kind = 'working_hours',\n): Promise<void> {\n const core = getCoreClient()\n const tenantId = getTenantId()\n\n // Delete existing weekly schedules (day_of_week NOT NULL, specific_date IS NULL)\n const { error: delErr } = await core\n .from('schedules')\n .delete()\n .eq('assignee_id', assigneeId)\n .eq('kind', kind)\n .not('day_of_week', 'is', null)\n .is('specific_date', null)\n\n if (delErr) throw delErr\n\n // Build insert rows\n const rows: Record<string, unknown>[] = []\n for (const [dayStr, day] of Object.entries(week)) {\n if (!day.enabled) continue\n for (const period of day.periods) {\n const metadata = period.settings ? mergeBlockSettings({}, period.settings) : {}\n rows.push({\n tenant_id: tenantId,\n kind,\n assignee_id: assigneeId,\n day_of_week: Number(dayStr),\n specific_date: null,\n starts_at: period.startsAt,\n ends_at: period.endsAt,\n is_active: true,\n metadata,\n })\n }\n }\n\n if (rows.length > 0) {\n const { error: insErr } = await core.from('schedules').insert(rows)\n if (insErr) throw insErr\n }\n}\n\n/**\n * Enumerate all dates in a range (inclusive).\n */\nfunction eachDate(startDate: string, endDate: string): string[] {\n const dates: string[] = []\n const current = new Date(startDate + 'T00:00:00Z')\n const end = new Date(endDate + 'T00:00:00Z')\n while (current <= end) {\n dates.push(current.toISOString().slice(0, 10))\n current.setUTCDate(current.getUTCDate() + 1)\n }\n return dates\n}\n\n/**\n * Save a date-range exception.\n * type: 'unavailable' marks days off, 'available' sets custom hours.\n * Stores notes and range info in metadata for retrieval.\n */\nexport async function saveException(input: {\n assigneeId: string\n startDate: string\n endDate: string\n type: 'available' | 'unavailable'\n periods: { startsAt: string; endsAt: string }[]\n notes?: string\n settings?: BlockSettings\n kind?: string\n}): Promise<void> {\n const core = getCoreClient()\n const tenantId = getTenantId()\n const kind = input.kind ?? 'working_hours'\n const dates = eachDate(input.startDate, input.endDate)\n const isRange = dates.length > 1\n const meta = mergeBlockSettings(\n {\n ...(input.notes ? { notes: input.notes } : {}),\n ...(isRange ? { rangeStart: input.startDate, rangeEnd: input.endDate } : {}),\n exceptionType: input.type,\n },\n input.settings ?? {},\n )\n\n // Delete existing exceptions for all dates in range (single query)\n const { error: delErr } = await core\n .from('schedules')\n .delete()\n .eq('assignee_id', input.assigneeId)\n .eq('kind', kind)\n .in('specific_date', dates)\n if (delErr) throw delErr\n\n const rows: Record<string, unknown>[] = []\n\n if (input.type === 'unavailable') {\n // One sentinel row per date with is_active: false\n for (const date of dates) {\n rows.push({\n tenant_id: tenantId,\n kind,\n assignee_id: input.assigneeId,\n day_of_week: null,\n specific_date: date,\n starts_at: '00:00',\n ends_at: '00:00',\n is_active: false,\n metadata: meta,\n })\n }\n } else {\n // Custom available hours for each date\n for (const date of dates) {\n for (const p of input.periods) {\n rows.push({\n tenant_id: tenantId,\n kind,\n assignee_id: input.assigneeId,\n day_of_week: null,\n specific_date: date,\n starts_at: p.startsAt,\n ends_at: p.endsAt,\n is_active: true,\n metadata: meta,\n })\n }\n }\n }\n\n if (rows.length > 0) {\n const { error } = await core.from('schedules').insert(rows)\n if (error) throw error\n }\n}\n\n/**\n * Delete an exception by its start date.\n * If it was part of a range, deletes all dates in that range.\n */\nexport async function deleteException(\n assigneeId: string,\n startDate: string,\n endDate?: string,\n kind = 'working_hours',\n): Promise<void> {\n const core = getCoreClient()\n const dates = eachDate(startDate, endDate ?? startDate)\n const { error } = await core\n .from('schedules')\n .delete()\n .eq('assignee_id', assigneeId)\n .eq('kind', kind)\n .in('specific_date', dates)\n if (error) throw error\n}\n","import React, { useRef, useEffect, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport { X, ChevronDown } from 'lucide-react'\nimport type { BlockSettings } from '../../lib/schedule-service'\nimport type { ScheduleBlockConfig } from '../../lib/schedule-config'\nimport { useTranslation } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Props\n// ---------------------------------------------------------------------------\n\ninterface BlockSettingsPopoverProps {\n settings: BlockSettings\n onChange: (settings: BlockSettings) => void\n config: ScheduleBlockConfig\n /** Ref to the trigger element for positioning */\n triggerRef: React.RefObject<HTMLElement | null>\n open: boolean\n onClose: () => void\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function BlockSettingsPopover({\n settings,\n onChange,\n config,\n triggerRef,\n open,\n onClose,\n}: BlockSettingsPopoverProps) {\n const t = useTranslation()\n const popoverRef = useRef<HTMLDivElement>(null)\n const [pos, setPos] = useState({ top: 0, left: 0 })\n\n useEffect(() => {\n if (!open || !triggerRef.current) return\n const rect = triggerRef.current.getBoundingClientRect()\n const popW = 280\n let left = rect.left + rect.width / 2 - popW / 2\n if (left + popW > window.innerWidth - 12) left = window.innerWidth - popW - 12\n if (left < 8) left = 8\n setPos({ top: rect.bottom + 6, left })\n }, [open, triggerRef])\n\n useEffect(() => {\n if (!open) return\n const handler = (e: MouseEvent) => {\n if (popoverRef.current?.contains(e.target as Node)) return\n if (triggerRef.current?.contains(e.target as Node)) return\n onClose()\n }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n }, [open, onClose, triggerRef])\n\n if (!open) return null\n\n const showServices = config.showServices !== false && config.services && config.services.length > 0\n const showConcurrent = config.showConcurrent !== false\n const showBookingWindow = config.showBookingWindow !== false\n const showLocations = config.showLocations === true && config.locations && config.locations.length > 0\n\n function update(patch: Partial<BlockSettings>) {\n onChange({ ...settings, ...patch })\n }\n\n return createPortal(\n <div\n ref={popoverRef}\n style={{ position: 'fixed', top: pos.top, left: pos.left, zIndex: 9999 }}\n className=\"fayz-glass-surface w-[280px] rounded-xl border bg-popover shadow-xl\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-3 py-2.5 border-b\">\n <span className=\"text-xs font-semibold\">{t('schedule.blockSettings.title')}</span>\n <button type=\"button\" onClick={onClose} className=\"p-0.5 rounded text-muted-foreground hover:text-foreground\">\n <X className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n\n <div className=\"p-3 space-y-3\">\n {/* Location select */}\n {showLocations && (\n <LocationSelect\n locations={config.locations!}\n value={settings.locationId}\n onChange={(id) => update({ locationId: id || undefined })}\n />\n )}\n\n {/* Services multi-select */}\n {showServices && (\n <ServiceSelect\n services={config.services!}\n selected={settings.allowedServiceIds ?? []}\n onChange={(ids) => update({ allowedServiceIds: ids.length > 0 ? ids : undefined })}\n />\n )}\n\n {/* Max concurrent */}\n {showConcurrent && (\n <div>\n <label className=\"text-[11px] font-medium text-muted-foreground\">{t('schedule.blockSettings.maxConcurrent')}</label>\n <div className=\"flex items-center gap-2 mt-1\">\n <button\n type=\"button\"\n onClick={() => update({ maxConcurrent: Math.max(1, (settings.maxConcurrent ?? config.defaults.maxConcurrent) - 1) })}\n className=\"flex h-7 w-7 items-center justify-center rounded-md border text-sm hover:bg-muted bg-card shadow-button active:shadow-button-inset transition-colors\"\n >\n -\n </button>\n <span className=\"text-sm font-medium w-6 text-center\">\n {settings.maxConcurrent ?? config.defaults.maxConcurrent}\n </span>\n <button\n type=\"button\"\n onClick={() => update({ maxConcurrent: (settings.maxConcurrent ?? config.defaults.maxConcurrent) + 1 })}\n className=\"flex h-7 w-7 items-center justify-center rounded-md border text-sm hover:bg-muted bg-card shadow-button active:shadow-button-inset transition-colors\"\n >\n +\n </button>\n </div>\n </div>\n )}\n\n {/* Booking window */}\n {showBookingWindow && (\n <div className=\"grid grid-cols-2 gap-2\">\n <div>\n <label className=\"text-[11px] font-medium text-muted-foreground\">{t('schedule.blockSettings.minAdvance')}</label>\n <div className=\"flex items-center gap-1 mt-1\">\n <input\n type=\"number\"\n min={0}\n value={settings.minAdvanceHours ?? config.defaults.minAdvanceHours}\n onChange={(e) => update({ minAdvanceHours: Number(e.target.value) || 0 })}\n className=\"w-full rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2 py-1 text-xs tabular-nums\"\n />\n <span className=\"text-[10px] text-muted-foreground shrink-0\">{t('schedule.blockSettings.hrs')}</span>\n </div>\n </div>\n <div>\n <label className=\"text-[11px] font-medium text-muted-foreground\">{t('schedule.blockSettings.maxAdvance')}</label>\n <div className=\"flex items-center gap-1 mt-1\">\n <input\n type=\"number\"\n min={1}\n value={settings.maxAdvanceDays ?? config.defaults.maxAdvanceDays}\n onChange={(e) => update({ maxAdvanceDays: Number(e.target.value) || 30 })}\n className=\"w-full rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2 py-1 text-xs tabular-nums\"\n />\n <span className=\"text-[10px] text-muted-foreground shrink-0\">{t('schedule.blockSettings.days')}</span>\n </div>\n </div>\n </div>\n )}\n\n {/* Label */}\n <div>\n <label className=\"text-[11px] font-medium text-muted-foreground\">{t('schedule.blockSettings.label')}</label>\n <input\n type=\"text\"\n value={settings.label ?? ''}\n onChange={(e) => update({ label: e.target.value || undefined })}\n placeholder={t('schedule.blockSettings.labelPlaceholder')}\n className=\"mt-1 w-full rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2 py-1 text-xs placeholder:text-muted-foreground/40\"\n />\n </div>\n </div>\n </div>,\n document.body,\n )\n}\n\n// ---------------------------------------------------------------------------\n// Service multi-select (simple dropdown with checkboxes)\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// Location select (custom dropdown)\n// ---------------------------------------------------------------------------\n\nfunction LocationSelect({\n locations,\n value,\n onChange,\n}: {\n locations: { id: string; name: string }[]\n value: string | undefined\n onChange: (id: string) => void\n}) {\n const t = useTranslation()\n const [open, setOpen] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (!open) return\n const handler = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false) }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n }, [open])\n\n const current = value ? locations.find((l) => l.id === value) : null\n const label = current ? current.name : t('schedule.blockSettings.noLocation')\n\n return (\n <div ref={ref} className=\"relative\">\n <label className=\"text-[11px] font-medium text-muted-foreground\">{t('schedule.blockSettings.location')}</label>\n <button\n type=\"button\"\n onClick={() => setOpen((p) => !p)}\n className=\"mt-1 flex items-center justify-between w-full rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2 py-1.5 text-xs hover:bg-muted/30 transition-colors\"\n >\n <span className={current ? '' : 'text-muted-foreground'}>{label}</span>\n <ChevronDown className=\"h-3 w-3 text-muted-foreground\" />\n </button>\n {open && (\n <div className=\"fayz-glass-surface absolute top-full left-0 z-10 mt-1 w-full max-h-40 overflow-y-auto rounded-lg border bg-popover shadow-lg py-1\">\n <button\n type=\"button\"\n onClick={() => { onChange(''); setOpen(false) }}\n className={`block w-full px-2.5 py-1.5 text-xs text-left transition-colors ${!value ? 'bg-primary/10 text-primary font-medium' : 'hover:bg-muted/50'}`}\n >\n {t('schedule.blockSettings.noLocation')}\n </button>\n {locations.map((l) => (\n <button\n key={l.id}\n type=\"button\"\n onClick={() => { onChange(l.id); setOpen(false) }}\n className={`block w-full px-2.5 py-1.5 text-xs text-left transition-colors ${l.id === value ? 'bg-primary/10 text-primary font-medium' : 'hover:bg-muted/50'}`}\n >\n {l.name}\n </button>\n ))}\n </div>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Service multi-select (simple dropdown with checkboxes)\n// ---------------------------------------------------------------------------\n\nfunction ServiceSelect({\n services,\n selected,\n onChange,\n}: {\n services: { id: string; name: string }[]\n selected: string[]\n onChange: (ids: string[]) => void\n}) {\n const t = useTranslation()\n const [open, setOpen] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (!open) return\n const handler = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false) }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n }, [open])\n\n const allSelected = selected.length === 0\n const label = allSelected\n ? t('schedule.blockSettings.allServices')\n : selected.length === 1\n ? services.find((s) => s.id === selected[0])?.name ?? t('schedule.blockSettings.oneService')\n : t('schedule.blockSettings.nServices', { count: selected.length })\n\n function toggle(id: string) {\n onChange(selected.includes(id) ? selected.filter((s) => s !== id) : [...selected, id])\n }\n\n return (\n <div ref={ref} className=\"relative\">\n <label className=\"text-[11px] font-medium text-muted-foreground\">{t('schedule.blockSettings.allowedServices')}</label>\n <button\n type=\"button\"\n onClick={() => setOpen((p) => !p)}\n className=\"mt-1 flex items-center justify-between w-full rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2 py-1.5 text-xs hover:bg-muted/30 transition-colors\"\n >\n <span className={allSelected ? 'text-muted-foreground' : ''}>{label}</span>\n <ChevronDown className=\"h-3 w-3 text-muted-foreground\" />\n </button>\n {open && (\n <div className=\"fayz-glass-surface absolute top-full left-0 z-10 mt-1 w-full max-h-40 overflow-y-auto rounded-lg border bg-popover shadow-lg py-1\">\n <button\n type=\"button\"\n onClick={() => onChange([])}\n className={`block w-full px-2.5 py-1.5 text-xs text-left transition-colors ${allSelected ? 'bg-primary/10 text-primary font-medium' : 'hover:bg-muted/50'}`}\n >\n {t('schedule.blockSettings.allServices')}\n </button>\n {services.map((s) => {\n const checked = selected.includes(s.id)\n return (\n <button\n key={s.id}\n type=\"button\"\n onClick={() => toggle(s.id)}\n className={`flex items-center gap-2 w-full px-2.5 py-1.5 text-xs text-left transition-colors ${checked ? 'bg-primary/5' : 'hover:bg-muted/50'}`}\n >\n <span className={`flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-sm border ${\n checked ? 'border-primary bg-primary text-primary-foreground' : 'border-muted-foreground/30'\n }`}>\n {checked && <svg className=\"h-2.5 w-2.5\" viewBox=\"0 0 12 12\" fill=\"none\"><path d=\"M2 6l3 3 5-5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/></svg>}\n </span>\n <span className=\"truncate\">{s.name}</span>\n </button>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n","import React, { useEffect, useState, useCallback, useRef, useSyncExternalStore } from 'react'\nimport { Clock, Plus, Trash2, Copy, Save, CalendarOff, CalendarPlus, Check, Settings, X } from 'lucide-react'\nimport { toast } from '@fayz-ai/ui'\nimport {\n getSchedules,\n replaceWeeklySchedules,\n saveException,\n deleteException,\n parseBlockSettings,\n} from '../../lib/schedule-service'\nimport type { ScheduleRecord, BlockSettings } from '../../lib/schedule-service'\nimport { getScheduleBlockConfig, subscribeScheduleBlockConfig } from '../../lib/schedule-config'\nimport type { ScheduleBlockConfig } from '../../lib/schedule-config'\nimport { useTranslation } from '@fayz-ai/core'\nimport { BlockSettingsPopover } from './BlockSettingsPopover'\nimport { Card, CardContent } from '@fayz-ai/ui'\nimport { Button } from '@fayz-ai/ui'\nimport { Badge } from '@fayz-ai/ui'\nimport { Skeleton } from '@fayz-ai/ui'\nimport { DatePicker } from '@fayz-ai/ui'\nimport { TimePicker } from '@fayz-ai/ui'\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@fayz-ai/ui'\nimport { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, ModalTitle, ModalDescription } from '@fayz-ai/ui'\nimport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@fayz-ai/ui'\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DAY_KEYS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']\nconst WEEK_ORDER = [1, 2, 3, 4, 5, 6, 0] // Mon–Sun display order\n\ninterface Period {\n id?: string\n startsAt: string\n endsAt: string\n settings?: BlockSettings\n}\n\ninterface DaySchedule {\n enabled: boolean\n periods: Period[]\n}\n\ntype WeekSchedule = Record<number, DaySchedule>\n\ninterface ExceptionEntry {\n startDate: string\n endDate: string\n type: 'available' | 'unavailable'\n periods: { startsAt: string; endsAt: string }[]\n notes: string\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction schedulesToWeek(schedules: ScheduleRecord[]): WeekSchedule {\n const week: WeekSchedule = {}\n for (let i = 0; i < 7; i++) {\n week[i] = { enabled: false, periods: [] }\n }\n for (const s of schedules) {\n if (s.dayOfWeek == null || s.specificDate != null) continue\n const day = week[s.dayOfWeek]\n if (s.isActive) {\n day.enabled = true\n const settings = parseBlockSettings(s.metadata ?? {})\n const hasSettings = Object.values(settings).some((v) => v !== undefined)\n day.periods.push({\n id: s.id,\n startsAt: s.startsAt,\n endsAt: s.endsAt,\n settings: hasSettings ? settings : undefined,\n })\n }\n }\n for (const day of Object.values(week)) {\n day.periods.sort((a, b) => a.startsAt.localeCompare(b.startsAt))\n }\n return week\n}\n\nfunction schedulesToExceptions(schedules: ScheduleRecord[]): ExceptionEntry[] {\n // Group by range key (rangeStart–rangeEnd or single date)\n const map = new Map<string, ExceptionEntry>()\n for (const s of schedules) {\n if (!s.specificDate) continue\n const meta = (s.metadata ?? {}) as Record<string, unknown>\n const rangeStart = (meta.rangeStart as string) ?? s.specificDate\n const rangeEnd = (meta.rangeEnd as string) ?? s.specificDate\n const key = `${rangeStart}__${rangeEnd}`\n const exType = (meta.exceptionType as string) === 'available' ? 'available' : 'unavailable'\n const notes = (meta.notes as string) ?? ''\n\n const existing = map.get(key)\n if (!existing) {\n map.set(key, {\n startDate: rangeStart,\n endDate: rangeEnd,\n type: exType,\n periods: s.isActive ? [{ startsAt: s.startsAt, endsAt: s.endsAt }] : [],\n notes,\n })\n } else if (s.isActive && s.specificDate === rangeStart) {\n existing.periods.push({ startsAt: s.startsAt, endsAt: s.endsAt })\n }\n }\n return Array.from(map.values()).sort((a, b) => a.startDate.localeCompare(b.startDate))\n}\n\nfunction formatDate(dateStr: string): string {\n const d = new Date(dateStr + 'T00:00:00')\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' })\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// PeriodRow — single time block as a horizontal row\n// ---------------------------------------------------------------------------\n\ninterface PeriodRowProps {\n period: Period\n dayOfWeek: number\n blockConfig: ScheduleBlockConfig | null\n settingsOpen: boolean\n onUpdateTime: (field: 'startsAt' | 'endsAt', value: string) => void\n onUpdateBuffer: (value: number) => void\n onUpdateSettings: (settings: BlockSettings) => void\n onRemove: () => void\n onAddBlock: () => void\n onCopyToAll: () => void\n onToggleSettings: () => void\n onCloseSettings: () => void\n}\n\nfunction PeriodRow({\n period, blockConfig, dayOfWeek,\n settingsOpen, onUpdateTime, onUpdateBuffer, onUpdateSettings,\n onRemove, onCopyToAll, onToggleSettings, onCloseSettings,\n onAddBlock,\n}: PeriodRowProps) {\n const t = useTranslation()\n const gearRef = useRef<HTMLButtonElement>(null)\n const bufferValue = period.settings?.bufferMinutes ?? blockConfig?.defaults.bufferMinutes ?? 0\n const hasCustomSettings = period.settings && Object.entries(period.settings).some(\n ([k, v]) => k !== 'bufferMinutes' && v !== undefined,\n )\n const dayName = t(`schedule.days.${DAY_KEYS[dayOfWeek]}`)\n\n return (\n <TooltipProvider delayDuration={300}>\n <div className=\"flex items-center gap-1.5 group\">\n {/* Label */}\n {period.settings?.label && (\n <span className=\"text-[10px] font-medium text-primary bg-primary/10 rounded-full px-2 py-0.5 shrink-0\">\n {period.settings.label}\n </span>\n )}\n\n {/* Time range */}\n <TimePicker value={period.startsAt} onChange={(v) => onUpdateTime('startsAt', v)} interval={30} className=\"w-[90px]\" />\n <span className=\"text-xs text-muted-foreground/50\">-</span>\n <TimePicker value={period.endsAt} onChange={(v) => onUpdateTime('endsAt', v)} interval={30} min={period.startsAt} className=\"w-[90px]\" />\n\n {/* Buffer pill */}\n <Tooltip>\n <TooltipTrigger asChild>\n <div className=\"flex items-center gap-1 rounded-full border bg-muted/30 px-2 py-1 shrink-0\">\n <input\n type=\"number\"\n min={0}\n max={120}\n value={bufferValue}\n onChange={(e) => onUpdateBuffer(Number(e.target.value) || 0)}\n className=\"w-8 bg-transparent text-xs text-center tabular-nums outline-none\"\n />\n <span className=\"text-[10px] text-muted-foreground\">{t('schedule.editor.min')}</span>\n </div>\n </TooltipTrigger>\n <TooltipContent>{t('schedule.editor.bufferTooltip')}</TooltipContent>\n </Tooltip>\n\n {/* Actions */}\n <div className=\"flex items-center gap-0.5 shrink-0 ml-auto\">\n <Tooltip>\n <TooltipTrigger asChild>\n <button type=\"button\" onClick={onRemove}\n className=\"p-1.5 rounded-md text-muted-foreground/30 hover:text-destructive hover:bg-destructive/5 transition-colors\">\n <X className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>{t('schedule.editor.removeInterval')}</TooltipContent>\n </Tooltip>\n\n <Tooltip>\n <TooltipTrigger asChild>\n <button type=\"button\" onClick={onAddBlock}\n className=\"p-1.5 rounded-md text-muted-foreground/30 hover:text-foreground hover:bg-muted transition-colors\">\n <Plus className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>{t('schedule.editor.newInterval', { day: dayName })}</TooltipContent>\n </Tooltip>\n\n <Tooltip>\n <TooltipTrigger asChild>\n <button type=\"button\" onClick={onCopyToAll}\n className=\"p-1.5 rounded-md text-muted-foreground/30 hover:text-foreground hover:bg-muted transition-colors\">\n <Copy className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>{t('schedule.editor.copyToAll')}</TooltipContent>\n </Tooltip>\n\n {blockConfig && (\n <Tooltip>\n <TooltipTrigger asChild>\n <button ref={gearRef} type=\"button\" onClick={onToggleSettings}\n className={`p-1.5 rounded-md transition-colors ${\n hasCustomSettings\n ? 'text-primary bg-primary/5'\n : 'text-muted-foreground/30 hover:text-foreground hover:bg-muted'\n }`}>\n <Settings className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>{t('schedule.blockSettings.title')}</TooltipContent>\n </Tooltip>\n )}\n </div>\n\n {/* Settings popover */}\n {blockConfig && (\n <BlockSettingsPopover\n settings={period.settings ?? {}}\n onChange={onUpdateSettings}\n config={blockConfig}\n triggerRef={gearRef}\n open={settingsOpen}\n onClose={onCloseSettings}\n />\n )}\n </div>\n </TooltipProvider>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Main Component\n// ---------------------------------------------------------------------------\n\ninterface ScheduleEditorProps {\n assigneeId: string\n}\n\nexport function ScheduleEditor({ assigneeId }: ScheduleEditorProps) {\n const t = useTranslation()\n const [week, setWeek] = useState<WeekSchedule>({})\n const [exceptions, setExceptions] = useState<ExceptionEntry[]>([])\n const [loading, setLoading] = useState(true)\n const [saving, setSaving] = useState(false)\n const [showAddException, setShowAddException] = useState(false)\n const blockConfig = useSyncExternalStore(subscribeScheduleBlockConfig, getScheduleBlockConfig)\n const [settingsPopover, setSettingsPopover] = useState<{ dayOfWeek: number; idx: number } | null>(null)\n const [weekDirty, setWeekDirty] = useState(false)\n\n // Lazy-fetch locations when showLocations is enabled but locations aren't loaded yet\n useEffect(() => {\n if (blockConfig?.showLocations && (!blockConfig.locations || blockConfig.locations.length === 0) && blockConfig.fetchLocations) {\n blockConfig.fetchLocations().catch(() => {})\n }\n }, [blockConfig?.showLocations, blockConfig?.locations?.length])\n\n // New exception form state\n const [newExStartDate, setNewExStartDate] = useState('')\n const [newExEndDate, setNewExEndDate] = useState('')\n const [newExType, setNewExType] = useState<'unavailable' | 'available'>('unavailable')\n const [newExPeriods, setNewExPeriods] = useState([{ startsAt: '09:00', endsAt: '17:00' }])\n const [newExNotes, setNewExNotes] = useState('')\n const [savingException, setSavingException] = useState(false)\n\n const loadData = useCallback(async () => {\n setLoading(true)\n try {\n const data = await getSchedules(assigneeId)\n setWeek(schedulesToWeek(data))\n setExceptions(schedulesToExceptions(data))\n setWeekDirty(false)\n } catch {\n toast.error(t('schedule.editor.failedToLoad'))\n }\n setLoading(false)\n }, [assigneeId])\n\n useEffect(() => {\n loadData()\n }, [loadData])\n\n // --- Weekly hours handlers ---\n\n function markDirty() { setWeekDirty(true) }\n\n function toggleDay(dayOfWeek: number) {\n markDirty()\n setWeek((prev) => ({\n ...prev,\n [dayOfWeek]: {\n ...prev[dayOfWeek],\n enabled: !prev[dayOfWeek]?.enabled,\n periods: prev[dayOfWeek]?.enabled ? [] : [{ startsAt: '09:00', endsAt: '18:00' }],\n },\n }))\n }\n\n function updatePeriod(dayOfWeek: number, idx: number, field: 'startsAt' | 'endsAt', value: string) {\n markDirty()\n setWeek((prev) => {\n const day = { ...prev[dayOfWeek] }\n const periods = [...day.periods]\n periods[idx] = { ...periods[idx], [field]: value }\n return { ...prev, [dayOfWeek]: { ...day, periods } }\n })\n }\n\n function addPeriod(dayOfWeek: number) {\n markDirty()\n setWeek((prev) => {\n const day = { ...prev[dayOfWeek] }\n const last = day.periods[day.periods.length - 1]\n day.periods = [...day.periods, { startsAt: last?.endsAt ?? '13:00', endsAt: '18:00' }]\n return { ...prev, [dayOfWeek]: day }\n })\n }\n\n function removePeriod(dayOfWeek: number, idx: number) {\n markDirty()\n setWeek((prev) => {\n const day = { ...prev[dayOfWeek] }\n day.periods = day.periods.filter((_, i) => i !== idx)\n if (day.periods.length === 0) day.enabled = false\n return { ...prev, [dayOfWeek]: day }\n })\n }\n\n function updatePeriodSettings(dayOfWeek: number, idx: number, settings: BlockSettings) {\n markDirty()\n setWeek((prev) => {\n const day = { ...prev[dayOfWeek] }\n const periods = [...day.periods]\n periods[idx] = { ...periods[idx], settings }\n return { ...prev, [dayOfWeek]: { ...day, periods } }\n })\n }\n\n function updateBufferMinutes(dayOfWeek: number, idx: number, value: number) {\n markDirty()\n setWeek((prev) => {\n const day = { ...prev[dayOfWeek] }\n const periods = [...day.periods]\n const existing = periods[idx].settings ?? {}\n periods[idx] = { ...periods[idx], settings: { ...existing, bufferMinutes: value || undefined } }\n return { ...prev, [dayOfWeek]: { ...day, periods } }\n })\n }\n\n function copyToAll(sourceDayOfWeek: number) {\n markDirty()\n const source = week[sourceDayOfWeek]\n if (!source) return\n setWeek((prev) => {\n const next = { ...prev }\n for (let i = 0; i < 7; i++) {\n if (i === sourceDayOfWeek) continue\n next[i] = {\n enabled: source.enabled,\n periods: source.periods.map((p) => ({ startsAt: p.startsAt, endsAt: p.endsAt, settings: p.settings ? { ...p.settings } : undefined })),\n }\n }\n return next\n })\n }\n\n async function handleSaveWeekly() {\n setSaving(true)\n try {\n await replaceWeeklySchedules(assigneeId, week)\n toast.success(t('schedule.editor.saved'))\n loadData()\n } catch (err: any) {\n toast.error(t('schedule.editor.failedToSave'), { description: err?.message })\n }\n setSaving(false)\n }\n\n // --- Exception handlers ---\n\n async function handleAddException() {\n if (!newExStartDate) {\n toast.error(t('schedule.editor.selectStartDate'))\n return\n }\n const endDate = newExEndDate || newExStartDate\n if (endDate < newExStartDate) {\n toast.error(t('schedule.editor.endDateAfterStart'))\n return\n }\n setSavingException(true)\n try {\n await saveException({\n assigneeId,\n startDate: newExStartDate,\n endDate,\n type: newExType,\n periods: newExType === 'unavailable' ? [] : newExPeriods,\n notes: newExNotes || undefined,\n })\n toast.success(t('schedule.editor.exceptionAdded'))\n setShowAddException(false)\n setNewExStartDate('')\n setNewExEndDate('')\n setNewExType('unavailable')\n setNewExPeriods([{ startsAt: '09:00', endsAt: '17:00' }])\n setNewExNotes('')\n loadData()\n } catch (err: any) {\n toast.error(t('schedule.editor.failedToSaveException'), { description: err?.message })\n }\n setSavingException(false)\n }\n\n async function handleDeleteException(startDate: string, endDate: string) {\n try {\n await deleteException(assigneeId, startDate, endDate)\n toast.success(t('schedule.editor.exceptionRemoved'))\n loadData()\n } catch (err: any) {\n toast.error(t('schedule.editor.failedToDelete'), { description: err?.message })\n }\n }\n\n // --- Render ---\n\n if (loading) {\n return (\n <div className=\"fz-fields fz-fields-2 gap-6\">\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <Skeleton className=\"h-9 w-9 rounded-lg\" />\n <div className=\"space-y-1.5\"><Skeleton className=\"h-4 w-36\" /><Skeleton className=\"h-3 w-48\" /></div>\n </div>\n <Skeleton className=\"h-8 w-20 rounded-md\" />\n </div>\n <Card>\n <CardContent className=\"p-0 divide-y\">\n {Array.from({ length: 7 }).map((_, i) => (\n <div key={i} className=\"flex items-center gap-3 px-4 py-3\">\n <Skeleton className=\"h-5 w-5 rounded-full\" />\n <Skeleton className=\"h-4 w-8\" />\n {i < 5 ? (\n <>\n <Skeleton className=\"h-8 w-24 rounded-lg\" />\n <Skeleton className=\"h-3 w-3\" />\n <Skeleton className=\"h-8 w-24 rounded-lg\" />\n </>\n ) : (\n <Skeleton className=\"h-4 w-20\" />\n )}\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <Skeleton className=\"h-9 w-9 rounded-lg\" />\n <div className=\"space-y-1.5\"><Skeleton className=\"h-4 w-32\" /><Skeleton className=\"h-3 w-44\" /></div>\n </div>\n <Skeleton className=\"h-8 w-32 rounded-md\" />\n </div>\n <Card><CardContent className=\"flex items-center justify-center py-8\"><Skeleton className=\"h-3 w-48\" /></CardContent></Card>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"fz-fields fz-fields-2 gap-6\">\n {/* ---- Weekly Working Hours ---- */}\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-9 w-9 items-center justify-center rounded-lg bg-primary/10\">\n <Clock className=\"h-4 w-4 text-primary\" />\n </div>\n <div>\n <h3 className=\"text-sm font-semibold\">{t('schedule.editor.weeklyTitle')}</h3>\n <p className=\"text-xs text-muted-foreground\">{t('schedule.editor.weeklyDescription')}</p>\n </div>\n </div>\n {weekDirty && (\n <Button size=\"sm\" onClick={handleSaveWeekly} disabled={saving}>\n <Save className=\"h-4 w-4 mr-1.5\" />\n {saving ? t('common.saving') : t('common.save')}\n </Button>\n )}\n </div>\n\n {/* Day rows */}\n <Card>\n <CardContent className=\"p-0 divide-y\">\n {WEEK_ORDER.map((dayOfWeek) => {\n const day = week[dayOfWeek] ?? { enabled: false, periods: [] }\n return (\n <div\n key={dayOfWeek}\n className={`flex items-start gap-4 px-4 py-3 transition-colors ${day.enabled ? '' : 'bg-muted/20'}`}\n >\n {/* Day toggle checkbox + label */}\n <button\n type=\"button\"\n onClick={() => toggleDay(dayOfWeek)}\n className=\"flex items-center gap-2.5 w-20 shrink-0 pt-1.5\"\n >\n <span className={`flex h-5 w-5 shrink-0 items-center justify-center rounded-full transition-all ${\n day.enabled\n ? 'bg-primary text-primary-foreground shadow-sm'\n : 'border-2 border-muted-foreground/25 hover:border-muted-foreground/40'\n }`}>\n {day.enabled && <Check className=\"h-3 w-3\" strokeWidth={3} />}\n </span>\n <span className={`text-sm font-medium ${day.enabled ? '' : 'text-muted-foreground/40'}`}>\n {t(`schedule.days.${DAY_KEYS[dayOfWeek]}`)}\n </span>\n </button>\n\n {/* Content */}\n {day.enabled ? (\n <div className=\"flex-1 space-y-2\">\n {day.periods.map((period, idx) => (\n <PeriodRow\n key={idx}\n period={period}\n dayOfWeek={dayOfWeek}\n blockConfig={blockConfig}\n settingsOpen={settingsPopover?.dayOfWeek === dayOfWeek && settingsPopover?.idx === idx}\n onUpdateTime={(field, v) => updatePeriod(dayOfWeek, idx, field, v)}\n onUpdateBuffer={(v) => updateBufferMinutes(dayOfWeek, idx, v)}\n onUpdateSettings={(s) => updatePeriodSettings(dayOfWeek, idx, s)}\n onRemove={() => removePeriod(dayOfWeek, idx)}\n onAddBlock={() => addPeriod(dayOfWeek)}\n onCopyToAll={() => copyToAll(dayOfWeek)}\n onToggleSettings={() => setSettingsPopover(\n settingsPopover?.dayOfWeek === dayOfWeek && settingsPopover?.idx === idx ? null : { dayOfWeek, idx }\n )}\n onCloseSettings={() => setSettingsPopover(null)}\n />\n ))}\n </div>\n ) : (\n <TooltipProvider delayDuration={300}>\n <div className=\"flex items-center gap-2 pt-1.5\">\n <span className=\"text-sm text-muted-foreground/40\">{t('schedule.editor.unavailable')}</span>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={() => toggleDay(dayOfWeek)}\n className=\"flex h-6 w-6 items-center justify-center rounded-full border border-muted-foreground/25 text-muted-foreground/40 hover:border-foreground/40 hover:text-foreground hover:bg-muted transition-colors\"\n >\n <Plus className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>{t('schedule.editor.addHoursFor', { day: t(`schedule.days.${DAY_KEYS[dayOfWeek]}`) })}</TooltipContent>\n </Tooltip>\n </div>\n </TooltipProvider>\n )}\n </div>\n )\n })}\n </CardContent>\n </Card>\n </div>\n\n {/* ---- Date Exceptions ---- */}\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-9 w-9 items-center justify-center rounded-lg bg-orange-500/10\">\n <CalendarOff className=\"h-4 w-4 text-orange-600\" />\n </div>\n <div>\n <h3 className=\"text-sm font-semibold\">{t('schedule.editor.exceptionsTitle')}</h3>\n <p className=\"text-xs text-muted-foreground\">{t('schedule.editor.exceptionsDescription')}</p>\n </div>\n </div>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => setShowAddException(true)}\n >\n <CalendarPlus className=\"h-4 w-4 mr-1.5\" />\n {t('schedule.editor.addException')}\n </Button>\n </div>\n\n {/* Add exception modal */}\n <Modal open={showAddException} onOpenChange={setShowAddException}>\n <ModalContent size=\"md\">\n <ModalHeader>\n <ModalTitle>{t('schedule.editor.addException')}</ModalTitle>\n <ModalDescription>{t('schedule.editor.exceptionsDescription')}</ModalDescription>\n </ModalHeader>\n\n <ModalBody className=\"space-y-5\">\n {/* Date range */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-xs font-medium text-muted-foreground mb-1.5 block\">{t('schedule.editor.startDate')}</label>\n <DatePicker\n value={newExStartDate}\n onChange={(v) => {\n setNewExStartDate(v)\n if (!newExEndDate || v > newExEndDate) setNewExEndDate(v)\n }}\n />\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground mb-1.5 block\">{t('schedule.editor.endDate')}</label>\n <DatePicker\n value={newExEndDate || newExStartDate}\n onChange={setNewExEndDate}\n />\n </div>\n </div>\n\n {/* Type — segmented tabs */}\n <div>\n <label className=\"text-xs font-medium text-muted-foreground mb-1.5 block\">{t('schedule.editor.type')}</label>\n <Tabs value={newExType} onValueChange={(v) => setNewExType(v as 'unavailable' | 'available')}>\n <TabsList className=\"h-9 w-full\">\n <TabsTrigger value=\"unavailable\" className=\"text-xs gap-1.5 flex-1\">\n <CalendarOff className=\"h-3.5 w-3.5\" />\n {t('schedule.editor.unavailable')}\n </TabsTrigger>\n <TabsTrigger value=\"available\" className=\"text-xs gap-1.5 flex-1\">\n <Clock className=\"h-3.5 w-3.5\" />\n {t('schedule.editor.customHours')}\n </TabsTrigger>\n </TabsList>\n </Tabs>\n </div>\n\n {/* Custom hours — only when type=available */}\n {newExType === 'available' && (\n <div className=\"space-y-3\">\n <label className=\"text-xs font-medium text-muted-foreground\">{t('schedule.editor.workingHours')}</label>\n {newExPeriods.map((period, idx) => (\n <div key={idx} className=\"flex items-center gap-3\">\n <TimePicker\n value={period.startsAt}\n onChange={(v) => {\n const updated = [...newExPeriods]\n updated[idx] = { ...updated[idx], startsAt: v }\n setNewExPeriods(updated)\n }}\n interval={30}\n className=\"flex-1\"\n />\n <span className=\"text-xs text-muted-foreground shrink-0\">{t('schedule.editor.to')}</span>\n <TimePicker\n value={period.endsAt}\n onChange={(v) => {\n const updated = [...newExPeriods]\n updated[idx] = { ...updated[idx], endsAt: v }\n setNewExPeriods(updated)\n }}\n interval={30}\n min={period.startsAt}\n className=\"flex-1\"\n />\n {newExPeriods.length > 1 && (\n <button\n type=\"button\"\n onClick={() => setNewExPeriods(newExPeriods.filter((_, i) => i !== idx))}\n className=\"p-1.5 rounded-md text-muted-foreground hover:text-destructive hover:bg-destructive/5 transition-colors shrink-0\"\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n </button>\n )}\n </div>\n ))}\n <button\n type=\"button\"\n onClick={() => {\n const last = newExPeriods[newExPeriods.length - 1]\n setNewExPeriods([...newExPeriods, { startsAt: last?.endsAt ?? '13:00', endsAt: '18:00' }])\n }}\n className=\"flex items-center gap-1 text-xs text-primary hover:underline\"\n >\n <Plus className=\"h-3 w-3\" /> {t('schedule.editor.addTimeBlock')}\n </button>\n </div>\n )}\n\n {/* Notes */}\n <div>\n <label className=\"text-xs font-medium text-muted-foreground mb-1.5 block\">{t('schedule.editor.notes')}</label>\n <input\n type=\"text\"\n value={newExNotes}\n onChange={(e) => setNewExNotes(e.target.value)}\n placeholder={t('schedule.editor.notesPlaceholder')}\n className=\"block w-full rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm placeholder:text-muted-foreground/40 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1\"\n />\n </div>\n </ModalBody>\n\n <ModalFooter>\n <Button variant=\"ghost\" onClick={() => setShowAddException(false)}>\n {t('common.cancel')}\n </Button>\n <Button onClick={handleAddException} disabled={savingException}>\n <Save className=\"h-3.5 w-3.5 mr-1.5\" />\n {savingException ? t('common.saving') : t('schedule.editor.saveException')}\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n\n {/* Exception list */}\n {exceptions.length > 0 ? (\n <Card>\n <CardContent className=\"p-0 divide-y\">\n {exceptions.map((ex) => {\n const isRange = ex.startDate !== ex.endDate\n const dateLabel = isRange\n ? `${formatDate(ex.startDate)} — ${formatDate(ex.endDate)}`\n : formatDate(ex.startDate)\n return (\n <div key={ex.startDate + ex.endDate} className=\"flex items-center justify-between px-4 py-3 group\">\n <div className=\"flex items-center gap-3 min-w-0\">\n {/* Type indicator dot */}\n <span className={`h-2.5 w-2.5 shrink-0 rounded-full ${\n ex.type === 'unavailable' ? 'bg-destructive' : 'bg-success'\n }`} />\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span className=\"text-sm font-medium\">{dateLabel}</span>\n <Badge variant=\"secondary\" className=\"text-[10px]\">\n {ex.type === 'unavailable' ? t('schedule.editor.unavailable') : t('schedule.editor.customHours')}\n </Badge>\n {ex.type === 'available' && ex.periods.length > 0 && (\n <span className=\"text-xs text-muted-foreground\">\n {ex.periods.map((p) => `${p.startsAt} — ${p.endsAt}`).join(', ')}\n </span>\n )}\n </div>\n {ex.notes && (\n <p className=\"text-xs text-muted-foreground mt-0.5 truncate\">{ex.notes}</p>\n )}\n </div>\n </div>\n <button\n type=\"button\"\n onClick={() => handleDeleteException(ex.startDate, ex.endDate)}\n className=\"p-1.5 rounded-md text-muted-foreground hover:text-destructive hover:bg-destructive/5 transition-colors shrink-0 ml-2\"\n title={t('schedule.editor.removeException')}\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n )\n })}\n </CardContent>\n </Card>\n ) : (\n !showAddException && (\n <Card>\n <CardContent className=\"flex items-center justify-center py-8 text-sm text-muted-foreground\">\n {t('schedule.editor.noExceptions')}\n </CardContent>\n </Card>\n )\n )}\n </div>\n </div>\n )\n}\n"]}
@@ -1,8 +0,0 @@
1
- export { SubscriptionPage } from './chunk-YBLLTHYP.js';
2
- import './chunk-YUHCC7JY.js';
3
- import './chunk-CTCK5JUQ.js';
4
- import './chunk-NB6X5O5L.js';
5
- import './chunk-WJ3H3RJN.js';
6
- import './chunk-5GWUM4SM.js';
7
- //# sourceMappingURL=SubscriptionPage-Y23PH6US.js.map
8
- //# sourceMappingURL=SubscriptionPage-Y23PH6US.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/org/store.ts"],"names":[],"mappings":";;;;AAGA,IAAM,WAAA,GAAc,kBAAA;AAMpB,SAAS,iBAAA,GAAmC;AAC1C,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,YAAA,KAAiB,WAAA,EAAa,OAAO,IAAA;AAChD,IAAA,OAAO,YAAA,CAAa,QAAQ,WAAW,CAAA;AAAA,EACzC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,aAAa,KAAA,EAA4B;AAChD,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACzC,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,YAAA,CAAa,OAAA,CAAQ,aAAa,KAAK,CAAA;AAAA,IACzC,CAAA,MAAO;AACL,MAAA,YAAA,CAAa,WAAW,WAAW,CAAA;AAAA,IACrC;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAuBO,IAAM,oBAAA,GAAuB,MAAA,CAAiB,CAAC,GAAA,MAAS;AAAA,EAC7D,UAAA,EAAY,IAAA;AAAA,EACZ,UAAU,EAAC;AAAA,EACX,SAAS,EAAC;AAAA,EACV,iBAAiB,EAAC;AAAA,EAClB,OAAA,EAAS,KAAA;AAAA,EAET,aAAA,EAAe,CAAC,GAAA,KAAQ;AACtB,IAAA,iBAAA,CAAkB,KAAK,EAAE,CAAA;AACzB,IAAA,YAAA,CAAa,GAAA,EAAK,MAAM,IAAI,CAAA;AAC5B,IAAA,GAAA,CAAI,EAAE,UAAA,EAAY,GAAA,EAAK,CAAA;AAAA,EACzB,CAAA;AAAA,EACA,aAAa,CAAC,IAAA,KAAS,IAAI,EAAE,QAAA,EAAU,MAAM,CAAA;AAAA,EAC7C,YAAY,CAAC,OAAA,KAAY,GAAA,CAAI,EAAE,SAAS,CAAA;AAAA,EACxC,oBAAoB,CAAC,KAAA,KAAU,IAAI,EAAE,eAAA,EAAiB,OAAO,CAAA;AAAA,EAC7D,YAAY,CAAC,OAAA,KAAY,GAAA,CAAI,EAAE,SAAS,CAAA;AAAA,EACxC,OAAO,MAAM;AACX,IAAA,iBAAA,CAAkB,MAAS,CAAA;AAU3B,IAAA,GAAA,CAAI,EAAE,UAAA,EAAY,IAAA,EAAM,QAAA,EAAU,EAAC,EAAG,OAAA,EAAS,EAAC,EAAG,OAAA,EAAS,KAAA,EAAO,CAAA;AAAA,EACrE;AACF,CAAA,CAAE","file":"chunk-5GWUM4SM.js","sourcesContent":["import { create } from 'zustand'\nimport { setActiveTenantId, type Organization, type OrgMember, type OrgMembership } from '@fayz-ai/core'\n\nconst STORAGE_KEY = 'fayz:current-org'\n\n// ---------------------------------------------------------------------------\n// Persistence helpers\n// ---------------------------------------------------------------------------\n\nfunction getPersistedOrgId(): string | null {\n try {\n if (typeof localStorage === 'undefined') return null\n return localStorage.getItem(STORAGE_KEY)\n } catch {\n return null\n }\n}\n\nfunction persistOrgId(orgId: string | null): void {\n try {\n if (typeof localStorage === 'undefined') return\n if (orgId) {\n localStorage.setItem(STORAGE_KEY, orgId)\n } else {\n localStorage.removeItem(STORAGE_KEY)\n }\n } catch {\n // ignore\n }\n}\n\n// ---------------------------------------------------------------------------\n// Store interface\n// ---------------------------------------------------------------------------\n\nexport interface OrgStore {\n currentOrg: Organization | null\n userOrgs: OrgMembership[]\n members: OrgMember[]\n /** Person `kind`s that make up the team (from config.team.personKinds). Drives\n * the Person-first Team screen; empty = legacy membership-only mode. */\n teamPersonKinds: string[]\n loading: boolean\n\n setCurrentOrg: (org: Organization | null) => void\n setUserOrgs: (orgs: OrgMembership[]) => void\n setMembers: (members: OrgMember[]) => void\n setTeamPersonKinds: (kinds: string[]) => void\n setLoading: (loading: boolean) => void\n reset: () => void\n}\n\nexport const useOrganizationStore = create<OrgStore>((set) => ({\n currentOrg: null,\n userOrgs: [],\n members: [],\n teamPersonKinds: [],\n loading: false,\n\n setCurrentOrg: (org) => {\n setActiveTenantId(org?.id)\n persistOrgId(org?.id ?? null)\n set({ currentOrg: org })\n },\n setUserOrgs: (orgs) => set({ userOrgs: orgs }),\n setMembers: (members) => set({ members }),\n setTeamPersonKinds: (kinds) => set({ teamPersonKinds: kinds }),\n setLoading: (loading) => set({ loading }),\n reset: () => {\n setActiveTenantId(undefined)\n // NOTE: do NOT clear the persisted org id here. The org providers call\n // reset() whenever the auth store transiently reports `user === null` —\n // which happens on every fresh load while the Supabase session hydrates\n // asynchronously. Wiping 'fayz:current-org' at that moment drops a\n // multi-org user's workspace selection BEFORE loadOrgs can read it back,\n // so the app always falls to memberships[0] on reload (single-org users\n // never noticed). The pin is a last-selected hint that's re-validated\n // against the fresh membership list on load, so it's safe to keep across\n // sign-out too (a mismatching pin just falls back to memberships[0]).\n set({ currentOrg: null, userOrgs: [], members: [], loading: false })\n },\n}))\n\nexport { getPersistedOrgId, persistOrgId }\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/billing/store.ts","../src/billing/plan-badge.ts","../src/billing/trial.ts","../src/app/routing.tsx","../src/billing/TrialWidget.tsx"],"names":["paidPlanIds","named","React2"],"mappings":"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","file":"chunk-CTCK5JUQ.js","sourcesContent":["import { create } from 'zustand'\nimport type { Plan, BillingCheckoutFn } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface Subscription {\n id: string\n orgId: string\n planId: string\n status: 'active' | 'trialing' | 'past_due' | 'canceled' | 'incomplete'\n currentPeriodStart: string\n currentPeriodEnd: string\n cancelAtPeriodEnd?: boolean\n stripeSubscriptionId?: string\n}\n\nexport interface Invoice {\n id: string\n orgId: string\n amount: number\n currency: string\n status: 'paid' | 'open' | 'void' | 'uncollectible'\n pdfUrl?: string\n createdAt: string\n}\n\nexport interface BillingState {\n subscription: Subscription | null\n invoices: Invoice[]\n plans: Plan[]\n loading: boolean\n /** Payment-gateway seam seeded from `config.billing.onCheckout` (see core\n * BillingConfig). When set, the Subscription page routes plan changes through\n * it instead of writing `plan` straight onto the org. */\n checkout: BillingCheckoutFn | null\n}\n\n// ---------------------------------------------------------------------------\n// Store\n// ---------------------------------------------------------------------------\n\nexport interface BillingStore extends BillingState {\n setSubscription: (subscription: Subscription | null) => void\n setInvoices: (invoices: Invoice[]) => void\n setPlans: (plans: Plan[]) => void\n setLoading: (loading: boolean) => void\n setCheckout: (checkout: BillingCheckoutFn | null) => void\n reset: () => void\n}\n\nconst initialState: BillingState = {\n subscription: null,\n invoices: [],\n plans: [],\n loading: false,\n checkout: null,\n}\n\nexport const useBillingStore = create<BillingStore>((set) => ({\n ...initialState,\n setSubscription: (subscription) => set({ subscription }),\n setInvoices: (invoices) => set({ invoices }),\n setPlans: (plans) => set({ plans }),\n setLoading: (loading) => set({ loading }),\n setCheckout: (checkout) => set({ checkout }),\n reset: () => set(initialState),\n}))\n","import type { Plan } from '@fayz-ai/core'\n\nexport interface PlanBadgeInfo {\n /** Display label, e.g. 'Free' or 'Pro'. */\n label: string\n /** Resolved plan id (falls back to the raw org.plan string). */\n planId: string\n /** Paid plan (price > 0) — drives the Crown icon + gold styling in the menus. */\n paid: boolean\n}\n\nfunction capitalize(s: string): string {\n return s ? s.charAt(0).toUpperCase() + s.slice(1) : s\n}\n\n/**\n * Resolve an org's `plan` string against the configured billing plans into the\n * badge shown next to the user in both menus. Falls back to a capitalized\n * version of the raw string when the id isn't in config (defensive — e.g. a\n * legacy 'free' tenant before billing was wired).\n */\nexport function resolvePlanBadge(\n planId: string | undefined | null,\n plans: Plan[],\n): PlanBadgeInfo {\n const id = planId || 'free'\n const match = plans.find((p) => p.id === id)\n if (match) {\n return { label: match.name, planId: match.id, paid: match.price > 0 }\n }\n return { label: capitalize(id), planId: id, paid: false }\n}\n","import * as React from 'react'\nimport type { Organization, Plan } from '@fayz-ai/core'\nimport { useOrganizationStore } from '../org/store'\nimport { useBillingStore } from './store'\n\n/**\n * The free trial, as one derived fact.\n *\n * A trial is not a fourth plan or a state machine — it is a WINDOW during which\n * a tenant on the free plan is entitled to a paid one. Modelling it that way is\n * what keeps it out of every gate in the product: the access provider resolves\n * the effective plan once, and the nav crowns, the entitlement gates, the limit\n * caps and the assistant's lock all follow without knowing a trial exists.\n *\n * `trialEndsAt` is written by the database when the tenant is created (see\n * migration 147) and is never written by the client — a trial the browser could\n * extend is not a trial. A tenant with no `trialEndsAt` predates the column and\n * is left alone: status `none`, plan exactly as stored.\n */\n\nexport type TrialStatus = 'none' | 'active' | 'expired'\n\nexport interface TrialState {\n status: TrialStatus\n /** ISO date the window closes. */\n endsAt?: string\n /** Whole days remaining, floored at 0. `0` on the last day, not a negative. */\n daysLeft: number\n /** The last 48 hours, when the banner stops being informational. */\n endingSoon: boolean\n}\n\nexport const NO_TRIAL: TrialState = { status: 'none', daysLeft: 0, endingSoon: false }\n\nconst DAY_MS = 86_400_000\n\n/** Pure — the part worth testing, and it needs neither React nor a clock. */\nexport function resolveTrial(\n org: Pick<Organization, 'plan' | 'trialEndsAt'> | null | undefined,\n paidPlanIds: ReadonlySet<string>,\n now: number = Date.now(),\n): TrialState {\n if (!org?.trialEndsAt) return NO_TRIAL\n // Somebody who is paying is not on a trial, whatever the column still says.\n if (org.plan && paidPlanIds.has(org.plan)) return NO_TRIAL\n\n const ends = Date.parse(org.trialEndsAt)\n if (Number.isNaN(ends)) return NO_TRIAL\n\n const remaining = ends - now\n if (remaining <= 0) return { status: 'expired', endsAt: org.trialEndsAt, daysLeft: 0, endingSoon: false }\n\n const daysLeft = Math.ceil(remaining / DAY_MS)\n return {\n status: 'active',\n endsAt: org.trialEndsAt,\n daysLeft,\n endingSoon: remaining <= 2 * DAY_MS,\n }\n}\n\n/**\n * The plan whose entitlements apply RIGHT NOW.\n *\n * During the trial that is the trial plan — by default the most expensive one\n * configured, because the point of a trial is to be worth losing. After it, the\n * tenant's own plan, which for a free tenant is the free one: that fall is the\n * paywall, and it needs no separate enforcement path.\n *\n * ── Por que um plano desconhecido cai no piso, e não em `null` ──────────────\n * A frase acima (\"essa queda é o paywall\") só era verdade quando o id gravado\n * em `tenants.plan` existia no catálogo do app. Quando não existia — o\n * ChefControl vendia `starter/professional/enterprise` enquanto o pool grava\n * `free/pro/business` — isto devolvia `null`, e `null` não é \"sem plano\": é SEM\n * TETO. `resolveLimit` lê teto ausente como ilimitado e `isEntitledByPlan` só\n * nega com um `false` explícito. O resultado é que vencer o trial LIBERAVA em\n * vez de travar, que é o oposto do paywall.\n *\n * Então um id que o catálogo não conhece cai no plano mais barato — o piso é a\n * resposta segura para \"não sei em que plano esta conta está\". `null` fica\n * reservado para o único caso em que ilimitado é a leitura certa: o app que não\n * vende plano nenhum e portanto não tem o que travar.\n */\nexport function effectivePlan(\n org: Pick<Organization, 'plan'> | null | undefined,\n plans: Plan[],\n trial: TrialState,\n trialPlanId?: string,\n): Plan | null {\n if (trial.status === 'active') {\n const named = trialPlanId ? plans.find((p) => p.id === trialPlanId) : undefined\n if (named) return named\n const paid = plans.filter((p) => p.price > 0)\n if (paid.length) return paid.reduce((best, p) => (p.price > best.price ? p : best))\n }\n if (plans.length === 0) return null\n\n const named = org?.plan ? plans.find((p) => p.id === org.plan) : undefined\n if (named) return named\n\n const floor = plans.reduce((cheapest, p) => (p.price < cheapest.price ? p : cheapest))\n if (org?.plan) {\n // Avisa alto: é um defeito de dados (catálogo e pool discordando), e quem\n // vê primeiro é quem estiver com o console aberto.\n console.warn(\n `[billing] tenant plan \"${org.plan}\" não existe neste catálogo (${plans.map((p) => p.id).join(', ')}) — aplicando o piso \"${floor.id}\"`,\n )\n }\n return floor\n}\n\n/** Ids of the plans somebody actually pays for. */\nexport function paidPlanIds(plans: Plan[]): Set<string> {\n return new Set(plans.filter((p) => p.price > 0).map((p) => p.id))\n}\n\n/**\n * Live trial state for the current workspace.\n *\n * Ticks once an hour rather than on a timer per second: nothing on screen\n * counts down in real time, and a banner that says \"2 days left\" only has to be\n * right the next time somebody looks at it.\n */\nexport function useTrial(): TrialState {\n const org = useOrganizationStore((s) => s.currentOrg)\n const plans = useBillingStore((s) => s.plans)\n const [now, setNow] = React.useState(() => Date.now())\n\n React.useEffect(() => {\n const id = window.setInterval(() => setNow(Date.now()), 3_600_000)\n return () => window.clearInterval(id)\n }, [])\n\n return React.useMemo(\n () => resolveTrial(org, paidPlanIds(plans), now),\n [org?.plan, org?.trialEndsAt, plans, now],\n )\n}\n","import * as React from 'react'\nimport { hashRouterAdapter } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Admin hash router — the same lightweight approach the storefront uses. The\n// admin shell collects routes from the plugin runtime + manifest pages and\n// switches on the current hash path. Deliberately not react-router: an SDK\n// shell shipping a router creates singleton hazards under source-alias dev.\n// ---------------------------------------------------------------------------\n\nconst adapter = hashRouterAdapter()\n\nexport function normalizeAdminPath(path: string): string {\n const clean = `/${path}`.replace(/\\/+/g, '/')\n return clean.length > 1 ? clean.replace(/\\/+$/, '') : clean\n}\n\nexport function navigateTo(to: string): void {\n adapter.navigate(normalizeAdminPath(to))\n}\n\nexport function useAdminPath(): string {\n const [path, setPath] = React.useState(() => normalizeAdminPath(adapter.getCurrentPath() || '/'))\n React.useEffect(() => {\n return adapter.onPathChange((p) => {\n setPath(normalizeAdminPath(p || '/'))\n if (typeof window !== 'undefined') window.scrollTo(0, 0)\n })\n }, [])\n return path\n}\n\n/** Match '/courses/:id' against '/courses/abc' → { id: 'abc' }; supports a\n * trailing '/*' wildcard (matches the base and any deeper path). */\nexport function matchRoute(pattern: string, path: string): Record<string, string> | null {\n const cleanPath = (path.split('?')[0] ?? '').replace(/\\/+$/, '') || '/'\n if (pattern.endsWith('/*')) {\n const base = pattern.slice(0, -2)\n if (cleanPath === base || cleanPath.startsWith(`${base}/`)) return {}\n return null\n }\n const patternParts = pattern.split('/').filter(Boolean)\n const pathParts = cleanPath.split('/').filter(Boolean)\n if (patternParts.length !== pathParts.length) return null\n const params: Record<string, string> = {}\n for (let i = 0; i < patternParts.length; i++) {\n const pat = patternParts[i]!\n const part = pathParts[i]!\n if (pat.startsWith(':')) params[pat.slice(1)] = decodeURIComponent(part)\n else if (pat !== part) return null\n }\n return params\n}\n\n/** Score a route pattern for specificity so the most specific match wins\n * (static segments beat params; longer beats shorter; wildcard loses). */\nexport function routeScore(pattern: string): number {\n const isWildcard = pattern.endsWith('/*')\n const routePattern = isWildcard ? pattern.slice(0, -2) : pattern\n const parts = routePattern.split('/').filter(Boolean)\n let score = parts.length * 10\n for (const p of parts) if (!p.startsWith(':')) score += 5\n if (isWildcard) score -= 1\n return score\n}\n","import * as React from 'react'\nimport { Clock, Crown } from 'lucide-react'\nimport { tl } from '@fayz-ai/core'\nimport { cn } from '../lib/cn'\nimport { navigateTo } from '../app/routing'\nimport { useLayoutStore } from '@fayz-ai/ui'\nimport { useTrial } from './trial'\n\nexport interface TrialWidgetProps {\n /** Length of the window, for the progress bar. Matches the DB column default (migration 044). */\n totalDays?: number\n /** Where \"see the plans\" goes. */\n route?: string\n className?: string\n}\n\n/**\n * The trial, in the rail.\n *\n * A countdown is a promise about the future, so it belongs where somebody looks\n * at their own progress — one line under the getting-started checklist, in the\n * menu's own colours, not a banner across the app. Two states only:\n *\n * • RUNNING — informational, and quiet until the last two days.\n * • ENDED — the paywall's face. It stops being a note and becomes a button,\n * because at that point every gated feature in the product is already\n * answering \"not on your plan\" and this is the one place that says why.\n *\n * There is no third state: a paying tenant, or one that predates trials, gets\n * nothing at all.\n */\nexport function TrialWidget({ totalDays = 30, route = '/settings/subscription', className }: TrialWidgetProps) {\n const trial = useTrial()\n const collapsed = useLayoutStore((s) => s.sidebarCollapsed)\n\n if (trial.status === 'none') return null\n\n const expired = trial.status === 'expired'\n const pct = Math.max(0, Math.min(100, (trial.daysLeft / totalDays) * 100))\n\n const label = expired\n ? tl('Trial ended', 'Seu teste terminou')\n : trial.daysLeft <= 1\n ? tl('Last day of your trial', 'Último dia do teste')\n : tl(`${trial.daysLeft} days of trial left`, `${trial.daysLeft} dias de teste`)\n\n if (collapsed) {\n return (\n <button\n type=\"button\"\n onClick={() => navigateTo(route)}\n title={label}\n aria-label={label}\n data-tour=\"billing.trial\"\n className={cn(\n 'flex w-full items-center justify-center rounded-button p-1.5 transition-colors',\n expired\n ? 'bg-primary/15 text-primary hover:bg-primary/25'\n : 'text-sidebar-foreground/70 hover:bg-sidebar-accent/60',\n className,\n )}\n >\n {expired ? <Crown className=\"h-4 w-4\" /> : <Clock className=\"h-4 w-4\" />}\n </button>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={() => navigateTo(route)}\n data-tour=\"billing.trial\"\n className={cn(\n 'w-full rounded-button px-1.5 py-1.5 text-left transition-colors',\n expired ? 'bg-primary/15 hover:bg-primary/25' : 'hover:bg-sidebar-accent/50',\n className,\n )}\n >\n <span className=\"flex items-center gap-2\">\n {expired\n ? <Crown className=\"h-3.5 w-3.5 shrink-0 text-primary\" />\n : <Clock className={cn('h-3.5 w-3.5 shrink-0', trial.endingSoon ? 'text-warning' : 'text-sidebar-muted')} />}\n <span\n className={cn(\n 'min-w-0 flex-1 truncate text-[12px] font-medium',\n expired ? 'text-sidebar-foreground' : 'text-sidebar-foreground/90',\n )}\n >\n {label}\n </span>\n </span>\n {expired ? (\n <span className=\"mt-1 block pl-[22px] text-[11px] leading-snug text-sidebar-muted\">\n {tl('Choose a plan to keep the assistant', 'Escolha um plano para manter o assistente')}\n </span>\n ) : (\n <span className=\"mt-1.5 block h-1 overflow-hidden rounded-full bg-sidebar-accent\">\n <span\n className={cn(\n 'block h-full rounded-full transition-all',\n trial.endingSoon ? 'bg-warning' : 'bg-sidebar-foreground/70',\n )}\n style={{ width: `${pct}%` }}\n />\n </span>\n )}\n </button>\n )\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/org/choice.ts","../src/org/cache.ts","../src/org/context.tsx"],"names":[],"mappings":"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","file":"chunk-NB6X5O5L.js","sourcesContent":["import type { OrgMembership } from '@fayz-ai/core'\n\n/**\n * Which workspace this account lands in, when it belongs to more than one.\n *\n * The provider used to answer this by itself — `handoff ?? pinned ?? first` —\n * and that last fallback is a guess with no way to correct it: an account in\n * seven workspaces opened whichever one sorted first and never learnt that the\n * other six existed. The rule below keeps every branch that IS an answer and\n * hands the remaining case to the person, once.\n */\n\nconst AUTOPICK_KEY = 'fayz:workspace-autopick'\n\n/**\n * The workspace a switch already committed to, surviving exactly one reload.\n *\n * Changing workspace ends in a full page reload — the only way to guarantee\n * that every plugin store, cache and open screen is rebuilt against the new\n * tenant instead of showing the previous one's rows. That reload comes back\n * through the same boot path as a fresh login, so without this marker the\n * picker would open and ask a question the user answered one second ago.\n *\n * sessionStorage, not local: it is about THIS navigation, and a tab opened\n * tomorrow should ask again.\n */\nconst SWITCHING_KEY = 'fayz:workspace-switching'\n\n/** Records the destination, for the boot that happens after the reload. */\nexport function markWorkspaceSwitch(orgId: string): void {\n try {\n if (typeof sessionStorage === 'undefined') return\n sessionStorage.setItem(SWITCHING_KEY, orgId)\n } catch {\n // ignore\n }\n}\n\n/** Reads the destination and consumes it — it is good for one boot only. */\nexport function takeWorkspaceSwitch(): string | null {\n try {\n if (typeof sessionStorage === 'undefined') return null\n const v = sessionStorage.getItem(SWITCHING_KEY)\n if (v) sessionStorage.removeItem(SWITCHING_KEY)\n return v\n } catch {\n return null\n }\n}\n\n/** Whether the last explicit choice stands in for every future login. */\nexport function getAutoPick(): boolean {\n try {\n if (typeof localStorage === 'undefined') return false\n return localStorage.getItem(AUTOPICK_KEY) === '1'\n } catch {\n return false\n }\n}\n\nexport function setAutoPick(on: boolean): void {\n try {\n if (typeof localStorage === 'undefined') return\n if (on) localStorage.setItem(AUTOPICK_KEY, '1')\n else localStorage.removeItem(AUTOPICK_KEY)\n } catch {\n // ignore\n }\n}\n\nexport interface WorkspaceChoiceInput {\n /** Every workspace this account belongs to, as the membership list read it. */\n memberships: OrgMembership[]\n /** A switch that is completing across a reload — already answered, once. */\n switchingToId?: string | null\n /** A sibling app's switcher named a workspace on the way in (008). */\n handoffId: string | null\n /** `fayz:current-org` — the last workspace this browser was in. */\n pinnedId: string | null\n /** \"Não perguntar novamente\" is on for this browser. */\n autoPick: boolean\n}\n\nexport type WorkspaceChoice =\n /** Open this one without asking. */\n | { kind: 'resolved'; orgId: string }\n /** Put the picker on screen; `suggestedId` is the row to pre-select. */\n | { kind: 'ask'; suggestedId: string | null }\n /** No workspace at all — the first-run setup flow's business, not ours. */\n | { kind: 'none' }\n\n/**\n * The decision, as a function, so the one piece of logic that decides what a\n * multi-workspace account sees after login can be tested without a browser.\n */\nexport function decideWorkspaceChoice({\n memberships,\n switchingToId = null,\n handoffId,\n pinnedId,\n autoPick,\n}: WorkspaceChoiceInput): WorkspaceChoice {\n if (memberships.length === 0) return { kind: 'none' }\n\n const has = (id: string | null): string | null =>\n id && memberships.some((m) => m.orgId === id) ? id : null\n\n // The freshest answer there is: this reload IS the switch completing.\n const switching = has(switchingToId)\n if (switching) return { kind: 'resolved', orgId: switching }\n\n // A handoff is somebody clicking a specific account in a sibling app's\n // switcher one second ago. That is a fresher answer than anything stored\n // here, and asking again would be asking a question already answered.\n const handoff = has(handoffId)\n if (handoff) return { kind: 'resolved', orgId: handoff }\n\n // One workspace is not a choice.\n if (memberships.length === 1) return { kind: 'resolved', orgId: memberships[0]!.orgId }\n\n // The pin is a HINT, always re-validated against the list we just read: a\n // workspace someone was removed from falls through to the question instead of\n // opening an account they can no longer see.\n const pinned = has(pinnedId)\n if (pinned && autoPick) return { kind: 'resolved', orgId: pinned }\n\n return { kind: 'ask', suggestedId: pinned }\n}\n","import type { Organization, OrgMember, OrgMembership, PermissionProfile } from '@fayz-ai/core'\n\n/**\n * Snapshot of the org bootstrap (org + memberships + members + permission\n * profiles) so a page reload doesn't wait on the whole chain again.\n *\n * Every mount used to pay `acceptPendingInvites → listUserOrgs → getOrg →\n * listMembers + listProfiles` before `org.id` existed, and every screen keyed\n * off the tenant (Conectores, plugin tabs, permission gates) sat idle until\n * then. The snapshot paints that state synchronously and the network is only\n * touched again once it goes stale.\n */\n\nconst STORAGE_KEY = 'fayz:org-snapshot'\nconst VERSION = 1\n\n/** Served without touching the network. */\nexport const ORG_CACHE_TTL_MS = 5 * 60 * 1000\n/** Older than this and the snapshot is dropped instead of painted. */\nconst MAX_AGE_MS = 24 * 60 * 60 * 1000\n/** Bigger than this (huge member lists) and we skip persisting rather than blow the quota. */\nconst MAX_BYTES = 512 * 1024\n\nexport interface OrgSnapshot {\n version: number\n /** Who the snapshot belongs to — a different user gets a cold load. */\n userId: string\n /** When the data last came from the server (store patches don't move it). */\n savedAt: number\n org: Organization\n userOrgs: OrgMembership[]\n members: OrgMember[]\n profiles: PermissionProfile[]\n currentProfileId: string | null\n}\n\nexport type OrgSnapshotInput = Omit<OrgSnapshot, 'version' | 'savedAt'>\n\nfunction storage(): Storage | null {\n try {\n if (typeof localStorage === 'undefined') return null\n return localStorage\n } catch {\n return null\n }\n}\n\nexport function readOrgSnapshot(): OrgSnapshot | null {\n const store = storage()\n if (!store) return null\n try {\n const raw = store.getItem(STORAGE_KEY)\n if (!raw) return null\n const snapshot = JSON.parse(raw) as OrgSnapshot\n if (snapshot?.version !== VERSION || !snapshot.org?.id || !snapshot.userId) return null\n if (snapshotAge(snapshot) > MAX_AGE_MS) {\n store.removeItem(STORAGE_KEY)\n return null\n }\n return snapshot\n } catch {\n return null\n }\n}\n\nexport function snapshotAge(snapshot: OrgSnapshot): number {\n const age = Date.now() - snapshot.savedAt\n // A clock that moved backwards shouldn't hand out an eternally fresh cache.\n return age < 0 ? Number.POSITIVE_INFINITY : age\n}\n\nexport function isSnapshotFresh(snapshot: OrgSnapshot, ttlMs: number): boolean {\n return snapshotAge(snapshot) < ttlMs\n}\n\n/** Record a fresh server read — restarts the TTL window. */\nexport function saveOrgSnapshot(input: OrgSnapshotInput): void {\n write({ ...input, version: VERSION, savedAt: Date.now() })\n}\n\n/**\n * Keep the snapshot in step with store writes made outside the provider\n * (renaming the org in Settings, editing a role) WITHOUT restarting the TTL —\n * otherwise a UI-only change would push the next revalidation out forever.\n */\nexport function patchOrgSnapshot(input: OrgSnapshotInput): void {\n const current = readOrgSnapshot()\n if (!current || current.userId !== input.userId) return\n write({ ...input, version: VERSION, savedAt: current.savedAt })\n}\n\nexport function clearOrgSnapshot(): void {\n try {\n storage()?.removeItem(STORAGE_KEY)\n } catch {\n // ignore\n }\n}\n\nfunction write(snapshot: OrgSnapshot): void {\n const store = storage()\n if (!store) return\n try {\n const raw = JSON.stringify(snapshot)\n if (raw.length > MAX_BYTES) return\n store.setItem(STORAGE_KEY, raw)\n } catch {\n // Quota or serialization failure — the cache is an optimization, not state.\n }\n}\n","import * as React from 'react'\nimport type { OrgAdapter, Organization, OrgMembership } from '@fayz-ai/core'\nimport { useAuthStore, readAppHandoff } from '@fayz-ai/auth'\nimport { useOrganizationStore, getPersistedOrgId } from './store'\nimport { decideWorkspaceChoice, getAutoPick, takeWorkspaceSwitch } from './choice'\nimport { usePermissionsStore } from '../permissions'\nimport {\n ORG_CACHE_TTL_MS,\n clearOrgSnapshot,\n isSnapshotFresh,\n patchOrgSnapshot,\n readOrgSnapshot,\n saveOrgSnapshot,\n type OrgSnapshot,\n} from './cache'\n\n// ---------------------------------------------------------------------------\n// Adapter context\n// ---------------------------------------------------------------------------\n\nconst OrgAdapterContext = React.createContext<OrgAdapter | null>(null)\n\nexport function useOrgAdapter(): OrgAdapter {\n const adapter = React.useContext(OrgAdapterContext)\n if (!adapter) {\n throw new Error('useOrgAdapter must be used within an <OrgProvider>')\n }\n return adapter\n}\n\nexport function useOrgAdapterOptional(): OrgAdapter | null {\n return React.useContext(OrgAdapterContext)\n}\n\n// ---------------------------------------------------------------------------\n// Tenant / org hook\n// ---------------------------------------------------------------------------\n\nexport interface TenantContext {\n /** The currently active organization */\n org: Organization | null\n /** All orgs the current user belongs to */\n userOrgs: OrgMembership[]\n loading: boolean\n /**\n * The bootstrap has finished at least once, so `org === null` now MEANS\n * \"belongs to no workspace\" instead of \"we have not looked yet\".\n *\n * `loading` cannot answer that: it starts `false`, before the effect that\n * loads anything has run. Anything deciding what to render from an empty org\n * — the setup gate — reads this, or it decides during the gap and flips its\n * mind a frame later.\n */\n settled: boolean\n /**\n * The membership list was actually READ for this account, and answered.\n *\n * Distinct from `settled`, which only says the wait is over — it is set in a\n * `finally`, so a failed `listUserOrgs` settles too. Anything that treats\n * \"no orgs\" as a FACT (the first-run setup gate) has to ask this instead.\n */\n orgsKnown: boolean\n /** Switch the active org */\n switchOrg: (orgId: string) => Promise<void>\n /** Refresh the current org from the adapter */\n refreshOrg: () => Promise<void>\n}\n\nconst TenantContext = React.createContext<TenantContext | null>(null)\n\n/**\n * Access the current tenant / organization.\n * Must be used inside <OrgProvider>.\n */\nexport function useTenant(): TenantContext {\n const ctx = React.useContext(TenantContext)\n if (!ctx) {\n throw new Error('useTenant must be used inside <OrgProvider>')\n }\n return ctx\n}\n\nexport function useTenantOptional(): TenantContext | null {\n return React.useContext(TenantContext)\n}\n\n// ---------------------------------------------------------------------------\n// Provider\n// ---------------------------------------------------------------------------\n\nexport interface OrgProviderProps {\n adapter: OrgAdapter\n /** When true, automatically creates an org if the user has none */\n autoCreate?: boolean\n /**\n * How long the cached org bootstrap is served before the provider goes back\n * to the network (default 5 min). A cached load paints synchronously, so\n * screens that key off `org.id` don't wait a round trip on every reload.\n * `0` disables the cache and restores the always-fetch behaviour.\n */\n cacheTtlMs?: number\n children: React.ReactNode\n}\n\nconst useIsomorphicLayoutEffect =\n typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect\n\nexport function OrgProvider({\n adapter,\n autoCreate = false,\n cacheTtlMs = ORG_CACHE_TTL_MS,\n children,\n}: OrgProviderProps) {\n const { user, isLoading: authLoading } = useAuthStore()\n const { currentOrg, userOrgs, loading, setCurrentOrg, setUserOrgs, setMembers, setLoading, reset } =\n useOrganizationStore()\n const setProfiles = usePermissionsStore((s) => s.setProfiles)\n const setCurrentProfile = usePermissionsStore((s) => s.setCurrentProfile)\n\n const adapterRef = React.useRef(adapter)\n adapterRef.current = adapter\n\n const [snapshot] = React.useState<OrgSnapshot | null>(() =>\n cacheTtlMs > 0 ? readOrgSnapshot() : null,\n )\n // One load per signed-in user per mount — auth reports `isLoading` and `user`\n // in two separate store writes, so the effect would otherwise fire twice.\n const loadedForRef = React.useRef<string | null>(null)\n\n // WHOSE bootstrap has finished, not whether one has. A boolean could not tell\n // the difference between \"we know this account has no workspace\" and \"we knew\n // that about the account that just signed out\" — which is what flashed the\n // setup flow over every login: sign-out settled it, and sign-in kept the\n // stale `true` for the whole round trip.\n //\n // A painted snapshot is already an answer for its own user: that account HAS a\n // workspace, and revalidation will not turn that into \"has none\".\n const [settledFor, setSettledFor] = React.useState<string | null>(() =>\n snapshot?.org ? snapshot.userId : null,\n )\n // Same shape, different question: WHOSE membership list came back. Seeded\n // from a painted snapshot for the same reason — that account's list was read\n // once and cached, and revalidation cannot turn \"has one\" into \"has none\".\n const [orgsReadFor, setOrgsReadFor] = React.useState<string | null>(() =>\n snapshot?.org ? snapshot.userId : null,\n )\n // Signed out there is nothing to wait for; signed in, only this user's answer counts.\n const settled = user ? settledFor === user.id : !authLoading\n const orgsKnown = !!user && orgsReadFor === user.id\n\n // Paint the last known org before the first child renders. The stores are\n // filled in a layout effect, so nothing gets a frame with `org === null`.\n useIsomorphicLayoutEffect(() => {\n if (!snapshot) return\n setUserOrgs(snapshot.userOrgs)\n setCurrentOrg(snapshot.org)\n setMembers(snapshot.members)\n setProfiles(snapshot.profiles)\n setCurrentProfile(snapshot.profiles.find((p) => p.id === snapshot.currentProfileId) ?? null)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // Keep the snapshot in step with store writes made outside this provider —\n // renaming the org in Settings, editing a role — so the cache never serves a\n // value the user already changed on screen. Patching leaves `savedAt` alone:\n // a UI-only edit must not push the next revalidation further out.\n React.useEffect(() => {\n if (cacheTtlMs <= 0 || !user) return\n const uid = user.id\n const sync = () => {\n const org = useOrganizationStore.getState()\n if (!org.currentOrg) return\n const perms = usePermissionsStore.getState()\n patchOrgSnapshot({\n userId: uid,\n org: org.currentOrg,\n userOrgs: org.userOrgs,\n members: org.members,\n profiles: perms.profiles,\n // realProfile, not currentProfile: an impersonation preview is not\n // something to cache back as the user's own role.\n currentProfileId: perms.realProfile?.id ?? null,\n })\n }\n const unsubscribeOrg = useOrganizationStore.subscribe(sync)\n const unsubscribePerms = usePermissionsStore.subscribe(sync)\n return () => {\n unsubscribeOrg()\n unsubscribePerms()\n }\n }, [user?.id, cacheTtlMs])\n\n // Load the org's members + permission profiles into the shared stores whenever\n // an org resolves. This is what makes the role list, the invite dialog's role\n // dropdown, and permission checks work — previously nothing loaded them here,\n // so those surfaces came up empty. Also resolves the signed-in user's own role.\n const hydrateOrg = React.useCallback(\n async (org: Organization, memberships: OrgMembership[], uid: string | undefined) => {\n try {\n const [members, profiles] = await Promise.all([\n adapterRef.current.listMembers(org.id),\n adapterRef.current.listProfiles(org.id),\n ])\n setMembers(members)\n setProfiles(profiles)\n const myMembership = uid ? members.find((m) => m.userId === uid) : undefined\n const profile = profiles.find((p) => p.id === myMembership?.profileId) ?? null\n setCurrentProfile(profile)\n // Everything the next reload needs, stamped now — this is the only\n // place the TTL window restarts.\n if (cacheTtlMs > 0 && uid) {\n saveOrgSnapshot({\n userId: uid,\n org,\n userOrgs: memberships,\n members,\n profiles,\n currentProfileId: profile?.id ?? null,\n })\n }\n } catch {\n // Non-fatal — leave stores as-is if the load fails.\n }\n },\n [setMembers, setProfiles, setCurrentProfile, cacheTtlMs],\n )\n\n // Load orgs when user is authenticated\n React.useEffect(() => {\n if (!user) {\n // A cold load reports `user === null` while the session hydrates — that's\n // not a sign-out, so the painted snapshot stands until auth settles.\n if (authLoading) return\n loadedForRef.current = null\n reset()\n clearOrgSnapshot()\n setSettledFor(null)\n setOrgsReadFor(null)\n return\n }\n\n const cached = snapshot?.userId === user.id ? snapshot : null\n\n // Already painted and still inside its window: skip the whole bootstrap.\n if (cached && isSnapshotFresh(cached, cacheTtlMs)) {\n setSettledFor(user.id)\n setOrgsReadFor(user.id)\n return\n }\n\n // A snapshot from another account was painted — drop it before loading.\n if (snapshot && snapshot.userId !== user.id && loadedForRef.current === null) {\n reset()\n clearOrgSnapshot()\n }\n\n if (loadedForRef.current === user.id) return\n loadedForRef.current = user.id\n\n // Stale but painted: revalidate quietly, so screens keep the data they're\n // showing instead of flipping back to a skeleton.\n const silent = !!cached\n\n let cancelled = false\n\n async function loadOrgs() {\n if (!silent) setLoading(true)\n try {\n // Redeem invites first — an invitee has no membership until this runs,\n // and without it autoCreate below would hand them a personal org\n // instead of the one that invited them.\n let accepted = 0\n try {\n accepted = (await adapterRef.current.acceptPendingInvites?.()) ?? 0\n } catch {\n // Non-fatal: fall through and load whatever memberships exist.\n }\n\n if (cancelled) return\n\n let memberships = await adapterRef.current.listUserOrgs(user!.id)\n\n // An empty list right after accepting means the read was deduped onto a\n // request that started before the invite landed. Ask once more.\n if (memberships.length === 0 && accepted > 0) {\n memberships = await adapterRef.current.listUserOrgs(user!.id)\n }\n\n if (cancelled) return\n\n setUserOrgs(memberships)\n // The read answered. Everything after this can still fail without\n // turning \"this account has no workspace\" into a guess.\n setOrgsReadFor(user!.id)\n\n // Auto-create org if user has none\n if (memberships.length === 0 && accepted === 0 && autoCreate) {\n const newOrg = await adapterRef.current.createOrg(\n user!.fullName ? `${user!.fullName}'s Organization` : 'My Organization',\n user!.id,\n )\n if (!cancelled) {\n const ownMembership: OrgMembership[] = [\n {\n orgId: newOrg.id,\n orgName: newOrg.name,\n orgSlug: newOrg.slug,\n profileId: 'owner',\n profileName: 'Owner',\n },\n ]\n setUserOrgs(ownMembership)\n setCurrentOrg(newOrg)\n await hydrateOrg(newOrg, ownMembership, user!.id)\n }\n return\n }\n\n // Which workspace to open — or whether to open one at all. The ladder\n // lives in `decideWorkspaceChoice`; the only branch that changed shape\n // here is the last one. It used to be `?? memberships[0]`, which turned\n // \"we do not know which of your seven accounts you meant\" into a silent\n // guess the user could not see, let alone correct.\n const choice = decideWorkspaceChoice({\n memberships,\n // Consumed here, and only here: this is the one boot the marker was\n // written for, and leaving it behind would pin the next one too.\n switchingToId: takeWorkspaceSwitch(),\n handoffId: readAppHandoff()?.tenantId ?? null,\n pinnedId: getPersistedOrgId(),\n autoPick: getAutoPick(),\n })\n\n // Leaving `currentOrg` null IS the ask: the chooser gate reads exactly\n // this state — a membership list we have read, more than one row in it,\n // and no active workspace — so no extra flag has to be kept in sync.\n if (choice.kind !== 'resolved') return\n\n if (!cancelled) {\n const org = await adapterRef.current.getOrg(choice.orgId)\n if (!cancelled) {\n setCurrentOrg(org)\n await hydrateOrg(org, memberships, user!.id)\n }\n }\n } finally {\n if (!cancelled && !silent) setLoading(false)\n // Settled even when the load threw: the answer is then \"we asked and\n // could not tell\", and holding the screen forever is worse than showing\n // the app. It is about the wait being over, not about success.\n if (!cancelled) setSettledFor(user!.id)\n }\n }\n\n void loadOrgs()\n\n return () => {\n cancelled = true\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [user?.id, authLoading])\n\n async function switchOrg(orgId: string): Promise<void> {\n setLoading(true)\n try {\n const org = await adapterRef.current.getOrg(orgId)\n setCurrentOrg(org)\n await hydrateOrg(org, useOrganizationStore.getState().userOrgs, user?.id)\n } finally {\n setLoading(false)\n }\n }\n\n // Explicit refresh always goes to the network and restarts the cache window.\n async function refreshOrg(): Promise<void> {\n if (!currentOrg) return\n setLoading(true)\n try {\n const org = await adapterRef.current.getOrg(currentOrg.id)\n setCurrentOrg(org)\n await hydrateOrg(org, useOrganizationStore.getState().userOrgs, user?.id)\n } finally {\n setLoading(false)\n }\n }\n\n const tenantValue: TenantContext = {\n org: currentOrg,\n userOrgs,\n loading,\n settled,\n orgsKnown,\n switchOrg,\n refreshOrg,\n }\n\n return (\n <OrgAdapterContext.Provider value={adapter}>\n <TenantContext.Provider value={tenantValue}>\n {children}\n </TenantContext.Provider>\n </OrgAdapterContext.Provider>\n )\n}\n"]}
@@ -1,20 +0,0 @@
1
- // src/lib/schedule-config.ts
2
- var globalConfig = null;
3
- var listeners = /* @__PURE__ */ new Set();
4
- function setScheduleBlockConfig(config) {
5
- globalConfig = config;
6
- listeners.forEach((fn) => fn());
7
- }
8
- function getScheduleBlockConfig() {
9
- return globalConfig;
10
- }
11
- function subscribeScheduleBlockConfig(listener) {
12
- listeners.add(listener);
13
- return () => {
14
- listeners.delete(listener);
15
- };
16
- }
17
-
18
- export { getScheduleBlockConfig, setScheduleBlockConfig, subscribeScheduleBlockConfig };
19
- //# sourceMappingURL=chunk-RKXZ7RUG.js.map
20
- //# sourceMappingURL=chunk-RKXZ7RUG.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/schedule-config.ts"],"names":[],"mappings":";AAyBA,IAAI,YAAA,GAA2C,IAAA;AAC/C,IAAM,SAAA,uBAAgB,GAAA,EAAgB;AAE/B,SAAS,uBAAuB,MAAA,EAAmC;AACxE,EAAA,YAAA,GAAe,MAAA;AACf,EAAA,SAAA,CAAU,OAAA,CAAQ,CAAC,EAAA,KAAO,EAAA,EAAI,CAAA;AAChC;AAEO,SAAS,sBAAA,GAAqD;AACnE,EAAA,OAAO,YAAA;AACT;AAGO,SAAS,6BAA6B,QAAA,EAAkC;AAC7E,EAAA,SAAA,CAAU,IAAI,QAAQ,CAAA;AACtB,EAAA,OAAO,MAAM;AAAE,IAAA,SAAA,CAAU,OAAO,QAAQ,CAAA;AAAA,EAAE,CAAA;AAC5C","file":"chunk-RKXZ7RUG.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Schedule Block Config Registry\n// Lightweight global config — set by the agenda plugin, read by ScheduleEditor.\n// No React context needed. Graceful degradation when not configured.\n// ---------------------------------------------------------------------------\n\nexport interface ScheduleBlockConfig {\n defaults: {\n bufferMinutes: number\n maxConcurrent: number\n minAdvanceHours: number\n maxAdvanceDays: number\n }\n /** Available services for the multi-select filter. */\n services?: { id: string; name: string }[]\n showServices?: boolean\n showConcurrent?: boolean\n showBookingWindow?: boolean\n /** Available locations for per-block assignment. */\n locations?: { id: string; name: string }[]\n showLocations?: boolean\n /** Lazy fetcher — called when locations are needed but not yet loaded. */\n fetchLocations?: () => Promise<{ id: string; name: string }[]>\n}\n\nlet globalConfig: ScheduleBlockConfig | null = null\nconst listeners = new Set<() => void>()\n\nexport function setScheduleBlockConfig(config: ScheduleBlockConfig): void {\n globalConfig = config\n listeners.forEach((fn) => fn())\n}\n\nexport function getScheduleBlockConfig(): ScheduleBlockConfig | null {\n return globalConfig\n}\n\n/** Subscribe to config changes. Returns unsubscribe function. */\nexport function subscribeScheduleBlockConfig(listener: () => void): () => void {\n listeners.add(listener)\n return () => { listeners.delete(listener) }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/permissions/store.ts","../src/permissions/context.tsx"],"names":[],"mappings":"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","file":"chunk-WJ3H3RJN.js","sourcesContent":["import { create } from 'zustand'\nimport type { FeatureDeclaration, PermissionProfile } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Store interface\n// ---------------------------------------------------------------------------\n\nexport interface PermissionsStore {\n features: FeatureDeclaration[]\n profiles: PermissionProfile[]\n /** The effective profile used for permission checks (may be impersonated) */\n currentProfile: PermissionProfile | null\n /** The user's actual profile (preserved during impersonation) */\n realProfile: PermissionProfile | null\n /** The profile being previewed, if any */\n impersonatedProfile: PermissionProfile | null\n /** Whether impersonation is active */\n isImpersonating: boolean\n\n setFeatures: (features: FeatureDeclaration[]) => void\n setProfiles: (profiles: PermissionProfile[]) => void\n setCurrentProfile: (profile: PermissionProfile | null) => void\n startImpersonation: (profile: PermissionProfile) => void\n stopImpersonation: () => void\n reset: () => void\n}\n\nexport const usePermissionsStore = create<PermissionsStore>((set, get) => ({\n features: [],\n profiles: [],\n currentProfile: null,\n realProfile: null,\n impersonatedProfile: null,\n isImpersonating: false,\n\n setFeatures: (features) => set({ features }),\n setProfiles: (profiles) => set({ profiles }),\n setCurrentProfile: (profile) =>\n set({\n currentProfile: profile,\n realProfile: profile,\n impersonatedProfile: null,\n isImpersonating: false,\n }),\n startImpersonation: (profile) =>\n set({\n currentProfile: profile,\n impersonatedProfile: profile,\n isImpersonating: true,\n }),\n stopImpersonation: () => {\n const { realProfile } = get()\n set({\n currentProfile: realProfile,\n impersonatedProfile: null,\n isImpersonating: false,\n })\n },\n reset: () =>\n set({\n features: [],\n profiles: [],\n currentProfile: null,\n realProfile: null,\n impersonatedProfile: null,\n isImpersonating: false,\n }),\n}))\n","import * as React from 'react'\nimport type { FeatureDeclaration, PermissionsConfig, PermissionProfile } from '@fayz-ai/core'\nimport { usePluginRuntimeOptional } from '@fayz-ai/core'\nimport { usePermissionsStore } from './store'\n\n// ---------------------------------------------------------------------------\n// Permission check helpers\n// ---------------------------------------------------------------------------\n\n// The role-side check moved to @fayz-ai/core/access (single implementation for\n// browser, headless and the Fayz broker). Re-exported to keep call-sites stable.\nimport { profileHasPermission } from '@fayz-ai/core/access'\nexport { profileHasPermission }\n\n/**\n * Merge plugin-declared features with the app's own, deduped by id. The app's\n * declaration wins on collision (it can override a plugin's label/actions).\n */\nfunction mergeFeatures(\n pluginFeatures: FeatureDeclaration[] | undefined,\n appFeatures: FeatureDeclaration[] | undefined,\n): FeatureDeclaration[] {\n const byId = new Map<string, FeatureDeclaration>()\n for (const f of pluginFeatures ?? []) byId.set(f.id, f)\n for (const f of appFeatures ?? []) byId.set(f.id, f) // app override wins\n return Array.from(byId.values())\n}\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\n/**\n * Why a `hasPermission` answer can be trusted, in three states rather than two:\n *\n * - `loading` — the RBAC catalog has not arrived. Checks DENY (the engine\n * fails closed), but the answer is not final: render a\n * skeleton, not \"you don't have access\".\n * - `ready` — the catalog arrived. A denial is the real answer, including\n * for a member the org gave no role.\n * - `unmanaged` — no <PermissionsProvider> in the tree at all. Only reported\n * by the *Optional hooks, which allow everything: an SDK\n * component under a bare host shell has no RBAC runtime to\n * ask, and gating there is an enhancement, not a guarantee.\n */\nexport type PermissionsStatus = 'loading' | 'ready' | 'unmanaged'\n\ninterface PermissionsContextValue {\n hasPermission: (feature: string, action?: string) => boolean\n status: PermissionsStatus\n canImpersonate: boolean\n startImpersonation: (profile: PermissionProfile) => void\n stopImpersonation: () => void\n}\n\nconst PermissionsContext = React.createContext<PermissionsContextValue | null>(null)\n\n// ---------------------------------------------------------------------------\n// Provider\n// ---------------------------------------------------------------------------\n\nexport interface PermissionsProviderProps {\n config?: PermissionsConfig\n children: React.ReactNode\n}\n\nexport function PermissionsProvider({ config, children }: PermissionsProviderProps) {\n const { setFeatures, startImpersonation, stopImpersonation, currentProfile, profiles, isImpersonating } =\n usePermissionsStore()\n\n // Plugins declare their own permission features via `declaredFeatures`, which the\n // plugin runtime aggregates into `pluginFeatures`. Merging them here is what makes\n // a plugin \"born compatible\" — its features show up in the RBAC matrix and gate\n // checks without the app re-declaring them. The app's own `config.features` wins\n // on id collisions (app override), so an app can refine a plugin's declaration.\n const runtime = usePluginRuntimeOptional()\n const pluginFeatures = runtime?.pluginFeatures\n\n React.useEffect(() => {\n const merged = mergeFeatures(pluginFeatures, config?.features)\n if (merged.length > 0) {\n setFeatures(merged)\n }\n }, [config, pluginFeatures, setFeatures])\n\n function hasPermission(feature: string, action?: string): boolean {\n return profileHasPermission(currentProfile, feature, action)\n }\n\n // The org bootstrap writes `profiles` (the catalog) before it resolves the\n // member's own role, so a filled catalog — not a non-null profile — is what\n // says the load is over. Without that, a member with no role assigned would\n // look identical to a load that never finished.\n const status: PermissionsStatus = currentProfile || profiles.length > 0 ? 'ready' : 'loading'\n\n const value: PermissionsContextValue = {\n hasPermission,\n status,\n canImpersonate: !isImpersonating,\n startImpersonation,\n stopImpersonation,\n }\n\n return (\n <PermissionsContext.Provider value={value}>\n {children}\n </PermissionsContext.Provider>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Hooks\n// ---------------------------------------------------------------------------\n\n/**\n * Returns a function that checks whether the current user has a given\n * permission. Throws if used outside <PermissionsProvider>.\n */\nexport function usePermission(): (feature: string, action?: string) => boolean {\n const ctx = React.useContext(PermissionsContext)\n if (!ctx) {\n throw new Error('usePermission must be used inside <PermissionsProvider>')\n }\n return ctx.hasPermission\n}\n\n/**\n * Like usePermission, but degrades to allow-all when no <PermissionsProvider>\n * is mounted — so SDK components (e.g. the CRUD engine's PermissionGate) work\n * under any host shell instead of throwing. Gating is an enhancement, not a\n * hard requirement at the component level.\n *\n * That fallback covers `unmanaged` ONLY. Under a provider this is the real\n * check, which denies until the profile resolves: a missing provider means\n * nobody asked for gating, while a missing profile means we cannot yet say yes.\n * Pair with {@link usePermissionsStatus} to show a skeleton while `loading`.\n */\nexport function usePermissionOptional(): (feature: string, action?: string) => boolean {\n const ctx = React.useContext(PermissionsContext)\n return ctx?.hasPermission ?? (() => true)\n}\n\n/**\n * Why the current answers are what they are — `unmanaged` outside a provider.\n * The signal a surface needs to avoid rendering a lock over a decision that has\n * not been made yet.\n */\nexport function usePermissionsStatus(): PermissionsStatus {\n return React.useContext(PermissionsContext)?.status ?? 'unmanaged'\n}\n\n/**\n * Convenience hook — returns true/false for a specific feature + action.\n * Example: `const canEdit = useHasPermission('clients', 'write')`\n */\nexport function useHasPermission(feature: string, action?: string): boolean {\n const ctx = React.useContext(PermissionsContext)\n if (!ctx) {\n throw new Error('useHasPermission must be used inside <PermissionsProvider>')\n }\n return ctx.hasPermission(feature, action)\n}\n\n/**\n * Convenience hook that surfaces the full permissions context, including\n * impersonation controls.\n */\nexport function usePermissions(): PermissionsContextValue {\n const ctx = React.useContext(PermissionsContext)\n if (!ctx) {\n throw new Error('usePermissions must be used inside <PermissionsProvider>')\n }\n return ctx\n}\n\n// Re-export feature declarations for use in feature flag checks\nexport type { FeatureDeclaration }\n"]}