@quanticjs/notification-ui 9.0.0 → 9.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +997 -996
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +986 -970
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/notification-provider.tsx","../src/notification-realtime-provider.tsx","../src/notification-preferences.tsx","../src/use-unread-count.ts","../src/use-notification-feed.ts","../src/notification-bell.tsx","../src/notification-inbox.tsx","../src/notification-center.tsx","../src/delivery-analytics-page.tsx","../src/use-delivery-analytics.ts","../src/use-funnel-stats.ts","../src/use-delivery-types.ts","../src/funnel-stats.tsx","../src/trend-chart.tsx","../src/type-table.tsx","../src/template-status-badge.tsx","../src/template-list.tsx","../src/template-editor.tsx","../src/template-preview-pane.tsx","../src/template-version-history.tsx","../src/delivery-log-viewer.tsx","../src/use-broadcasts.ts","../src/broadcast-list.tsx","../src/broadcast-progress.tsx","../src/broadcast-composer.tsx","../src/segment-list.tsx","../src/segment-builder.tsx","../src/suppression-manager.tsx","../src/dlq-console.tsx","../src/catalog-editor.tsx","../src/missing-translations-panel.tsx","../src/fallback-report-panel.tsx","../src/recipient-admin-panel.tsx","../src/webhook-endpoint-manager.tsx","../src/operations-overview.tsx","../src/delivery-log-explorer.tsx","../src/quiet-hours-form.tsx","../src/frequency-cap-table.tsx","../src/tenant-config-form.tsx","../src/tracking-config-form.tsx","../src/api-key-manager.tsx","../src/application-registry-panel.tsx"],"sourcesContent":["export {\n NotificationProvider,\n useNotificationConfig,\n type NotificationProviderProps,\n type NotificationConfig,\n} from './notification-provider';\n\nexport {\n NotificationPreferences,\n type NotificationPreferencesProps,\n type NotificationPreferenceDto,\n type NotificationChannel,\n type DigestPeriod,\n} from './notification-preferences';\n\nexport {\n NotificationRealtimeProvider,\n useRealtimeContext,\n type NotificationRealtimeProviderProps,\n type RealtimeStatus,\n} from './notification-realtime-provider';\n\nexport { useUnreadCount, type UseUnreadCountOptions } from './use-unread-count';\n\nexport {\n useNotificationFeed,\n type UseNotificationFeedOptions,\n type NotificationFeedItem,\n type PaginatedFeed,\n} from './use-notification-feed';\n\nexport { NotificationBell, type NotificationBellProps } from './notification-bell';\n\nexport { NotificationInbox, type NotificationInboxProps } from './notification-inbox';\n\nexport { NotificationCenter, type NotificationCenterProps } from './notification-center';\n\nexport { DeliveryAnalyticsPage, type DeliveryAnalyticsPageProps } from './delivery-analytics-page';\nexport { FunnelStats, type FunnelStatsProps } from './funnel-stats';\nexport { TrendChart, type TrendChartProps } from './trend-chart';\nexport { TypeTable, type TypeTableProps } from './type-table';\nexport {\n useDeliveryAnalytics,\n type UseDeliveryAnalyticsOptions,\n type DailyDeliveryStats,\n type DeliveryAnalyticsFilters,\n} from './use-delivery-analytics';\nexport {\n useFunnelStats,\n type UseFunnelStatsOptions,\n type DeliveryFunnel,\n} from './use-funnel-stats';\nexport {\n useDeliveryTypes,\n type UseDeliveryTypesOptions,\n type DeliveryTypeBreakdown,\n} from './use-delivery-types';\n\nexport { TemplateStatusBadge, type TemplateStatus } from './template-status-badge';\n\nexport { TemplateList, type TemplateListProps, type TemplateListItem } from './template-list';\n\nexport {\n TemplateEditor,\n type TemplateEditorProps,\n type TemplateEditorFields,\n type TemplateVersionResponse,\n} from './template-editor';\n\nexport {\n TemplatePreviewPane,\n type TemplatePreviewPaneProps,\n type PreviewResult,\n} from './template-preview-pane';\n\nexport {\n TemplateVersionHistory,\n type TemplateVersionHistoryProps,\n type TemplateVersion,\n} from './template-version-history';\n\nexport {\n DeliveryLogViewer,\n type DeliveryLogViewerProps,\n type DeliveryLogRow,\n type DeliveryLogPage,\n} from './delivery-log-viewer';\n\n// ─── Management console admin components (SPEC-notification-management-console) ───\n\nexport {\n useBroadcasts,\n type UseBroadcastsOptions,\n type BroadcastListItem,\n type BroadcastListPage,\n} from './use-broadcasts';\nexport { BroadcastList, type BroadcastListProps } from './broadcast-list';\nexport {\n BroadcastProgress,\n type BroadcastProgressProps,\n type BroadcastDetail,\n} from './broadcast-progress';\nexport {\n BroadcastComposer,\n type BroadcastComposerProps,\n type BroadcastCreatedResult,\n} from './broadcast-composer';\n\nexport { SegmentList, type SegmentListProps, type Segment } from './segment-list';\nexport {\n SegmentBuilder,\n type SegmentBuilderProps,\n type SegmentForm,\n type SegmentType,\n} from './segment-builder';\n\nexport {\n SuppressionManager,\n type SuppressionManagerProps,\n type Suppression,\n type SuppressionPage,\n type SuppressionChannel,\n} from './suppression-manager';\n\nexport {\n DlqConsole,\n type DlqConsoleProps,\n type DlqMessage,\n type DlqPage,\n type DlqMessageDetail,\n type DlqStatusFilter,\n} from './dlq-console';\n\nexport { CatalogEditor, type CatalogEditorProps, type CatalogEntry } from './catalog-editor';\nexport {\n MissingTranslationsPanel,\n type MissingTranslationsPanelProps,\n type MissingEntry,\n} from './missing-translations-panel';\nexport {\n FallbackReportPanel,\n type FallbackReportPanelProps,\n type FallbackEntry,\n} from './fallback-report-panel';\n\nexport {\n RecipientAdminPanel,\n type RecipientAdminPanelProps,\n type RecipientSummary,\n type RecipientPage,\n} from './recipient-admin-panel';\n\nexport {\n WebhookEndpointManager,\n type WebhookEndpointManagerProps,\n type WebhookEndpoint,\n type WebhookDelivery,\n} from './webhook-endpoint-manager';\n\nexport {\n OperationsOverview,\n type OperationsOverviewProps,\n type OperationsOverviewResponse,\n type OperationsChannelStat,\n} from './operations-overview';\nexport {\n DeliveryLogExplorer,\n type DeliveryLogExplorerProps,\n type DeliveryLogExplorerRow,\n type DeliveryLogExplorerPage,\n} from './delivery-log-explorer';\n\nexport { QuietHoursForm, type QuietHoursFormProps, type QuietHours } from './quiet-hours-form';\nexport { FrequencyCapTable, type FrequencyCapTableProps, type Cap } from './frequency-cap-table';\nexport {\n TenantConfigForm,\n type TenantConfigFormProps,\n type TenantConfig,\n} from './tenant-config-form';\nexport {\n TrackingConfigForm,\n type TrackingConfigFormProps,\n type TrackingConfig,\n} from './tracking-config-form';\n\nexport {\n ApiKeyManager,\n type ApiKeyManagerProps,\n type ApiKey,\n type ApiKeyCreateResponse,\n} from './api-key-manager';\n\nexport {\n ApplicationRegistryPanel,\n type ApplicationRegistryPanelProps,\n type Application,\n} from './application-registry-panel';\n","import { createContext, useContext, useMemo, type ReactNode } from 'react';\nimport {\n NotificationRealtimeProvider,\n type NotificationRealtimeProviderProps,\n} from './notification-realtime-provider';\n\n/**\n * Resolved notification config shared with every bell / inbox / hook below the\n * provider. A consumer app sets these once; components and hooks read them from\n * context, so the bell dropped into `AppShell`'s `TopBar.actions` scopes to the\n * registered app without prop-drilling `appId` everywhere.\n */\nexport interface NotificationConfig {\n /**\n * The registered application slug this app's notifications are scoped to\n * (must match a row in the engine's application registry). Flows to `?appId=`\n * on list / unread-count / read-all and filters realtime events. Omit on a\n * shell / portal to get the unified cross-app inbox.\n */\n appId?: string;\n /** API path prefix the engine's notification endpoints are mounted on. Default `/notifications`. */\n basePath: string;\n /** Unread-count / feed poll interval in ms when the socket is down. Default 60_000. */\n pollIntervalMs: number;\n}\n\nconst DEFAULT_CONFIG: NotificationConfig = {\n appId: undefined,\n basePath: '/notifications',\n pollIntervalMs: 60_000,\n};\n\nconst NotificationConfigContext = createContext<NotificationConfig>(DEFAULT_CONFIG);\n\n/**\n * Reads the ambient notification config. Returns framework defaults when no\n * `NotificationProvider` is mounted, so components still work with explicit\n * props in isolation (and in tests).\n */\nexport function useNotificationConfig(): NotificationConfig {\n return useContext(NotificationConfigContext);\n}\n\nexport interface NotificationProviderProps\n extends Pick<NotificationRealtimeProviderProps, 'serverUrl' | 'disabled'> {\n /**\n * The consumer app's registered slug — the one thing an app must declare to\n * scope its bell. Omit on a shell / portal for the unified inbox.\n */\n appId?: string;\n /** Endpoint path prefix (through the host BFF). Default `/notifications`. */\n basePath?: string;\n /** Poll interval (ms) used while the realtime socket is unavailable. Default 60_000. */\n pollIntervalMs?: number;\n children: ReactNode;\n}\n\n/**\n * Single registration point for notifications. Wrap the app (above `AppShell`)\n * once:\n *\n * ```tsx\n * <NotificationProvider appId=\"delivery-hub\">\n * <AppShell topBar={{ actions: <NotificationBell /> }}>…</AppShell>\n * </NotificationProvider>\n * ```\n *\n * It opens the shared realtime socket (app-filtered) and publishes `appId` /\n * `basePath` / `pollIntervalMs` to every notification component and hook below.\n */\nexport function NotificationProvider({\n appId,\n basePath = '/notifications',\n pollIntervalMs = 60_000,\n serverUrl,\n disabled,\n children,\n}: NotificationProviderProps) {\n const config = useMemo<NotificationConfig>(\n () => ({ appId, basePath, pollIntervalMs }),\n [appId, basePath, pollIntervalMs],\n );\n\n return (\n <NotificationConfigContext.Provider value={config}>\n <NotificationRealtimeProvider appId={appId} serverUrl={serverUrl} disabled={disabled}>\n {children}\n </NotificationRealtimeProvider>\n </NotificationConfigContext.Provider>\n );\n}\n","import { createContext, useContext, useEffect, useRef, useState, type ReactNode } from 'react';\nimport { useQueryClient } from '@tanstack/react-query';\nimport { io, type Socket } from 'socket.io-client';\n\nexport type RealtimeStatus = 'connected' | 'reconnecting' | 'disconnected' | 'disabled';\n\ninterface RealtimeContextValue {\n socket: Socket | null;\n status: RealtimeStatus;\n}\n\nconst RealtimeContext = createContext<RealtimeContextValue>({ socket: null, status: 'disabled' });\n\nexport interface NotificationRealtimeProviderProps {\n /** Socket.IO server base URL — defaults to current origin (BFF proxy). */\n serverUrl?: string;\n /** Disable WebSocket (falls back to polling). Default: false. */\n disabled?: boolean;\n /**\n * Scope realtime invalidation to a producing app (SPEC-application-scoping).\n * When set, `notification:new` events for other apps are ignored; events for\n * this app or system-wide (`appId: null`) still refresh the feed/badge. Omit\n * for a portal that reacts to every app's events.\n */\n appId?: string;\n children: ReactNode;\n className?: string;\n}\n\n/**\n * Mounts a single shared Socket.IO connection to the engine's `/realtime`\n * namespace using only the BFF httpOnly session cookie (`withCredentials`).\n * On `notification:new` / `unread-count:changed` it invalidates the relevant\n * TanStack Query keys (leading-edge debounced over a 200 ms window) so existing\n * fetch logic is reused rather than patching caches. Exposes connection status\n * via context so hooks can switch to REST polling when the socket is down.\n */\nexport function NotificationRealtimeProvider({\n serverUrl = '',\n disabled = false,\n appId,\n children,\n}: NotificationRealtimeProviderProps) {\n const queryClient = useQueryClient();\n const [socket, setSocket] = useState<Socket | null>(null);\n const [status, setStatus] = useState<RealtimeStatus>(disabled ? 'disabled' : 'disconnected');\n const invalidateTimers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());\n\n useEffect(() => {\n if (disabled) {\n setStatus('disabled');\n return;\n }\n\n const debounceInvalidate = (key: readonly unknown[]) => {\n const cacheKey = JSON.stringify(key);\n if (invalidateTimers.current.has(cacheKey)) return; // leading-edge: ignore within window\n void queryClient.invalidateQueries({ queryKey: key as unknown[] });\n const timer = setTimeout(() => invalidateTimers.current.delete(cacheKey), 200);\n invalidateTimers.current.set(cacheKey, timer);\n };\n\n const s = io(`${serverUrl}/realtime`, {\n withCredentials: true,\n transports: ['websocket'],\n reconnectionDelay: 1_000,\n reconnectionDelayMax: 30_000,\n randomizationFactor: 0.5,\n });\n setSocket(s);\n\n s.on('connect', () => {\n setStatus('connected');\n // Full invalidation covers any gap during the disconnect window.\n void queryClient.invalidateQueries({ queryKey: ['notifications'] });\n });\n\n s.on('notification:new', (payload?: { appId?: string | null }) => {\n // App-scoped provider: ignore events for other apps. A system-wide event\n // (appId null/absent) always refreshes; an event for THIS app refreshes.\n const eventAppId = payload?.appId ?? null;\n if (appId && eventAppId && eventAppId !== appId) return;\n debounceInvalidate(['notifications']);\n debounceInvalidate(['notifications', 'unread-count']);\n });\n\n s.on('unread-count:changed', () => {\n debounceInvalidate(['notifications', 'unread-count']);\n });\n\n s.io.on('reconnect_attempt', () => setStatus('reconnecting'));\n\n s.on('disconnect', (reason: string) => {\n // Server-initiated disconnect (logout): auth is gone — do not reconnect.\n if (reason === 'io server disconnect') {\n s.io.opts.reconnection = false;\n setStatus('disabled');\n return;\n }\n setStatus('disconnected');\n });\n\n s.on('connect_error', () => setStatus('disconnected'));\n\n const timers = invalidateTimers.current;\n return () => {\n for (const t of timers.values()) clearTimeout(t);\n timers.clear();\n s.disconnect();\n setSocket(null);\n setStatus('disconnected');\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [disabled, serverUrl, appId]);\n\n return (\n <RealtimeContext.Provider value={{ socket, status }}>{children}</RealtimeContext.Provider>\n );\n}\n\nexport function useRealtimeContext(): RealtimeContextValue {\n return useContext(RealtimeContext);\n}\n","import { useEffect, useMemo, useState } from 'react';\nimport { useApiQuery, useApiMutation } from '@quanticjs/react-query';\nimport { useToast, cn } from '@quanticjs/react-ui';\n\nexport type NotificationChannel = 'inapp' | 'email';\nexport type DigestPeriod = 'none' | 'hourly' | 'daily';\n\nexport interface NotificationPreferenceDto {\n channel: NotificationChannel;\n type: string;\n enabled: boolean;\n digest: DigestPeriod;\n}\n\nexport interface NotificationPreferencesProps {\n /** API path prefix the engine's preference endpoints are mounted on (through the host app's BFF). */\n basePath?: string;\n /** Optional friendly labels per type key; unknown keys fall back to a derived label. */\n typeLabels?: Record<string, string>;\n className?: string;\n}\n\ninterface RowState {\n type: string;\n inappEnabled: boolean;\n emailEnabled: boolean;\n digest: DigestPeriod;\n}\n\nfunction deriveLabel(type: string): string {\n const stripped = type.replace(/^wfl_/, '').replace(/_/g, ' ');\n return stripped.charAt(0).toUpperCase() + stripped.slice(1);\n}\n\nfunction toRows(prefs: NotificationPreferenceDto[]): RowState[] {\n const byType = new Map<string, RowState>();\n for (const pref of prefs) {\n const row = byType.get(pref.type) ?? {\n type: pref.type,\n inappEnabled: true,\n emailEnabled: true,\n digest: 'none' as DigestPeriod,\n };\n if (pref.channel === 'inapp') {\n row.inappEnabled = pref.enabled;\n } else {\n row.emailEnabled = pref.enabled;\n row.digest = pref.digest;\n }\n byType.set(pref.type, row);\n }\n return [...byType.values()];\n}\n\nfunction toEntries(rows: RowState[]): Array<{\n channel: NotificationChannel;\n type: string;\n enabled: boolean;\n digest?: DigestPeriod;\n}> {\n return rows.flatMap((row) => [\n { channel: 'inapp' as const, type: row.type, enabled: row.inappEnabled },\n { channel: 'email' as const, type: row.type, enabled: row.emailEnabled, digest: row.digest },\n ]);\n}\n\n/**\n * Type × channel preference matrix with per-type email digest selection.\n * Embeddable in any app fronting the QuanticJS notification engine — the\n * host wraps it in its own page chrome and providers (QuanticProvider,\n * QuanticQueryProvider, ToastProvider).\n */\nexport function NotificationPreferences({\n basePath = '/notifications',\n typeLabels,\n className,\n}: NotificationPreferencesProps) {\n const toast = useToast();\n const { data, isLoading, isError, refetch } = useApiQuery<NotificationPreferenceDto[]>(\n ['notifications', 'preferences'],\n (client) => client.get(`${basePath}/preferences`),\n );\n\n const serverRows = useMemo(() => (data ? toRows(data) : []), [data]);\n const [rows, setRows] = useState<RowState[]>(serverRows);\n useEffect(() => setRows(serverRows), [serverRows]);\n\n const mutation = useApiMutation<\n NotificationPreferenceDto[],\n ReturnType<typeof toEntries>\n >((client, entries) => client.put(`${basePath}/preferences`, { entries }), {\n invalidates: [['notifications', 'preferences']],\n onSuccess: () => {\n toast.success('Notification preferences saved');\n },\n onError: (error) => {\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n },\n });\n\n const update = (type: string, patch: Partial<RowState>) => {\n setRows((prev) => prev.map((row) => (row.type === type ? { ...row, ...patch } : row)));\n };\n\n if (isLoading) {\n return (\n <div role=\"status\" aria-label=\"Loading notification preferences\" className={cn('space-y-2', className)}>\n {[0, 1, 2, 3].map((i) => (\n <div key={i} className=\"h-10 animate-pulse rounded-md bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('rounded-md border border-border p-6 text-center', className)}>\n <p className=\"text-sm text-muted-foreground\">Failed to load notification preferences.</p>\n <button\n type=\"button\"\n onClick={() => refetch()}\n className=\"mt-3 rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n if (rows.length === 0) {\n return (\n <div className={cn('rounded-md border border-border p-6 text-center', className)}>\n <p className=\"text-sm text-muted-foreground\">No notification preferences available.</p>\n </div>\n );\n }\n\n return (\n <div className={cn('space-y-4', className)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Notification\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n In-app\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Email\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Email digest\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => {\n const label = typeLabels?.[row.type] ?? deriveLabel(row.type);\n return (\n <tr key={row.type} className=\"border-b border-border\">\n <td className=\"py-3 pe-4\">{label}</td>\n <td className=\"px-4 py-3\">\n <input\n type=\"checkbox\"\n aria-label={`${label} in-app notifications`}\n checked={row.inappEnabled}\n onChange={(e) => update(row.type, { inappEnabled: e.target.checked })}\n />\n </td>\n <td className=\"px-4 py-3\">\n <input\n type=\"checkbox\"\n aria-label={`${label} email notifications`}\n checked={row.emailEnabled}\n onChange={(e) => update(row.type, { emailEnabled: e.target.checked })}\n />\n </td>\n <td className=\"px-4 py-3\">\n <select\n aria-label={`${label} email digest`}\n value={row.digest}\n disabled={!row.emailEnabled}\n onChange={(e) => update(row.type, { digest: e.target.value as DigestPeriod })}\n className=\"rounded-md border border-border bg-background px-2 py-1\"\n >\n <option value=\"none\">Immediately</option>\n <option value=\"hourly\">Hourly digest</option>\n <option value=\"daily\">Daily digest</option>\n </select>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n <button\n type=\"button\"\n onClick={() => mutation.mutate(toEntries(rows))}\n disabled={mutation.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground disabled:opacity-50\"\n >\n {mutation.isPending ? 'Saving…' : 'Save preferences'}\n </button>\n </div>\n );\n}\n","import { useApiQuery } from '@quanticjs/react-query';\nimport { useRealtimeContext } from './notification-realtime-provider';\nimport { useNotificationConfig } from './notification-provider';\n\nexport interface UseUnreadCountOptions {\n /** API path prefix the engine's notification endpoints are mounted on. */\n basePath?: string;\n /** Polling interval in ms when the socket is unavailable. Default: 60_000. */\n pollIntervalMs?: number;\n /** Scope the count to a producing app (its rows + system-wide). Omit for all. */\n appId?: string;\n}\n\n/**\n * Reads the unread badge count. When the realtime socket is connected, the\n * count is kept fresh by socket-driven cache invalidation and polling is\n * disabled; when the socket is down it transparently falls back to REST polling\n * at `pollIntervalMs`. Any option omitted falls back to the ambient\n * `NotificationProvider` config (where the consumer registered its `appId`).\n */\nexport function useUnreadCount(options: UseUnreadCountOptions = {}) {\n const config = useNotificationConfig();\n const basePath = options.basePath ?? config.basePath;\n const pollIntervalMs = options.pollIntervalMs ?? config.pollIntervalMs;\n const appId = options.appId ?? config.appId;\n const { status } = useRealtimeContext();\n const socketUp = status === 'connected';\n const key = appId\n ? ['notifications', 'unread-count', appId]\n : ['notifications', 'unread-count'];\n const url = appId\n ? `${basePath}/unread-count?appId=${encodeURIComponent(appId)}`\n : `${basePath}/unread-count`;\n\n return useApiQuery<{ count: number }>(key, (client) => client.get(url), {\n refetchInterval: socketUp ? false : pollIntervalMs,\n staleTime: socketUp ? Infinity : pollIntervalMs / 2,\n });\n}\n","import { useEffect } from 'react';\nimport { useApiQuery, useApiMutation } from '@quanticjs/react-query';\nimport { useToast } from '@quanticjs/react-ui';\nimport { useRealtimeContext } from './notification-realtime-provider';\nimport { useNotificationConfig } from './notification-provider';\n\nexport interface NotificationFeedItem {\n id: string;\n userId: string;\n type: string;\n title: string;\n body: string;\n metadata: Record<string, unknown> | null;\n isRead: boolean;\n createdAt: string;\n}\n\nexport interface PaginatedFeed {\n items: NotificationFeedItem[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface UseNotificationFeedOptions {\n basePath?: string;\n /** Polling interval in ms when the socket is unavailable. Default: 60_000. */\n pollIntervalMs?: number;\n limit?: number;\n /**\n * Scope the feed to a producing application (SPEC-application-scoping). When\n * set, every request carries `?appId=` so the bell shows only that app's rows\n * plus system-wide notifications. Omit for the unified portal view.\n */\n appId?: string;\n}\n\n/**\n * Fetches the notification feed (list) and exposes mark-read / mark-all-read\n * mutations. Falls back to REST polling when the socket is down. On socket\n * reconnect it emits `backfill:request` with the newest known timestamp so any\n * notifications created during the disconnect gap are pulled in.\n */\nexport function useNotificationFeed(options: UseNotificationFeedOptions = {}) {\n const config = useNotificationConfig();\n const basePath = options.basePath ?? config.basePath;\n const pollIntervalMs = options.pollIntervalMs ?? config.pollIntervalMs;\n const appId = options.appId ?? config.appId;\n const limit = options.limit ?? 50;\n const { socket, status } = useRealtimeContext();\n const socketUp = status === 'connected';\n const toast = useToast();\n const appParam = appId ? `&appId=${encodeURIComponent(appId)}` : '';\n const readAllPath = appId ? `${basePath}/read-all?appId=${encodeURIComponent(appId)}` : `${basePath}/read-all`;\n\n // The engine list endpoint reads `pageSize` (not `limit`); send pageSize so\n // the requested page size is actually honored.\n const query = useApiQuery<PaginatedFeed>(\n ['notifications', { limit, appId }],\n (client) => client.get(`${basePath}?page=1&pageSize=${limit}${appParam}`),\n {\n refetchInterval: socketUp ? false : pollIntervalMs,\n staleTime: socketUp ? Infinity : pollIntervalMs / 2,\n },\n );\n\n // Backfill on (re)connect — ask the server for anything created since the\n // newest item we currently hold.\n useEffect(() => {\n if (!socket) return;\n const onConnect = () => {\n const newest = query.data?.items?.[0]?.createdAt ?? new Date(0).toISOString();\n socket.emit('backfill:request', { since: newest });\n };\n socket.on('connect', onConnect);\n return () => {\n socket.off('connect', onConnect);\n };\n }, [socket, query.data]);\n\n const markRead = useApiMutation<void, string>(\n (client, id) => client.post(`${basePath}/${id}/read`, {}),\n {\n invalidates: [['notifications'], ['notifications', 'unread-count']],\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n const markAllRead = useApiMutation<void, void>(\n (client) => client.post(readAllPath, {}),\n {\n invalidates: [['notifications'], ['notifications', 'unread-count']],\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n return { ...query, markRead, markAllRead };\n}\n","import { cn } from '@quanticjs/react-ui';\nimport { useUnreadCount } from './use-unread-count';\n\nexport interface NotificationBellProps {\n basePath?: string;\n pollIntervalMs?: number;\n /** Scope the unread badge to a producing app (its rows + system-wide). */\n appId?: string;\n /** Invoked when the bell is activated (e.g. to open the inbox panel). */\n onClick?: () => void;\n className?: string;\n}\n\n/**\n * Accessible notification bell with an unread badge. The badge is hidden at\n * zero; the wrapper exposes a live `role=\"status\"` with an `aria-label`\n * describing the count so assistive tech announces changes.\n */\nexport function NotificationBell({\n basePath,\n pollIntervalMs,\n appId,\n onClick,\n className,\n}: NotificationBellProps) {\n // Omitted props fall back to the ambient NotificationProvider config.\n const { data } = useUnreadCount({ basePath, pollIntervalMs, appId });\n const count = data?.count ?? 0;\n const label = count === 0 ? 'No unread notifications' : `${count} unread notifications`;\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label=\"Notifications\"\n className={cn(\n 'relative inline-flex h-10 w-10 items-center justify-center rounded-full text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring',\n className,\n )}\n >\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n className=\"h-5 w-5\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M15 17h5l-1.4-1.4A2 2 0 0118 14.2V11a6 6 0 10-12 0v3.2a2 2 0 01-.6 1.4L4 17h5m6 0a3 3 0 11-6 0m6 0H9\"\n />\n </svg>\n <span role=\"status\" aria-label={label} className=\"sr-only\">\n {label}\n </span>\n {count > 0 && (\n <span\n aria-hidden=\"true\"\n className=\"absolute -end-0.5 -top-0.5 inline-flex min-w-5 items-center justify-center rounded-full bg-coral px-1.5 text-xs font-semibold text-coral-foreground ring-2 ring-background\"\n >\n {count > 99 ? '99+' : count}\n </span>\n )}\n </button>\n );\n}\n","import { cn } from '@quanticjs/react-ui';\nimport { useNotificationFeed, type NotificationFeedItem } from './use-notification-feed';\n\nexport interface NotificationInboxProps {\n basePath?: string;\n pollIntervalMs?: number;\n /** Scope the inbox to a producing app (its rows + system-wide). Omit for all. */\n appId?: string;\n className?: string;\n}\n\n/**\n * Notification inbox panel: renders the feed with loading / error / empty\n * states, marks individual items read on click, and offers a \"Mark all read\"\n * action. All reads invalidate `['notifications']` and\n * `['notifications','unread-count']` so the bell badge converges.\n */\nexport function NotificationInbox({\n basePath,\n pollIntervalMs,\n appId,\n className,\n}: NotificationInboxProps) {\n // Omitted props fall back to the ambient NotificationProvider config.\n const { data, isLoading, isError, refetch, markRead, markAllRead } = useNotificationFeed({\n basePath,\n pollIntervalMs,\n appId,\n });\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading notifications\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading notifications</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-12 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load notifications</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const items = data?.items ?? [];\n\n if (items.length === 0) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No notifications yet\n </div>\n );\n }\n\n return (\n <section aria-label=\"Notifications\" className={cn('flex flex-col', className)}>\n <header className=\"flex items-center justify-between border-b border-border px-4 py-2\">\n <h2 className=\"text-sm font-semibold text-foreground\">Notifications</h2>\n <button\n type=\"button\"\n onClick={() => markAllRead.mutate()}\n disabled={markAllRead.isPending}\n className=\"text-sm text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Mark all read\n </button>\n </header>\n <ul className=\"divide-y divide-border\">\n {items.map((item) => (\n <InboxRow key={item.id} item={item} onMarkRead={() => markRead.mutate(item.id)} />\n ))}\n </ul>\n </section>\n );\n}\n\nfunction InboxRow({\n item,\n onMarkRead,\n}: {\n item: NotificationFeedItem;\n onMarkRead: () => void;\n}) {\n return (\n <li>\n <button\n type=\"button\"\n onClick={onMarkRead}\n aria-label={`${item.title}${item.isRead ? '' : ' (unread)'}`}\n className={cn(\n 'flex w-full flex-col items-start gap-0.5 px-4 py-3 text-start hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring',\n item.isRead ? 'text-muted-foreground' : 'text-foreground',\n )}\n >\n <span className=\"flex items-center gap-2 text-sm font-medium\">\n {!item.isRead && (\n <span aria-hidden=\"true\" className=\"h-2 w-2 rounded-full bg-coral\" />\n )}\n {item.title}\n </span>\n {item.body && <span className=\"text-xs text-muted-foreground\">{item.body}</span>}\n </button>\n </li>\n );\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { cn, useExitAnimation, useFocusTrap } from '@quanticjs/react-ui';\nimport { useUnreadCount } from './use-unread-count';\nimport { NotificationInbox } from './notification-inbox';\n\nexport interface NotificationCenterProps {\n /**\n * Registered app slug to scope to. Omitted → falls back to the ambient\n * `NotificationProvider` config (omit there too, on a shell/portal, for the\n * unified inbox).\n */\n appId?: string;\n basePath?: string;\n pollIntervalMs?: number;\n className?: string;\n /** Class applied to the popover panel. */\n panelClassName?: string;\n}\n\nfunction BellIcon() {\n return (\n <svg\n aria-hidden\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"h-5 w-5\"\n >\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\" />\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\" />\n </svg>\n );\n}\n\n/**\n * Drop-in notification bell with an integrated inbox popover — badge **and**\n * dropdown in one component (the all-in-one shape consumer shells expect). Wrap\n * the app in `<NotificationProvider appId=…>` (or pass `appId` here) so it scopes\n * to the registered app; omit `appId` on a shell/portal for the unified inbox.\n *\n * Focus moves into the panel on open and returns to the trigger on close (the\n * focus trap keys off `open`, not the exit hook's `mounted`, so keyboard users\n * are never trapped during the exit animation).\n *\n * For a bare badge button you compose yourself (custom dropdown), use\n * `NotificationBell` + `NotificationInbox` directly instead.\n */\nexport function NotificationCenter({\n appId,\n basePath,\n pollIntervalMs,\n className,\n panelClassName,\n}: NotificationCenterProps) {\n const [open, setOpen] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const { data } = useUnreadCount({ appId, basePath, pollIntervalMs });\n\n const unreadCount = data?.count ?? 0;\n const badge = unreadCount > 99 ? '99+' : String(unreadCount);\n const label =\n unreadCount === 0 ? 'No unread notifications' : `${unreadCount} unread notifications`;\n\n const close = useCallback(() => setOpen(false), []);\n\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') close();\n };\n const onPointer = (e: MouseEvent) => {\n const c = containerRef.current;\n if (c && e.target instanceof Node && !c.contains(e.target)) close();\n };\n document.addEventListener('keydown', onKey);\n document.addEventListener('mousedown', onPointer);\n return () => {\n document.removeEventListener('keydown', onKey);\n document.removeEventListener('mousedown', onPointer);\n };\n }, [open, close]);\n\n useFocusTrap(panelRef, open);\n const panelExit = useExitAnimation(open);\n\n return (\n <div ref={containerRef} className={cn('relative inline-block', className)}>\n <button\n type=\"button\"\n aria-label={label}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n onClick={() => setOpen((p) => !p)}\n className=\"relative inline-flex h-10 w-10 items-center justify-center rounded-full text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <BellIcon />\n <span role=\"status\" className=\"sr-only\">\n {label}\n </span>\n {unreadCount > 0 && (\n <span\n aria-hidden\n className=\"absolute -end-0.5 -top-0.5 inline-flex min-w-5 items-center justify-center rounded-full bg-coral px-1.5 text-xs font-semibold text-coral-foreground ring-2 ring-background\"\n >\n {badge}\n </span>\n )}\n </button>\n\n {panelExit.mounted && (\n <div\n ref={panelRef}\n role=\"dialog\"\n aria-label=\"Notifications\"\n tabIndex={-1}\n data-state={panelExit.state}\n onAnimationEnd={panelExit.onAnimationEnd}\n className={cn(\n 'absolute end-0 z-(--z-popover) mt-2 w-96 overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-raised',\n panelExit.state === 'open'\n ? 'animate-pop-in'\n : 'animate-pop-out [animation-fill-mode:forwards]',\n panelClassName,\n )}\n >\n <NotificationInbox\n appId={appId}\n basePath={basePath}\n pollIntervalMs={pollIntervalMs}\n className=\"max-h-[28rem] overflow-y-auto\"\n />\n </div>\n )}\n </div>\n );\n}\n","import { useState } from 'react';\nimport { cn } from '@quanticjs/react-ui';\nimport { useDeliveryAnalytics } from './use-delivery-analytics';\nimport { useFunnelStats } from './use-funnel-stats';\nimport { useDeliveryTypes } from './use-delivery-types';\nimport { FunnelStats } from './funnel-stats';\nimport { TrendChart } from './trend-chart';\nimport { TypeTable } from './type-table';\n\nexport interface DeliveryAnalyticsPageProps {\n basePath?: string;\n organizationId?: string;\n className?: string;\n}\n\nconst DEFAULT_FROM = '2026-06-01';\nconst DEFAULT_TO = '2026-06-30';\n\nconst CHANNELS = ['', 'email', 'inapp', 'push', 'sms'] as const;\n\n/**\n * Admin delivery-analytics dashboard: channel/date-range filter, funnel stat\n * cards, per-day trend chart, and a per-type table. Implements the standard\n * loading / error / empty data-list states.\n */\nexport function DeliveryAnalyticsPage({\n basePath = '/analytics/notifications',\n organizationId,\n className,\n}: DeliveryAnalyticsPageProps) {\n const [channel, setChannel] = useState<string>('');\n const [from, setFrom] = useState<string>(DEFAULT_FROM);\n const [to, setTo] = useState<string>(DEFAULT_TO);\n\n const filters = { from, to, channel: channel || undefined, organizationId, basePath };\n const summary = useDeliveryAnalytics(filters);\n const funnel = useFunnelStats(filters);\n const types = useDeliveryTypes({ from, to, organizationId, basePath });\n\n const isLoading = summary.isLoading || funnel.isLoading || types.isLoading;\n const isError = summary.isError || funnel.isError || types.isError;\n\n return (\n <main className={cn('flex flex-col gap-6 p-4 sm:p-6', className)}>\n <header className=\"flex flex-col gap-1\">\n <h1 className=\"text-xl font-semibold text-foreground\">Delivery Analytics</h1>\n <p className=\"text-sm text-muted-foreground\">\n Cross-channel send, open, and click performance.\n </p>\n </header>\n\n <div className=\"flex flex-wrap items-end gap-3\">\n <label className=\"flex flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">Channel</span>\n <select\n value={channel}\n onChange={(e) => setChannel(e.target.value)}\n className=\"rounded border border-border bg-background px-2 py-1.5 text-foreground\"\n >\n {CHANNELS.map((c) => (\n <option key={c || 'all'} value={c}>\n {c === '' ? 'All channels' : c}\n </option>\n ))}\n </select>\n </label>\n <label className=\"flex flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">From</span>\n <input\n type=\"date\"\n value={from}\n onChange={(e) => setFrom(e.target.value)}\n className=\"rounded border border-border bg-background px-2 py-1.5 text-foreground\"\n />\n </label>\n <label className=\"flex flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">To</span>\n <input\n type=\"date\"\n value={to}\n onChange={(e) => setTo(e.target.value)}\n className=\"rounded border border-border bg-background px-2 py-1.5 text-foreground\"\n />\n </label>\n </div>\n\n {isLoading ? (\n <div role=\"status\" aria-label=\"Loading delivery analytics\" className=\"flex flex-col gap-3\">\n <span className=\"sr-only\">Loading delivery analytics</span>\n <div aria-hidden=\"true\" className=\"h-24 animate-pulse rounded bg-muted\" />\n <div aria-hidden=\"true\" className=\"h-72 animate-pulse rounded bg-muted\" />\n </div>\n ) : isError ? (\n <div className=\"flex flex-col items-start gap-3\">\n <p className=\"text-sm text-foreground\">Failed to load delivery analytics</p>\n <button\n type=\"button\"\n onClick={() => {\n void summary.refetch();\n void funnel.refetch();\n void types.refetch();\n }}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n ) : (summary.data?.length ?? 0) === 0 ? (\n <p className=\"rounded border border-border p-6 text-center text-sm text-muted-foreground\">\n No delivery data for the selected range\n </p>\n ) : (\n <div className=\"flex flex-col gap-6\">\n {funnel.data ? <FunnelStats funnel={funnel.data} /> : null}\n <section aria-label=\"Delivery trend\" className=\"rounded-lg border border-border p-4\">\n <h2 className=\"mb-3 text-sm font-semibold text-foreground\">Trend</h2>\n <TrendChart data={summary.data ?? []} />\n </section>\n <section aria-label=\"Delivery by type\" className=\"rounded-lg border border-border p-4\">\n <h2 className=\"mb-3 text-sm font-semibold text-foreground\">By type</h2>\n <TypeTable rows={types.data ?? []} />\n </section>\n </div>\n )}\n </main>\n );\n}\n","import { useApiQuery } from '@quanticjs/react-query';\n\nexport interface DailyDeliveryStats {\n day: string;\n sends: number;\n delivered: number;\n opened: number;\n clicked: number;\n bounced: number;\n failed: number;\n deliveryRate: number;\n openRate: number;\n clickRate: number;\n bounceRate: number;\n}\n\nexport interface DeliveryAnalyticsFilters {\n from: string;\n to: string;\n channel?: string;\n type?: string;\n organizationId?: string;\n}\n\nexport interface UseDeliveryAnalyticsOptions extends DeliveryAnalyticsFilters {\n basePath?: string;\n}\n\nfunction toQuery(filters: DeliveryAnalyticsFilters): string {\n const params = new URLSearchParams();\n params.set('from', filters.from);\n params.set('to', filters.to);\n if (filters.channel) params.set('channel', filters.channel);\n if (filters.type) params.set('type', filters.type);\n if (filters.organizationId) params.set('organizationId', filters.organizationId);\n return params.toString();\n}\n\n/** Per-day delivery summary stats for the selected filters. */\nexport function useDeliveryAnalytics({\n basePath = '/analytics/notifications',\n ...filters\n}: UseDeliveryAnalyticsOptions) {\n return useApiQuery<DailyDeliveryStats[]>(\n ['delivery-analytics', 'summary', filters],\n (client) => client.get(`${basePath}/summary?${toQuery(filters)}`),\n );\n}\n\nexport { toQuery as buildDeliveryAnalyticsQuery };\n","import { useApiQuery } from '@quanticjs/react-query';\nimport { buildDeliveryAnalyticsQuery, type DeliveryAnalyticsFilters } from './use-delivery-analytics';\n\nexport interface DeliveryFunnel {\n sends: number;\n delivered: number;\n opened: number;\n clicked: number;\n bounced: number;\n failed: number;\n openRate: number;\n clickRate: number;\n bounceRate: number;\n deliveryRate: number;\n}\n\nexport interface UseFunnelStatsOptions extends DeliveryAnalyticsFilters {\n basePath?: string;\n}\n\n/** Single aggregated funnel over the selected date range. */\nexport function useFunnelStats({\n basePath = '/analytics/notifications',\n ...filters\n}: UseFunnelStatsOptions) {\n return useApiQuery<DeliveryFunnel>(\n ['delivery-analytics', 'funnel', filters],\n (client) => client.get(`${basePath}/funnel?${buildDeliveryAnalyticsQuery(filters)}`),\n );\n}\n","import { useApiQuery } from '@quanticjs/react-query';\nimport type { DeliveryAnalyticsFilters } from './use-delivery-analytics';\n\nexport interface DeliveryTypeBreakdown {\n type: string;\n sends: number;\n delivered: number;\n opened: number;\n clicked: number;\n bounced: number;\n failed: number;\n openRate: number;\n clickRate: number;\n}\n\nexport interface UseDeliveryTypesOptions\n extends Pick<DeliveryAnalyticsFilters, 'from' | 'to' | 'organizationId'> {\n basePath?: string;\n}\n\n/** Per-type breakdown sorted by send volume descending. */\nexport function useDeliveryTypes({\n basePath = '/analytics/notifications',\n ...filters\n}: UseDeliveryTypesOptions) {\n const params = new URLSearchParams();\n params.set('from', filters.from);\n params.set('to', filters.to);\n if (filters.organizationId) params.set('organizationId', filters.organizationId);\n\n return useApiQuery<DeliveryTypeBreakdown[]>(\n ['delivery-analytics', 'types', filters],\n (client) => client.get(`${basePath}/types?${params.toString()}`),\n );\n}\n","import { cn } from '@quanticjs/react-ui';\nimport type { DeliveryFunnel } from './use-funnel-stats';\n\nexport interface FunnelStatsProps {\n funnel: DeliveryFunnel;\n className?: string;\n}\n\nconst pct = (n: number) => `${(n * 100).toFixed(1)}%`;\n\n/** Funnel stat cards: sends → delivered → opened → clicked, plus key rates. */\nexport function FunnelStats({ funnel, className }: FunnelStatsProps) {\n const cards: Array<{ label: string; value: string }> = [\n { label: 'Sends', value: String(funnel.sends) },\n { label: 'Delivered', value: String(funnel.delivered) },\n { label: 'Opened', value: String(funnel.opened) },\n { label: 'Clicked', value: String(funnel.clicked) },\n { label: 'Open rate', value: pct(funnel.openRate) },\n { label: 'Click rate', value: pct(funnel.clickRate) },\n { label: 'Bounce rate', value: pct(funnel.bounceRate) },\n { label: 'Delivery rate', value: pct(funnel.deliveryRate) },\n ];\n\n return (\n <ul className={cn('grid grid-cols-2 gap-3 sm:grid-cols-4', className)} aria-label=\"Delivery funnel\">\n {cards.map((c) => (\n <li\n key={c.label}\n className=\"flex flex-col gap-1 rounded-lg border border-border bg-card p-4\"\n >\n <span className=\"text-xs font-medium text-muted-foreground\">{c.label}</span>\n <span className=\"text-2xl font-semibold text-foreground\">{c.value}</span>\n </li>\n ))}\n </ul>\n );\n}\n","import { cn } from '@quanticjs/react-ui';\nimport {\n CartesianGrid,\n Line,\n LineChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from 'recharts';\nimport type { DailyDeliveryStats } from './use-delivery-analytics';\n\nexport interface TrendChartProps {\n data: DailyDeliveryStats[];\n className?: string;\n}\n\n/**\n * Per-day delivery trend line chart (sends / delivered / opened / clicked).\n * Route-split-friendly — recharts is only loaded with the analytics page.\n */\nexport function TrendChart({ data, className }: TrendChartProps) {\n return (\n <div className={cn('h-72 w-full', className)} role=\"img\" aria-label=\"Delivery trend over time\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <LineChart data={data} margin={{ top: 8, right: 16, bottom: 8, left: 0 }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke=\"var(--border)\" />\n <XAxis dataKey=\"day\" stroke=\"var(--muted-foreground)\" fontSize={12} />\n <YAxis stroke=\"var(--muted-foreground)\" fontSize={12} allowDecimals={false} />\n <Tooltip />\n <Line type=\"monotone\" dataKey=\"sends\" stroke=\"var(--primary)\" dot={false} />\n <Line type=\"monotone\" dataKey=\"delivered\" stroke=\"var(--chart-2, var(--primary))\" dot={false} />\n <Line type=\"monotone\" dataKey=\"opened\" stroke=\"var(--chart-3, var(--primary))\" dot={false} />\n <Line type=\"monotone\" dataKey=\"clicked\" stroke=\"var(--chart-4, var(--primary))\" dot={false} />\n </LineChart>\n </ResponsiveContainer>\n </div>\n );\n}\n","import { cn } from '@quanticjs/react-ui';\nimport type { DeliveryTypeBreakdown } from './use-delivery-types';\n\nexport interface TypeTableProps {\n rows: DeliveryTypeBreakdown[];\n className?: string;\n}\n\nconst pct = (n: number) => `${(n * 100).toFixed(1)}%`;\n\n/** Per-notification-type delivery breakdown, sorted by send volume. */\nexport function TypeTable({ rows, className }: TypeTableProps) {\n return (\n <table className={cn('w-full border-collapse text-sm', className)}>\n <caption className=\"sr-only\">Delivery breakdown by notification type</caption>\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">Type</th>\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">Sends</th>\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">Delivered</th>\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">Open rate</th>\n <th scope=\"col\" className=\"py-2 font-medium\">Click rate</th>\n </tr>\n </thead>\n <tbody>\n {rows.map((r) => (\n <tr key={r.type} className=\"border-b border-border/50\">\n <td className=\"py-2 pe-4 font-medium text-foreground\">{r.type}</td>\n <td className=\"py-2 pe-4 text-foreground\">{r.sends}</td>\n <td className=\"py-2 pe-4 text-foreground\">{r.delivered}</td>\n <td className=\"py-2 pe-4 text-foreground\">{pct(r.openRate)}</td>\n <td className=\"py-2 text-foreground\">{pct(r.clickRate)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n","import { cn } from '@quanticjs/react-ui';\n\nexport type TemplateStatus = 'draft' | 'published' | 'archived' | string;\n\nconst STATUS_STYLES: Record<string, string> = {\n draft: 'bg-muted text-muted-foreground',\n published: 'bg-primary text-primary-foreground',\n archived: 'bg-secondary text-secondary-foreground',\n};\n\n/**\n * Small status pill shared across the template admin components. Falls back to\n * a neutral style for unknown status values. Semantic tokens only — no hex.\n */\nexport function TemplateStatusBadge({\n status,\n className,\n}: {\n status: TemplateStatus;\n className?: string;\n}) {\n const style = STATUS_STYLES[status] ?? 'bg-muted text-muted-foreground';\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize',\n style,\n className,\n )}\n >\n {status}\n </span>\n );\n}\n","import { cn } from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\nimport { TemplateStatusBadge, type TemplateStatus } from './template-status-badge';\n\nexport interface TemplateListItem {\n templateId: string;\n locales: string[];\n latestStatus: TemplateStatus;\n versionCount: number;\n}\n\nexport interface TemplateListProps {\n /** API path the template admin endpoints are mounted on (through the BFF). */\n basePath?: string;\n className?: string;\n}\n\n/**\n * Admin data-list of notification templates. Renders the template id, the\n * latest version status, available locales, and version count with full\n * loading / error / empty / happy coverage.\n */\nexport function TemplateList({ basePath = '/api/templates', className }: TemplateListProps) {\n const { data, isLoading, isError, refetch } = useApiQuery<TemplateListItem[]>(\n ['templates', basePath],\n (client) => client.get(basePath),\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading templates\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading templates</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-12 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load templates</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const items = data ?? [];\n\n if (items.length === 0) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No templates found\n </div>\n );\n }\n\n return (\n <section aria-label=\"Templates\" className={cn('flex flex-col', className)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Template\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Locales\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Versions\n </th>\n </tr>\n </thead>\n <tbody>\n {items.map((item) => (\n <tr key={item.templateId} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 font-medium text-foreground\">{item.templateId}</td>\n <td className=\"px-4 py-3\">\n <TemplateStatusBadge status={item.latestStatus} />\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">{item.locales.join(', ')}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{item.versionCount}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </section>\n );\n}\n","import { useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation } from '@quanticjs/react-query';\nimport { TemplateStatusBadge, type TemplateStatus } from './template-status-badge';\n\nexport interface TemplateEditorFields {\n subject: string;\n heading: string;\n body: string;\n cta: string;\n html: string;\n}\n\nexport interface TemplateVersionResponse {\n id: string;\n versionNumber: number;\n status: TemplateStatus;\n}\n\nexport interface TemplateEditorProps {\n templateId: string;\n /** Existing version id to publish; falls back to the id returned by the draft save. */\n versionId?: string;\n initialFields?: Partial<TemplateEditorFields>;\n initialStatus?: TemplateStatus;\n basePath?: string;\n className?: string;\n}\n\nconst FIELD_DEFS: Array<{ key: keyof TemplateEditorFields; label: string; multiline: boolean }> = [\n { key: 'subject', label: 'Subject', multiline: false },\n { key: 'heading', label: 'Heading', multiline: false },\n { key: 'body', label: 'Body', multiline: true },\n { key: 'cta', label: 'CTA label', multiline: false },\n { key: 'html', label: 'HTML', multiline: true },\n];\n\n/** Returns true when {{ and }} counts are balanced. */\nfunction bracesBalanced(value: string): boolean {\n const open = (value.match(/\\{\\{/g) ?? []).length;\n const close = (value.match(/\\}\\}/g) ?? []).length;\n return open === close;\n}\n\n/**\n * Template draft editor. Validates Handlebars brace balance client-side before\n * submitting; saves a draft via PUT and offers a publish action. Surfaces\n * field-level errors and ApiError-aware toasts.\n */\nexport function TemplateEditor({\n templateId,\n versionId,\n initialFields,\n initialStatus = 'draft',\n basePath = '/api/templates',\n className,\n}: TemplateEditorProps) {\n const toast = useToast();\n const [fields, setFields] = useState<TemplateEditorFields>({\n subject: initialFields?.subject ?? '',\n heading: initialFields?.heading ?? '',\n body: initialFields?.body ?? '',\n cta: initialFields?.cta ?? '',\n html: initialFields?.html ?? '',\n });\n const [errors, setErrors] = useState<Partial<Record<keyof TemplateEditorFields, string>>>({});\n const [status, setStatus] = useState<TemplateStatus>(initialStatus);\n const [activeVersionId, setActiveVersionId] = useState<string | undefined>(versionId);\n\n const save = useApiMutation<TemplateVersionResponse, TemplateEditorFields>(\n (client, payload) => client.put(`${basePath}/${templateId}`, payload),\n {\n invalidates: [['templates']],\n onSuccess: (result) => {\n setStatus(result.status);\n setActiveVersionId(result.id);\n toast.success('Draft saved');\n },\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n const publish = useApiMutation<TemplateVersionResponse, string>(\n (client, vid) => client.post(`${basePath}/${templateId}/versions/${vid}/publish`, {}),\n {\n invalidates: [['templates']],\n onSuccess: () => {\n setStatus('published');\n toast.success('Version published');\n },\n onError: (error) =>\n toast.error(\n error.isConflict\n ? 'Version already published'\n : error.isServerError\n ? 'Something went wrong'\n : error.title,\n { description: `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})` },\n ),\n },\n );\n\n const validate = (): boolean => {\n const next: Partial<Record<keyof TemplateEditorFields, string>> = {};\n for (const { key } of FIELD_DEFS) {\n if (!bracesBalanced(fields[key])) {\n next[key] = 'Unbalanced Handlebars braces — every {{ needs a matching }}';\n }\n }\n setErrors(next);\n return Object.keys(next).length === 0;\n };\n\n const onSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n if (!validate()) return;\n save.mutate(fields);\n };\n\n return (\n <form onSubmit={onSubmit} className={cn('flex flex-col gap-4', className)} noValidate>\n <header className=\"flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold text-foreground\">Edit template: {templateId}</h2>\n <TemplateStatusBadge status={status} />\n </header>\n\n {FIELD_DEFS.map(({ key, label, multiline }) => {\n const fieldId = `template-${key}`;\n const errorId = `${fieldId}-error`;\n const error = errors[key];\n return (\n <div key={key} className=\"flex flex-col gap-1\">\n <label htmlFor={fieldId} className=\"text-sm font-medium text-foreground\">\n {label}\n </label>\n {multiline ? (\n <textarea\n id={fieldId}\n value={fields[key]}\n rows={4}\n aria-invalid={error ? 'true' : undefined}\n aria-describedby={error ? errorId : undefined}\n onChange={(e) => setFields((prev) => ({ ...prev, [key]: e.target.value }))}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n ) : (\n <input\n id={fieldId}\n type=\"text\"\n value={fields[key]}\n aria-invalid={error ? 'true' : undefined}\n aria-describedby={error ? errorId : undefined}\n onChange={(e) => setFields((prev) => ({ ...prev, [key]: e.target.value }))}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n )}\n {error && (\n <p id={errorId} className=\"text-xs text-destructive\">\n {error}\n </p>\n )}\n </div>\n );\n })}\n\n <div className=\"flex items-center gap-3\">\n <button\n type=\"submit\"\n disabled={save.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {save.isPending ? 'Saving…' : 'Save draft'}\n </button>\n <button\n type=\"button\"\n disabled={!activeVersionId || publish.isPending}\n onClick={() => activeVersionId && publish.mutate(activeVersionId)}\n className=\"rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {publish.isPending ? 'Publishing…' : 'Publish'}\n </button>\n </div>\n </form>\n );\n}\n","import { useEffect } from 'react';\nimport { cn } from '@quanticjs/react-ui';\nimport { useApiMutation } from '@quanticjs/react-query';\n\nexport interface PreviewResult {\n subject: string;\n html: string;\n text: string;\n}\n\nexport interface TemplatePreviewPaneProps {\n templateId: string;\n versionId: string;\n /** Sample variables passed to the render. */\n vars?: Record<string, unknown>;\n basePath?: string;\n className?: string;\n}\n\n/**\n * Renders a server-side preview of a template version. POSTs the version id and\n * sample vars, then displays the rendered subject, sandboxed HTML, and plaintext.\n */\nexport function TemplatePreviewPane({\n templateId,\n versionId,\n vars = {},\n basePath = '/api/templates',\n className,\n}: TemplatePreviewPaneProps) {\n const preview = useApiMutation<PreviewResult, { versionId: string; vars: Record<string, unknown> }>(\n (client, payload) => client.post(`${basePath}/${templateId}/preview`, payload),\n );\n\n const { mutate, data, isPending, isError } = preview;\n\n useEffect(() => {\n mutate({ versionId, vars });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [templateId, versionId]);\n\n if (isPending) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading preview\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading preview</span>\n <div aria-hidden=\"true\" className=\"h-6 w-1/2 animate-pulse rounded bg-muted\" />\n <div aria-hidden=\"true\" className=\"h-40 animate-pulse rounded bg-muted\" />\n </div>\n );\n }\n\n if (isError || !data) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load preview</p>\n <button\n type=\"button\"\n onClick={() => mutate({ versionId, vars })}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n return (\n <section aria-label=\"Template preview\" className={cn('flex flex-col gap-4', className)}>\n <h2 className=\"text-sm font-semibold text-foreground\">{data.subject}</h2>\n <iframe\n title=\"Email preview\"\n sandbox=\"\"\n srcDoc={data.html}\n className=\"h-96 w-full rounded-md border border-border bg-background\"\n />\n <div className=\"flex flex-col gap-1\">\n <h3 className=\"text-xs font-medium text-muted-foreground\">Plain text</h3>\n <pre className=\"overflow-auto whitespace-pre-wrap rounded-md border border-border bg-muted p-3 text-xs text-foreground\">\n {data.text}\n </pre>\n </div>\n </section>\n );\n}\n","import { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiQuery, useApiMutation } from '@quanticjs/react-query';\nimport { TemplateStatusBadge, type TemplateStatus } from './template-status-badge';\n\nexport interface TemplateVersion {\n id: string;\n versionNumber: number;\n status: TemplateStatus;\n createdBy: string;\n createdAt: string;\n locale: string;\n}\n\nexport interface TemplateVersionHistoryProps {\n templateId: string;\n basePath?: string;\n className?: string;\n /** Whether the roll back action is offered for archived versions. */\n canRollback?: boolean;\n}\n\n/**\n * Version history data-list for a template. Lists every version with its status,\n * author, and date, and offers a roll back action for archived versions.\n */\nexport function TemplateVersionHistory({\n templateId,\n basePath = '/api/templates',\n className,\n canRollback = true,\n}: TemplateVersionHistoryProps) {\n const toast = useToast();\n const versionsKey = ['templates', templateId, 'versions'] as const;\n\n const { data, isLoading, isError, refetch } = useApiQuery<TemplateVersion[]>(\n versionsKey,\n (client) => client.get(`${basePath}/${templateId}/versions`),\n );\n\n const rollback = useApiMutation<TemplateVersion, string>(\n (client, id) => client.post(`${basePath}/${templateId}/versions/${id}/rollback`, {}),\n {\n invalidates: [[...versionsKey], ['templates']],\n onSuccess: () => toast.success('Version rolled back'),\n onError: (error) =>\n toast.error(\n error.isConflict\n ? 'Version cannot be rolled back'\n : error.isServerError\n ? 'Something went wrong'\n : error.title,\n { description: `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})` },\n ),\n },\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading versions\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading versions</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load versions</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const versions = data ?? [];\n\n if (versions.length === 0) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No versions\n </div>\n );\n }\n\n return (\n <section aria-label=\"Version history\" className={cn('flex flex-col', className)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Version\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Author\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Date\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n <span className=\"sr-only\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {versions.map((version) => (\n <tr key={version.id} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 font-medium text-foreground\">v{version.versionNumber}</td>\n <td className=\"px-4 py-3\">\n <TemplateStatusBadge status={version.status} />\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">{version.createdBy}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{version.createdAt}</td>\n <td className=\"px-4 py-3 text-end\">\n {canRollback && version.status === 'archived' && (\n <button\n type=\"button\"\n disabled={rollback.isPending}\n onClick={() => rollback.mutate(version.id)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Roll back\n </button>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </section>\n );\n}\n","import { useState } from 'react';\nimport { cn } from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\nimport { TemplateStatusBadge, type TemplateStatus } from './template-status-badge';\n\nexport interface DeliveryLogRow {\n id: string;\n recipientEmail: string;\n status: TemplateStatus;\n attempts: number;\n lastError: string | null;\n createdAt: string;\n}\n\nexport interface DeliveryLogPage {\n items: DeliveryLogRow[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface DeliveryLogViewerProps {\n templateId: string;\n basePath?: string;\n className?: string;\n}\n\nconst LIMIT = 20;\n\n/**\n * Paginated viewer for email delivery logs filtered by template. Renders\n * recipient, status, attempt count, and the last error per row.\n */\nexport function DeliveryLogViewer({\n templateId,\n basePath = '/api/templates',\n className,\n}: DeliveryLogViewerProps) {\n const [page, setPage] = useState(1);\n\n const { data, isLoading, isError, refetch } = useApiQuery<DeliveryLogPage>(\n ['templates', templateId, 'delivery-logs', page],\n (client) => client.get(`${basePath}/${templateId}/delivery-logs?page=${page}&limit=${LIMIT}`),\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading delivery logs\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading delivery logs</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load delivery logs</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const rows = data?.items ?? [];\n const totalPages = data?.totalPages ?? 1;\n\n if (rows.length === 0) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No delivery logs\n </div>\n );\n }\n\n return (\n <section aria-label=\"Delivery logs\" className={cn('flex flex-col gap-3', className)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Recipient\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Attempts\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Last error\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 text-foreground\">{row.recipientEmail}</td>\n <td className=\"px-4 py-3\">\n <TemplateStatusBadge status={row.status} />\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.attempts}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.lastError ?? '—'}</td>\n </tr>\n ))}\n </tbody>\n </table>\n <nav aria-label=\"Delivery log pagination\" className=\"flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n disabled={page <= 1}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Previous\n </button>\n <span className=\"text-xs text-muted-foreground\">\n Page {page} of {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.min(totalPages, p + 1))}\n disabled={page >= totalPages}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Next\n </button>\n </nav>\n </section>\n );\n}\n","import { useApiQuery } from '@quanticjs/react-query';\n\nexport interface BroadcastListItem {\n id: string;\n templateId: string;\n type: string | null;\n status: string;\n channels: string[];\n totalRecipients: number;\n sentCount: number;\n failedCount: number;\n skippedCount: number;\n createdBy: string;\n startedAt: string | null;\n completedAt: string | null;\n createdAt: string;\n}\n\nexport interface BroadcastListPage {\n items: BroadcastListItem[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface UseBroadcastsOptions {\n page?: number;\n status?: string;\n basePath?: string;\n}\n\nconst LIMIT = 20;\n\n/** Paginated broadcast history. Optionally filters by status. */\nexport function useBroadcasts({ page = 1, status, basePath = '/api' }: UseBroadcastsOptions = {}) {\n const statusParam = status ? `&status=${encodeURIComponent(status)}` : '';\n return useApiQuery<BroadcastListPage>(['broadcasts', { page, status }], (client) =>\n client.get(`${basePath}/v1/broadcasts?page=${page}&limit=${LIMIT}${statusParam}`),\n );\n}\n","import { useState } from 'react';\nimport { cn, formatDateTime, StatusBadge, type StatusBadgeVariant } from '@quanticjs/react-ui';\nimport { useBroadcasts, type BroadcastListItem } from './use-broadcasts';\n\nexport interface BroadcastListProps {\n basePath?: string;\n status?: string;\n onSelect?: (id: string) => void;\n className?: string;\n}\n\nfunction statusVariant(status: string): StatusBadgeVariant {\n switch (status) {\n case 'completed':\n return 'success';\n case 'completed_with_errors':\n return 'warning';\n case 'failed':\n return 'destructive';\n case 'cancelled':\n return 'neutral';\n case 'in_progress':\n case 'running':\n case 'pending':\n return 'info';\n default:\n return 'neutral';\n }\n}\n\n/**\n * Paginated table of broadcast history. Renders template, status, channels,\n * sent/failed/skipped counts, creator, and creation time. When `onSelect` is\n * supplied each row becomes a button to drill into that broadcast.\n */\nexport function BroadcastList({\n basePath = '/api',\n status,\n onSelect,\n className,\n}: BroadcastListProps) {\n const [page, setPage] = useState(1);\n const { data, isLoading, isError, refetch } = useBroadcasts({ page, status, basePath });\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading broadcasts\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading broadcasts</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load broadcasts</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const rows = data?.items ?? [];\n const totalPages = data?.totalPages ?? 1;\n\n if (rows.length === 0) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No broadcasts\n </div>\n );\n }\n\n const renderTemplateCell = (row: BroadcastListItem) =>\n onSelect ? (\n <button\n type=\"button\"\n onClick={() => onSelect(row.id)}\n className=\"rounded text-start font-medium text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n {row.templateId}\n </button>\n ) : (\n <span className=\"text-foreground\">{row.templateId}</span>\n );\n\n return (\n <section aria-label=\"Broadcasts\" className={cn('flex flex-col gap-3', className)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Template\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Channels\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Sent / Failed / Skipped\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created by\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border\">\n <td className=\"py-3 pe-4\">{renderTemplateCell(row)}</td>\n <td className=\"px-4 py-3\">\n <StatusBadge variant={statusVariant(row.status)}>{row.status}</StatusBadge>\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {row.channels.length > 0 ? row.channels.join(', ') : '—'}\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {row.sentCount} / {row.failedCount} / {row.skippedCount}\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.createdBy}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{formatDateTime(row.createdAt)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n <nav aria-label=\"Broadcast pagination\" className=\"flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n disabled={page <= 1}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Previous\n </button>\n <span className=\"text-xs text-muted-foreground\">\n Page {page} of {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.min(totalPages, p + 1))}\n disabled={page >= totalPages}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Next\n </button>\n </nav>\n </section>\n );\n}\n","import { cn, useToast, StatusBadge, type StatusBadgeVariant } from '@quanticjs/react-ui';\nimport { useApiQuery, useApiMutation } from '@quanticjs/react-query';\n\nexport interface BroadcastDetail {\n id: string;\n templateId: string;\n status: string;\n channels: string[];\n totalRecipients: number;\n sentCount: number;\n failedCount: number;\n skippedCount: number;\n startedAt: string | null;\n completedAt: string | null;\n createdAt: string;\n}\n\nexport interface BroadcastProgressProps {\n broadcastId: string;\n basePath?: string;\n onCancelled?: () => void;\n className?: string;\n}\n\nconst TERMINAL_STATUSES = ['completed', 'completed_with_errors', 'failed', 'cancelled'];\n\nfunction isTerminalStatus(status: string | undefined): boolean {\n return status !== undefined && TERMINAL_STATUSES.includes(status);\n}\n\nfunction statusVariant(status: string): StatusBadgeVariant {\n switch (status) {\n case 'completed':\n return 'success';\n case 'completed_with_errors':\n return 'warning';\n case 'failed':\n return 'destructive';\n case 'cancelled':\n return 'neutral';\n default:\n return 'info';\n }\n}\n\n/**\n * Live progress for a single broadcast. Polls every 5s while the status is\n * non-terminal, then stops. Shows sent/failed/skipped/total counters, a\n * progress bar, and a Cancel action.\n */\nexport function BroadcastProgress({\n broadcastId,\n basePath = '/api',\n onCancelled,\n className,\n}: BroadcastProgressProps) {\n const toast = useToast();\n\n const { data, isLoading, isError, refetch } = useApiQuery<BroadcastDetail>(\n ['broadcasts', broadcastId],\n (client) => client.get(`${basePath}/v1/broadcasts/${broadcastId}`),\n {\n refetchInterval: (query) => (isTerminalStatus(query.state.data?.status) ? false : 5000),\n },\n );\n\n const cancel = useApiMutation<void, void>(\n (client) => client.delete(`${basePath}/v1/broadcasts/${broadcastId}`),\n {\n invalidates: [['broadcasts']],\n onSuccess: () => {\n toast.success('Broadcast cancelled');\n onCancelled?.();\n },\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading broadcast\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading broadcast</span>\n {[0, 1].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load broadcast</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n if (!data) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No broadcast\n </div>\n );\n }\n\n const total = data.totalRecipients;\n const processed = data.sentCount + data.failedCount + data.skippedCount;\n const pct = total > 0 ? Math.min(100, Math.round((processed / total) * 100)) : 0;\n const terminal = isTerminalStatus(data.status);\n\n return (\n <section aria-label=\"Broadcast progress\" className={cn('flex flex-col gap-4 p-4', className)}>\n <header className=\"flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold text-foreground\">Broadcast {data.templateId}</h2>\n <StatusBadge variant={statusVariant(data.status)} appearance=\"solid\">\n {data.status}\n </StatusBadge>\n </header>\n\n <div\n role=\"progressbar\"\n aria-valuenow={pct}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label=\"Broadcast completion\"\n className=\"h-2 w-full overflow-hidden rounded-full bg-muted\"\n >\n <div className=\"h-full rounded-full bg-primary\" style={{ width: `${pct}%` }} />\n </div>\n <p className=\"text-xs text-muted-foreground\">\n {processed} of {total} processed ({pct}%)\n </p>\n\n <dl className=\"grid grid-cols-2 gap-3 text-sm sm:grid-cols-4\">\n <div className=\"flex flex-col rounded-md border border-border bg-card p-3\">\n <dt className=\"text-xs text-muted-foreground\">Sent</dt>\n <dd className=\"text-foreground\">{data.sentCount}</dd>\n </div>\n <div className=\"flex flex-col rounded-md border border-border bg-card p-3\">\n <dt className=\"text-xs text-muted-foreground\">Failed</dt>\n <dd className=\"text-foreground\">{data.failedCount}</dd>\n </div>\n <div className=\"flex flex-col rounded-md border border-border bg-card p-3\">\n <dt className=\"text-xs text-muted-foreground\">Skipped</dt>\n <dd className=\"text-foreground\">{data.skippedCount}</dd>\n </div>\n <div className=\"flex flex-col rounded-md border border-border bg-card p-3\">\n <dt className=\"text-xs text-muted-foreground\">Total</dt>\n <dd className=\"text-foreground\">{total}</dd>\n </div>\n </dl>\n\n <div>\n <button\n type=\"button\"\n disabled={terminal || cancel.isPending}\n onClick={() => cancel.mutate()}\n className=\"rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {cancel.isPending ? 'Cancelling…' : 'Cancel'}\n </button>\n </div>\n </section>\n );\n}\n","import { useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiQuery, useApiMutation } from '@quanticjs/react-query';\n\nexport interface TemplateOption {\n id: string;\n name?: string;\n}\n\nexport interface SegmentOption {\n id: string;\n name: string;\n}\n\ninterface ItemsWrapper<T> {\n items: T[];\n}\n\nexport interface BroadcastCreatedResult {\n id: string;\n}\n\ninterface BroadcastCreateBody {\n templateId: string;\n channels: string[];\n type: string | null;\n segmentId: string | null;\n recipientIds: string[] | null;\n idempotencyKey: string;\n}\n\nexport interface BroadcastComposerProps {\n basePath?: string;\n onCreated?: (id: string) => void;\n className?: string;\n}\n\ntype AudienceMode = 'segment' | 'recipients';\n\nconst CHANNELS = ['inapp', 'email', 'push', 'sms', 'webhook', 'slack', 'teams'] as const;\n\ninterface ComposerErrors {\n templateId?: string;\n channels?: string;\n audience?: string;\n}\n\n/** Normalizes either an array or an `{ items }` wrapper into a plain array. */\nfunction normalizeList<T>(data: T[] | ItemsWrapper<T> | undefined): T[] {\n if (!data) return [];\n if (Array.isArray(data)) return data;\n return data.items ?? [];\n}\n\nfunction parseRecipients(raw: string): string[] {\n return raw\n .split(/[\\n,]/)\n .map((r) => r.trim())\n .filter((r) => r.length > 0);\n}\n\n/**\n * Compose and dispatch a broadcast. Loads templates and segments, lets the user\n * pick channels and either a segment or an explicit recipient list, and submits\n * with a stable idempotency key per compose session.\n */\nexport function BroadcastComposer({\n basePath = '/api',\n onCreated,\n className,\n}: BroadcastComposerProps) {\n const toast = useToast();\n const [idempotencyKey] = useState(() => crypto.randomUUID());\n\n const [templateId, setTemplateId] = useState('');\n const [channels, setChannels] = useState<string[]>([]);\n const [audienceMode, setAudienceMode] = useState<AudienceMode>('segment');\n const [segmentId, setSegmentId] = useState('');\n const [recipientsRaw, setRecipientsRaw] = useState('');\n const [type, setType] = useState('');\n const [errors, setErrors] = useState<ComposerErrors>({});\n\n const templatesQuery = useApiQuery<TemplateOption[] | ItemsWrapper<TemplateOption>>(\n ['templates'],\n (client) => client.get(`${basePath}/templates`),\n );\n\n const segmentsQuery = useApiQuery<SegmentOption[] | ItemsWrapper<SegmentOption>>(\n ['segments'],\n (client) => client.get(`${basePath}/v1/segments`),\n );\n\n const create = useApiMutation<BroadcastCreatedResult, BroadcastCreateBody>(\n (client, payload) => client.post(`${basePath}/v1/broadcasts`, payload),\n {\n invalidates: [['broadcasts']],\n onSuccess: (result) => {\n toast.success('Broadcast created');\n onCreated?.(result.id);\n },\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n const isLoading = templatesQuery.isLoading || segmentsQuery.isLoading;\n const isError = templatesQuery.isError || segmentsQuery.isError;\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading broadcast composer\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading broadcast composer</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load broadcast composer</p>\n <button\n type=\"button\"\n onClick={() => {\n void templatesQuery.refetch();\n void segmentsQuery.refetch();\n }}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const templates = normalizeList(templatesQuery.data);\n const segments = normalizeList(segmentsQuery.data);\n\n const toggleChannel = (channel: string) => {\n setChannels((prev) =>\n prev.includes(channel) ? prev.filter((c) => c !== channel) : [...prev, channel],\n );\n };\n\n const validate = (recipientIds: string[]): boolean => {\n const next: ComposerErrors = {};\n if (!templateId) next.templateId = 'Select a template';\n if (channels.length === 0) next.channels = 'Select at least one channel';\n if (audienceMode === 'segment' && !segmentId) {\n next.audience = 'Select a segment';\n }\n if (audienceMode === 'recipients' && recipientIds.length === 0) {\n next.audience = 'Add at least one recipient id';\n }\n setErrors(next);\n return Object.keys(next).length === 0;\n };\n\n const onSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n const recipientIds = parseRecipients(recipientsRaw);\n if (!validate(recipientIds)) return;\n create.mutate({\n templateId,\n channels,\n type: type.trim() ? type.trim() : null,\n segmentId: audienceMode === 'segment' ? segmentId : null,\n recipientIds: audienceMode === 'recipients' ? recipientIds : null,\n idempotencyKey,\n });\n };\n\n return (\n <form onSubmit={onSubmit} className={cn('flex flex-col gap-4 p-4', className)} noValidate>\n <h2 className=\"text-sm font-semibold text-foreground\">New broadcast</h2>\n\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"composer-template\" className=\"text-sm font-medium text-foreground\">\n Template\n </label>\n <select\n id=\"composer-template\"\n value={templateId}\n aria-invalid={errors.templateId ? 'true' : undefined}\n aria-describedby={errors.templateId ? 'composer-template-error' : undefined}\n onChange={(e) => setTemplateId(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <option value=\"\">Select a template…</option>\n {templates.map((t) => (\n <option key={t.id} value={t.id}>\n {t.name ?? t.id}\n </option>\n ))}\n </select>\n {errors.templateId && (\n <p id=\"composer-template-error\" className=\"text-xs text-destructive\">\n {errors.templateId}\n </p>\n )}\n </div>\n\n <fieldset\n className=\"flex flex-col gap-2\"\n aria-invalid={errors.channels ? 'true' : undefined}\n aria-describedby={errors.channels ? 'composer-channels-error' : undefined}\n >\n <legend className=\"text-sm font-medium text-foreground\">Channels</legend>\n <div className=\"flex flex-wrap gap-3\">\n {CHANNELS.map((channel) => {\n const checkboxId = `composer-channel-${channel}`;\n return (\n <label\n key={channel}\n htmlFor={checkboxId}\n className=\"flex items-center gap-2 text-sm text-foreground\"\n >\n <input\n id={checkboxId}\n type=\"checkbox\"\n checked={channels.includes(channel)}\n onChange={() => toggleChannel(channel)}\n className=\"rounded border-border focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n {channel}\n </label>\n );\n })}\n </div>\n {errors.channels && (\n <p id=\"composer-channels-error\" className=\"text-xs text-destructive\">\n {errors.channels}\n </p>\n )}\n </fieldset>\n\n <fieldset className=\"flex flex-col gap-2\">\n <legend className=\"text-sm font-medium text-foreground\">Audience</legend>\n <div className=\"flex gap-4\">\n <label\n htmlFor=\"composer-audience-segment\"\n className=\"flex items-center gap-2 text-sm text-foreground\"\n >\n <input\n id=\"composer-audience-segment\"\n type=\"radio\"\n name=\"composer-audience\"\n checked={audienceMode === 'segment'}\n onChange={() => setAudienceMode('segment')}\n className=\"border-border focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n Segment\n </label>\n <label\n htmlFor=\"composer-audience-recipients\"\n className=\"flex items-center gap-2 text-sm text-foreground\"\n >\n <input\n id=\"composer-audience-recipients\"\n type=\"radio\"\n name=\"composer-audience\"\n checked={audienceMode === 'recipients'}\n onChange={() => setAudienceMode('recipients')}\n className=\"border-border focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n Recipients\n </label>\n </div>\n\n {audienceMode === 'segment' ? (\n <select\n id=\"composer-segment\"\n aria-label=\"Segment\"\n value={segmentId}\n aria-invalid={errors.audience ? 'true' : undefined}\n aria-describedby={errors.audience ? 'composer-audience-error' : undefined}\n onChange={(e) => setSegmentId(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <option value=\"\">Select a segment…</option>\n {segments.map((s) => (\n <option key={s.id} value={s.id}>\n {s.name}\n </option>\n ))}\n </select>\n ) : (\n <textarea\n id=\"composer-recipients\"\n aria-label=\"Recipient ids\"\n value={recipientsRaw}\n rows={4}\n placeholder=\"Recipient ids separated by commas or new lines\"\n aria-invalid={errors.audience ? 'true' : undefined}\n aria-describedby={errors.audience ? 'composer-audience-error' : undefined}\n onChange={(e) => setRecipientsRaw(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n )}\n {errors.audience && (\n <p id=\"composer-audience-error\" className=\"text-xs text-destructive\">\n {errors.audience}\n </p>\n )}\n </fieldset>\n\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"composer-type\" className=\"text-sm font-medium text-foreground\">\n Type (optional)\n </label>\n <input\n id=\"composer-type\"\n type=\"text\"\n value={type}\n onChange={(e) => setType(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n\n <div>\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {create.isPending ? 'Creating…' : 'Create broadcast'}\n </button>\n </div>\n </form>\n );\n}\n","import { cn, formatDateTime, StatusBadge, type StatusBadgeVariant } from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\n\nexport interface Segment {\n id: string;\n name: string;\n type: string;\n description: string | null;\n recipientIds: string[] | null;\n createdBy: string;\n createdAt: string;\n}\n\nexport interface SegmentListProps {\n basePath?: string;\n onSelect?: (id: string) => void;\n onCreate?: () => void;\n className?: string;\n}\n\n/** Normalize the API response, which may be a bare array or `{ items: [...] }`. */\nfunction normalize(data: Segment[] | { items?: Segment[] } | undefined): Segment[] {\n if (Array.isArray(data)) return data;\n return data?.items ?? [];\n}\n\nfunction typeVariant(type: string): StatusBadgeVariant {\n switch (type) {\n case 'dynamic':\n return 'info';\n case 'static':\n return 'neutral';\n default:\n return 'neutral';\n }\n}\n\n/**\n * Table of audience segments. Renders name, type, description, recipient count,\n * and creation time. When `onSelect` is supplied each name becomes a button.\n * When `onCreate` is supplied a \"New segment\" button is rendered in the header.\n */\nexport function SegmentList({\n basePath = '/api',\n onSelect,\n onCreate,\n className,\n}: SegmentListProps) {\n const { data, isLoading, isError, refetch } = useApiQuery<Segment[] | { items?: Segment[] }>(\n ['segments'],\n (client) => client.get(`${basePath}/v1/segments`),\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading segments\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading segments</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load segments</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const rows = normalize(data);\n\n const header = onCreate ? (\n <header className=\"flex items-center justify-end\">\n <button\n type=\"button\"\n onClick={() => onCreate()}\n className=\"rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n New segment\n </button>\n </header>\n ) : null;\n\n if (rows.length === 0) {\n return (\n <section aria-label=\"Segments\" className={cn('flex flex-col gap-3', className)}>\n {header}\n <div className=\"p-6 text-center text-sm text-muted-foreground\">No segments</div>\n </section>\n );\n }\n\n const renderNameCell = (row: Segment) =>\n onSelect ? (\n <button\n type=\"button\"\n onClick={() => onSelect(row.id)}\n className=\"rounded text-start font-medium text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n {row.name}\n </button>\n ) : (\n <span className=\"text-foreground\">{row.name}</span>\n );\n\n return (\n <section aria-label=\"Segments\" className={cn('flex flex-col gap-3', className)}>\n {header}\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Name\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Type\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Description\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Recipients\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border\">\n <td className=\"py-3 pe-4\">{renderNameCell(row)}</td>\n <td className=\"px-4 py-3\">\n <StatusBadge variant={typeVariant(row.type)} appearance=\"dot\">\n {row.type}\n </StatusBadge>\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.description ?? '—'}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.recipientIds?.length ?? '—'}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{formatDateTime(row.createdAt)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </section>\n );\n}\n","import { useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation } from '@quanticjs/react-query';\n\nexport type SegmentType = 'static' | 'dynamic';\n\nexport interface SegmentForm {\n name: string;\n type: SegmentType;\n description: string;\n recipientIds: string[];\n}\n\nexport interface SegmentSaveResult {\n id: string;\n}\n\nexport interface SegmentBuilderProps {\n basePath?: string;\n segmentId?: string;\n initial?: Partial<SegmentForm>;\n onSaved?: (id: string) => void;\n onDeleted?: () => void;\n className?: string;\n}\n\ninterface SegmentPayload {\n name: string;\n type: SegmentType;\n description: string;\n recipientIds: string[];\n}\n\ntype SegmentFieldErrors = Partial<Record<'name' | 'recipientIds', string>>;\n\n/** Split a comma/newline-separated textarea value into a trimmed, non-empty list. */\nfunction parseRecipientIds(value: string): string[] {\n return value\n .split(/[\\n,]/)\n .map((id) => id.trim())\n .filter((id) => id.length > 0);\n}\n\n/**\n * Create/edit form for audience segments. Creates via POST and (when\n * `segmentId` is set) edits via PATCH with a guarded Delete action. Validates\n * client-side and surfaces field-level errors plus ApiError-aware toasts.\n */\nexport function SegmentBuilder({\n basePath = '/api',\n segmentId,\n initial,\n onSaved,\n onDeleted,\n className,\n}: SegmentBuilderProps) {\n const toast = useToast();\n const [name, setName] = useState(initial?.name ?? '');\n const [type, setType] = useState<SegmentType>(initial?.type ?? 'static');\n const [description, setDescription] = useState(initial?.description ?? '');\n const [recipientText, setRecipientText] = useState((initial?.recipientIds ?? []).join('\\n'));\n const [errors, setErrors] = useState<SegmentFieldErrors>({});\n\n const isEdit = Boolean(segmentId);\n\n const onMutationError = (error: {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n }) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n\n const save = useApiMutation<SegmentSaveResult, SegmentPayload>(\n (client, payload) =>\n segmentId\n ? client.patch(`${basePath}/v1/segments/${segmentId}`, payload)\n : client.post(`${basePath}/v1/segments`, payload),\n {\n invalidates: [['segments']],\n onSuccess: (result) => {\n toast.success(isEdit ? 'Segment updated' : 'Segment created');\n onSaved?.(result.id);\n },\n onError: onMutationError,\n },\n );\n\n const remove = useApiMutation<void, void>(\n (client) => client.delete(`${basePath}/v1/segments/${segmentId}`),\n {\n invalidates: [['segments']],\n onSuccess: () => {\n toast.success('Segment deleted');\n onDeleted?.();\n },\n onError: onMutationError,\n },\n );\n\n const validate = (recipientIds: string[]): boolean => {\n const next: SegmentFieldErrors = {};\n if (name.trim().length === 0) {\n next.name = 'Name is required';\n }\n if (type === 'static' && recipientIds.length === 0) {\n next.recipientIds = 'A static segment needs at least one recipient id';\n }\n setErrors(next);\n return Object.keys(next).length === 0;\n };\n\n const onSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n const recipientIds = parseRecipientIds(recipientText);\n if (!validate(recipientIds)) return;\n save.mutate({ name: name.trim(), type, description: description.trim(), recipientIds });\n };\n\n const onDelete = () => {\n if (!segmentId) return;\n if (!window.confirm('Delete this segment? This cannot be undone.')) return;\n remove.mutate();\n };\n\n return (\n <form onSubmit={onSubmit} className={cn('flex flex-col gap-4', className)} noValidate>\n <header className=\"flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold text-foreground\">\n {isEdit ? `Edit segment: ${segmentId}` : 'New segment'}\n </h2>\n </header>\n\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"segment-name\" className=\"text-sm font-medium text-foreground\">\n Name\n </label>\n <input\n id=\"segment-name\"\n type=\"text\"\n value={name}\n aria-invalid={errors.name ? 'true' : undefined}\n aria-describedby={errors.name ? 'segment-name-error' : undefined}\n onChange={(e) => setName(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n {errors.name && (\n <p id=\"segment-name-error\" className=\"text-xs text-destructive\">\n {errors.name}\n </p>\n )}\n </div>\n\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"segment-type\" className=\"text-sm font-medium text-foreground\">\n Type\n </label>\n <select\n id=\"segment-type\"\n value={type}\n onChange={(e) => setType(e.target.value as SegmentType)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <option value=\"static\">static</option>\n <option value=\"dynamic\">dynamic</option>\n </select>\n </div>\n\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"segment-description\" className=\"text-sm font-medium text-foreground\">\n Description\n </label>\n <textarea\n id=\"segment-description\"\n value={description}\n rows={3}\n onChange={(e) => setDescription(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n\n {type === 'static' && (\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"segment-recipients\" className=\"text-sm font-medium text-foreground\">\n Recipient ids\n </label>\n <textarea\n id=\"segment-recipients\"\n value={recipientText}\n rows={4}\n placeholder=\"Comma or newline separated\"\n aria-invalid={errors.recipientIds ? 'true' : undefined}\n aria-describedby={errors.recipientIds ? 'segment-recipients-error' : undefined}\n onChange={(e) => setRecipientText(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n {errors.recipientIds && (\n <p id=\"segment-recipients-error\" className=\"text-xs text-destructive\">\n {errors.recipientIds}\n </p>\n )}\n </div>\n )}\n\n <div className=\"flex items-center gap-3\">\n <button\n type=\"submit\"\n disabled={save.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {save.isPending ? 'Saving…' : isEdit ? 'Save changes' : 'Create segment'}\n </button>\n {isEdit && (\n <button\n type=\"button\"\n disabled={remove.isPending}\n onClick={onDelete}\n className=\"rounded-md border border-border px-4 py-2 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {remove.isPending ? 'Deleting…' : 'Delete'}\n </button>\n )}\n </div>\n </form>\n );\n}\n","import { useState } from 'react';\nimport { cn, formatDateTime, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport type SuppressionChannel = 'inapp' | 'email' | 'push' | 'sms';\n\nexport interface Suppression {\n id: string;\n channel: string;\n address: string;\n reason: string;\n createdAt: string;\n}\n\nexport interface SuppressionPage {\n items: Suppression[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface SuppressionManagerProps {\n basePath?: string;\n className?: string;\n}\n\ninterface SuppressionPayload {\n channel: SuppressionChannel;\n address: string;\n reason: string;\n}\n\nconst LIMIT = 20;\nconst CHANNELS: SuppressionChannel[] = ['inapp', 'email', 'push', 'sms'];\n\n/**\n * Manage the delivery suppression list. Lists suppressed addresses (paginated)\n * with per-row removal, and an inline add form. All mutations refetch the list\n * and surface ApiError-aware toasts.\n */\nexport function SuppressionManager({ basePath = '/api', className }: SuppressionManagerProps) {\n const toast = useToast();\n const [page, setPage] = useState(1);\n const [channel, setChannel] = useState<SuppressionChannel>('email');\n const [address, setAddress] = useState('');\n const [reason, setReason] = useState('');\n\n const { data, isLoading, isError, refetch } = useApiQuery<SuppressionPage>(\n ['suppression', page],\n (client) => client.get(`${basePath}/v1/admin/suppression?page=${page}&limit=${LIMIT}`),\n );\n\n const onMutationError = (error: {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n }) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n\n const add = useApiMutation<void, SuppressionPayload>(\n (client, payload) => client.post(`${basePath}/v1/admin/suppression`, payload),\n {\n invalidates: [['suppression']],\n onSuccess: () => {\n toast.success('Suppression added');\n setAddress('');\n setReason('');\n void refetch();\n },\n onError: onMutationError,\n },\n );\n\n const remove = useApiMutation<void, string>(\n (client, id) => client.delete(`${basePath}/v1/admin/suppression/${id}`),\n {\n invalidates: [['suppression']],\n onSuccess: () => {\n toast.success('Suppression removed');\n void refetch();\n },\n onError: onMutationError,\n },\n );\n\n const onAdd = (event: React.FormEvent) => {\n event.preventDefault();\n add.mutate({ channel, address: address.trim(), reason: reason.trim() });\n };\n\n const addForm = (\n <form onSubmit={onAdd} className=\"flex flex-wrap items-end gap-3\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"suppression-channel\" className=\"text-sm font-medium text-foreground\">\n Channel\n </label>\n <select\n id=\"suppression-channel\"\n value={channel}\n onChange={(e) => setChannel(e.target.value as SuppressionChannel)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n {CHANNELS.map((c) => (\n <option key={c} value={c}>\n {c}\n </option>\n ))}\n </select>\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"suppression-address\" className=\"text-sm font-medium text-foreground\">\n Address\n </label>\n <input\n id=\"suppression-address\"\n type=\"text\"\n value={address}\n onChange={(e) => setAddress(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"suppression-reason\" className=\"text-sm font-medium text-foreground\">\n Reason\n </label>\n <input\n id=\"suppression-reason\"\n type=\"text\"\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <button\n type=\"submit\"\n disabled={add.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {add.isPending ? 'Adding…' : 'Add suppression'}\n </button>\n </form>\n );\n\n let body: React.ReactNode;\n\n if (isLoading) {\n body = (\n <div role=\"status\" aria-label=\"Loading suppressions\" className=\"flex flex-col gap-2 p-4\">\n <span className=\"sr-only\">Loading suppressions</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n } else if (isError) {\n body = (\n <div className=\"flex flex-col items-start gap-3 p-4\">\n <p className=\"text-sm text-foreground\">Failed to load suppressions</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n } else {\n const rows = data?.items ?? [];\n const totalPages = data?.totalPages ?? 1;\n\n if (rows.length === 0) {\n body = <div className=\"p-6 text-center text-sm text-muted-foreground\">No suppressions</div>;\n } else {\n body = (\n <>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Channel\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Address\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Reason\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n <span className=\"sr-only\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 text-foreground\">{row.channel}</td>\n <td className=\"px-4 py-3 text-foreground\">{row.address}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.reason}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {formatDateTime(row.createdAt)}\n </td>\n <td className=\"px-4 py-3\">\n <button\n type=\"button\"\n disabled={remove.isPending}\n onClick={() => remove.mutate(row.id)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Remove\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n <nav aria-label=\"Suppression pagination\" className=\"flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n disabled={page <= 1}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Previous\n </button>\n <span className=\"text-xs text-muted-foreground\">\n Page {page} of {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.min(totalPages, p + 1))}\n disabled={page >= totalPages}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Next\n </button>\n </nav>\n </>\n );\n }\n }\n\n return (\n <section aria-label=\"Suppression list\" className={cn('flex flex-col gap-4', className)}>\n {addForm}\n {body}\n </section>\n );\n}\n","import { Fragment, useState } from 'react';\nimport {\n cn,\n formatDateTime,\n StatusBadge,\n type StatusBadgeVariant,\n useToast,\n} from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport type DlqStatusFilter = 'queued' | 'replayed' | 'discarded';\n\nexport interface DlqMessage {\n id: string;\n requestId: string | null;\n failureReason: string;\n status: string;\n attemptCount: number;\n firstSeenAt: string;\n}\n\nexport interface DlqPage {\n items: DlqMessage[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface DlqMessageDetail {\n id: string;\n requestId: string | null;\n failureReason: string;\n errorMessage: string | null;\n status: string;\n attemptCount: number;\n firstSeenAt: string;\n replayedAt: string | null;\n payload?: unknown;\n}\n\nexport interface DlqConsoleProps {\n basePath?: string;\n className?: string;\n}\n\nconst LIMIT = 20;\nconst STATUS_FILTERS: DlqStatusFilter[] = ['queued', 'replayed', 'discarded'];\n\ninterface MutationErrorShape {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n}\n\nfunction buildErrorDescription(error: MutationErrorShape): string {\n return error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`;\n}\n\nfunction statusVariant(status: string): StatusBadgeVariant {\n switch (status) {\n case 'replayed':\n return 'success';\n case 'discarded':\n return 'neutral';\n case 'queued':\n return 'warning';\n default:\n return 'neutral';\n }\n}\n\n/** Lazily fetches and renders the detail/payload for a single expanded row. */\nfunction DlqMessageDetailRow({ id, basePath }: { id: string; basePath: string }) {\n const { data, isLoading, isError, refetch } = useApiQuery<DlqMessageDetail>(\n ['dlq', 'detail', id],\n (client) => client.get(`${basePath}/admin/dlq/${id}`),\n );\n\n if (isLoading) {\n return (\n <div role=\"status\" aria-label=\"Loading message detail\" className=\"flex flex-col gap-2 p-3\">\n <span className=\"sr-only\">Loading message detail</span>\n <div aria-hidden=\"true\" className=\"h-16 animate-pulse rounded bg-muted\" />\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className=\"flex flex-col items-start gap-3 p-3\">\n <p className=\"text-sm text-foreground\">Failed to load message detail</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col gap-2 p-3 text-sm\">\n <p className=\"text-muted-foreground\">\n Error: <span className=\"text-foreground\">{data?.errorMessage ?? '—'}</span>\n </p>\n <pre className=\"max-h-64 overflow-auto rounded bg-muted p-3 text-xs text-foreground\">\n {JSON.stringify(data?.payload ?? {}, null, 2)}\n </pre>\n </div>\n );\n}\n\n/**\n * Dead-letter queue console. Lists failed messages (paginated, status-filtered)\n * with per-row expand to view payload/detail, plus Replay and Discard actions.\n * All mutations refetch the list and surface ApiError-aware toasts.\n */\nexport function DlqConsole({ basePath = '/api', className }: DlqConsoleProps) {\n const toast = useToast();\n const [page, setPage] = useState(1);\n const [statusFilter, setStatusFilter] = useState<DlqStatusFilter | ''>('');\n const [expandedId, setExpandedId] = useState<string | null>(null);\n\n const statusQuery = statusFilter ? `&status=${statusFilter}` : '';\n const { data, isLoading, isError, refetch } = useApiQuery<DlqPage>(\n ['dlq', page, statusFilter],\n (client) => client.get(`${basePath}/admin/dlq?page=${page}&limit=${LIMIT}${statusQuery}`),\n );\n\n const replay = useApiMutation<void, string>(\n (client, id) => client.post(`${basePath}/admin/dlq/${id}/replay`, {}),\n {\n invalidates: [['dlq']],\n onSuccess: () => {\n toast.success('Message queued for replay');\n void refetch();\n },\n onError: (error) => {\n if (error.isConflict) {\n toast.error('Message already replayed', {\n description: `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n void refetch();\n return;\n }\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: buildErrorDescription(error),\n });\n },\n },\n );\n\n const discard = useApiMutation<void, string>(\n (client, id) => client.delete(`${basePath}/admin/dlq/${id}`),\n {\n invalidates: [['dlq']],\n onSuccess: () => {\n toast.success('Message discarded');\n void refetch();\n },\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: buildErrorDescription(error),\n }),\n },\n );\n\n const filterControl = (\n <div className=\"flex items-center gap-2\">\n <label htmlFor=\"dlq-status\" className=\"text-sm font-medium text-foreground\">\n Status\n </label>\n <select\n id=\"dlq-status\"\n value={statusFilter}\n onChange={(e) => {\n setStatusFilter(e.target.value as DlqStatusFilter | '');\n setPage(1);\n }}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <option value=\"\">All</option>\n {STATUS_FILTERS.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n </div>\n );\n\n let body: React.ReactNode;\n\n if (isLoading) {\n body = (\n <div\n role=\"status\"\n aria-label=\"Loading dead-letter messages\"\n className=\"flex flex-col gap-2 p-4\"\n >\n <span className=\"sr-only\">Loading dead-letter messages</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n } else if (isError) {\n body = (\n <div className=\"flex flex-col items-start gap-3 p-4\">\n <p className=\"text-sm text-foreground\">Failed to load dead-letter messages</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n } else {\n const rows = data?.items ?? [];\n const totalPages = data?.totalPages ?? 1;\n\n if (rows.length === 0) {\n body = (\n <div className=\"p-6 text-center text-sm text-muted-foreground\">No dead-letter messages</div>\n );\n } else {\n body = (\n <>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Request\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Failure reason\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Attempts\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n First seen\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n <span className=\"sr-only\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => {\n const isExpanded = expandedId === row.id;\n return (\n <Fragment key={row.id}>\n <tr className=\"border-b border-border\">\n <td className=\"py-3 pe-4\">\n <button\n type=\"button\"\n aria-expanded={isExpanded}\n onClick={() => setExpandedId(isExpanded ? null : row.id)}\n className=\"rounded text-start font-medium text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n {row.requestId ?? row.id}\n </button>\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.failureReason}</td>\n <td className=\"px-4 py-3\">\n <StatusBadge variant={statusVariant(row.status)} appearance=\"dot\">\n {row.status}\n </StatusBadge>\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.attemptCount}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {formatDateTime(row.firstSeenAt)}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n disabled={replay.isPending}\n onClick={() => replay.mutate(row.id)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Replay\n </button>\n <button\n type=\"button\"\n disabled={discard.isPending}\n onClick={() => discard.mutate(row.id)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Discard\n </button>\n </div>\n </td>\n </tr>\n {isExpanded && (\n <tr className=\"border-b border-border\">\n <td colSpan={6} className=\"bg-muted/40\">\n <DlqMessageDetailRow id={row.id} basePath={basePath} />\n </td>\n </tr>\n )}\n </Fragment>\n );\n })}\n </tbody>\n </table>\n <nav aria-label=\"Dead-letter pagination\" className=\"flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n disabled={page <= 1}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Previous\n </button>\n <span className=\"text-xs text-muted-foreground\">\n Page {page} of {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.min(totalPages, p + 1))}\n disabled={page >= totalPages}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Next\n </button>\n </nav>\n </>\n );\n }\n }\n\n return (\n <section aria-label=\"Dead-letter queue\" className={cn('flex flex-col gap-4', className)}>\n <header className=\"flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold text-foreground\">Dead-letter queue</h2>\n {filterControl}\n </header>\n {body}\n </section>\n );\n}\n","import { useMemo, useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface CatalogEntry {\n key: string;\n locale: string;\n value: string;\n}\n\ninterface CatalogResponse {\n entries?: CatalogEntry[];\n}\n\nexport interface CatalogEditorProps {\n basePath?: string;\n className?: string;\n}\n\ninterface UpsertPayload {\n key: string;\n locale: string;\n value: string;\n}\n\ninterface DeletePayload {\n key: string;\n locale: string;\n}\n\nfunction normalize(\n data: CatalogResponse | CatalogEntry[] | Record<string, CatalogEntry> | undefined,\n): CatalogEntry[] {\n if (!data) return [];\n if (Array.isArray(data)) return data;\n if ('entries' in data && Array.isArray((data as CatalogResponse).entries)) {\n return (data as CatalogResponse).entries ?? [];\n }\n return Object.values(data as Record<string, CatalogEntry>).filter(\n (entry): entry is CatalogEntry =>\n typeof entry === 'object' &&\n entry !== null &&\n 'key' in entry &&\n 'locale' in entry &&\n 'value' in entry,\n );\n}\n\n/**\n * i18n catalog editor. Lists catalog entries with a key filter, supports inline\n * value editing, per-entry delete, and an add form. All mutations refetch and\n * surface ApiError-aware toasts.\n */\nexport function CatalogEditor({ basePath = '/api', className }: CatalogEditorProps) {\n const toast = useToast();\n const [filter, setFilter] = useState('');\n const [editingId, setEditingId] = useState<string | null>(null);\n const [editValue, setEditValue] = useState('');\n const [newKey, setNewKey] = useState('');\n const [newLocale, setNewLocale] = useState('');\n const [newValue, setNewValue] = useState('');\n\n const { data, isLoading, isError, refetch } = useApiQuery<\n CatalogResponse | CatalogEntry[] | Record<string, CatalogEntry>\n >(['i18n-catalog'], (client) => client.get(`${basePath}/i18n/catalog/export`));\n\n const onMutationError = (error: {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n }) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n\n const upsert = useApiMutation<void, UpsertPayload>(\n (client, payload) =>\n client.put(`${basePath}/i18n/catalog/entries/${encodeURIComponent(payload.key)}`, {\n locale: payload.locale,\n value: payload.value,\n }),\n {\n invalidates: [['i18n-catalog']],\n onSuccess: () => {\n toast.success('Entry saved');\n setEditingId(null);\n void refetch();\n },\n onError: onMutationError,\n },\n );\n\n const add = useApiMutation<void, UpsertPayload>(\n (client, payload) =>\n client.put(`${basePath}/i18n/catalog/entries/${encodeURIComponent(payload.key)}`, {\n locale: payload.locale,\n value: payload.value,\n }),\n {\n invalidates: [['i18n-catalog']],\n onSuccess: () => {\n toast.success('Entry added');\n setNewKey('');\n setNewLocale('');\n setNewValue('');\n void refetch();\n },\n onError: onMutationError,\n },\n );\n\n const remove = useApiMutation<void, DeletePayload>(\n (client, payload) =>\n client.delete(\n `${basePath}/i18n/catalog/entries/${encodeURIComponent(payload.key)}?locale=${encodeURIComponent(payload.locale)}`,\n ),\n {\n invalidates: [['i18n-catalog']],\n onSuccess: () => {\n toast.success('Entry removed');\n void refetch();\n },\n onError: onMutationError,\n },\n );\n\n const entries = useMemo(() => normalize(data), [data]);\n const filtered = useMemo(() => {\n const q = filter.trim().toLowerCase();\n if (!q) return entries;\n return entries.filter((e) => e.key.toLowerCase().includes(q));\n }, [entries, filter]);\n\n const onAdd = (event: React.FormEvent) => {\n event.preventDefault();\n add.mutate({ key: newKey.trim(), locale: newLocale.trim(), value: newValue });\n };\n\n const startEdit = (entry: CatalogEntry) => {\n setEditingId(`${entry.key}:${entry.locale}`);\n setEditValue(entry.value);\n };\n\n const addForm = (\n <form onSubmit={onAdd} className=\"flex flex-wrap items-end gap-3\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"catalog-new-key\" className=\"text-sm font-medium text-foreground\">\n Key\n </label>\n <input\n id=\"catalog-new-key\"\n type=\"text\"\n value={newKey}\n onChange={(e) => setNewKey(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"catalog-new-locale\" className=\"text-sm font-medium text-foreground\">\n Locale\n </label>\n <input\n id=\"catalog-new-locale\"\n type=\"text\"\n value={newLocale}\n onChange={(e) => setNewLocale(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"catalog-new-value\" className=\"text-sm font-medium text-foreground\">\n Value\n </label>\n <input\n id=\"catalog-new-value\"\n type=\"text\"\n value={newValue}\n onChange={(e) => setNewValue(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <button\n type=\"submit\"\n disabled={add.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {add.isPending ? 'Adding…' : 'Add entry'}\n </button>\n </form>\n );\n\n const filterInput = (\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"catalog-filter\" className=\"text-sm font-medium text-foreground\">\n Filter by key\n </label>\n <input\n id=\"catalog-filter\"\n type=\"text\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n );\n\n let body: React.ReactNode;\n\n if (isLoading) {\n body = (\n <div role=\"status\" aria-label=\"Loading catalog\" className=\"flex flex-col gap-2 p-4\">\n <span className=\"sr-only\">Loading catalog</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n } else if (isError) {\n body = (\n <div className=\"flex flex-col items-start gap-3 p-4\">\n <p className=\"text-sm text-foreground\">Failed to load catalog</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n } else if (filtered.length === 0) {\n body = (\n <div className=\"p-6 text-center text-sm text-muted-foreground\">\n {entries.length === 0 ? 'No catalog entries' : 'No entries match your filter'}\n </div>\n );\n } else {\n body = (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Key\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Locale\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Value\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n <span className=\"sr-only\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {filtered.map((entry) => {\n const rowId = `${entry.key}:${entry.locale}`;\n const isEditing = editingId === rowId;\n return (\n <tr key={rowId} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 font-mono text-foreground\">{entry.key}</td>\n <td className=\"px-4 py-3 text-foreground\">{entry.locale}</td>\n <td className=\"px-4 py-3 text-foreground\">\n {isEditing ? (\n <input\n type=\"text\"\n aria-label={`Value for ${entry.key} (${entry.locale})`}\n value={editValue}\n onChange={(e) => setEditValue(e.target.value)}\n className=\"w-full rounded-md border border-border bg-background px-3 py-1.5 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n ) : (\n entry.value\n )}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n {isEditing ? (\n <>\n <button\n type=\"button\"\n disabled={upsert.isPending}\n onClick={() =>\n upsert.mutate({\n key: entry.key,\n locale: entry.locale,\n value: editValue,\n })\n }\n className=\"rounded-md bg-primary px-3 py-1 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Save\n </button>\n <button\n type=\"button\"\n onClick={() => setEditingId(null)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Cancel\n </button>\n </>\n ) : (\n <>\n <button\n type=\"button\"\n onClick={() => startEdit(entry)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Edit\n </button>\n <button\n type=\"button\"\n disabled={remove.isPending}\n onClick={() => remove.mutate({ key: entry.key, locale: entry.locale })}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Delete\n </button>\n </>\n )}\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n );\n }\n\n return (\n <section aria-label=\"Catalog editor\" className={cn('flex flex-col gap-4', className)}>\n {addForm}\n {filterInput}\n {body}\n </section>\n );\n}\n","import { cn } from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\n\nexport interface MissingEntry {\n key: string;\n locale: string;\n type?: string;\n}\n\ninterface MissingResponse {\n missing?: MissingEntry[];\n}\n\nexport interface MissingTranslationsPanelProps {\n basePath?: string;\n className?: string;\n}\n\nfunction normalize(data: MissingResponse | MissingEntry[] | undefined): MissingEntry[] {\n if (Array.isArray(data)) return data;\n return data?.missing ?? [];\n}\n\n/**\n * Reports translation keys that have no value for one or more locales. An empty\n * result is the healthy state (\"No missing translations\").\n */\nexport function MissingTranslationsPanel({\n basePath = '/api',\n className,\n}: MissingTranslationsPanelProps) {\n const { data, isLoading, isError, refetch } = useApiQuery<MissingResponse | MissingEntry[]>(\n ['i18n-missing'],\n (client) => client.get(`${basePath}/i18n/catalog/missing`),\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading missing translations\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading missing translations</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load missing translations</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const rows = normalize(data);\n\n if (rows.length === 0) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No missing translations\n </div>\n );\n }\n\n return (\n <section aria-label=\"Missing translations\" className={cn('flex flex-col gap-3', className)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Key\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Locale\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Type\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row, i) => (\n <tr key={`${row.key}:${row.locale}:${i}`} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 font-mono text-foreground\">{row.key}</td>\n <td className=\"px-4 py-3 text-foreground\">{row.locale}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.type ?? '—'}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </section>\n );\n}\n","import { cn } from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\n\nexport interface FallbackEntry {\n key: string;\n requestedLocale: string;\n resolvedLocale: string;\n steps?: string[];\n}\n\ninterface FallbackResponse {\n entries?: FallbackEntry[];\n}\n\nexport interface FallbackReportPanelProps {\n basePath?: string;\n className?: string;\n}\n\nfunction normalize(data: FallbackResponse | FallbackEntry[] | undefined): FallbackEntry[] {\n if (Array.isArray(data)) return data;\n return data?.entries ?? [];\n}\n\n/**\n * Shows translation keys that resolved through locale fallback, including the\n * requested vs. resolved locale and the resolution chain when available.\n */\nexport function FallbackReportPanel({ basePath = '/api', className }: FallbackReportPanelProps) {\n const { data, isLoading, isError, refetch } = useApiQuery<FallbackResponse | FallbackEntry[]>(\n ['i18n-fallback-report'],\n (client) => client.get(`${basePath}/i18n/catalog/fallback-report`),\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading fallback report\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading fallback report</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load fallback report</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const rows = normalize(data);\n\n if (rows.length === 0) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No fallbacks reported\n </div>\n );\n }\n\n return (\n <section aria-label=\"Fallback report\" className={cn('flex flex-col gap-3', className)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Key\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Requested\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Resolved\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Chain\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row, i) => (\n <tr key={`${row.key}:${row.requestedLocale}:${i}`} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 font-mono text-foreground\">{row.key}</td>\n <td className=\"px-4 py-3 text-foreground\">{row.requestedLocale}</td>\n <td className=\"px-4 py-3 text-foreground\">{row.resolvedLocale}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {row.steps && row.steps.length > 0 ? (\n <ol className=\"flex flex-wrap items-center gap-1\">\n {row.steps.map((step, si) => (\n <li key={`${step}:${si}`} className=\"flex items-center gap-1\">\n <span className=\"rounded bg-muted px-1.5 py-0.5 text-xs text-foreground\">\n {step}\n </span>\n {si < (row.steps?.length ?? 0) - 1 && (\n <span aria-hidden=\"true\" className=\"text-muted-foreground\">\n →\n </span>\n )}\n </li>\n ))}\n </ol>\n ) : (\n '—'\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </section>\n );\n}\n","import { useState } from 'react';\nimport { cn, formatDateTime, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface RecipientSummary {\n userId: string;\n email: string | null;\n emailVerified: boolean;\n phone: string | null;\n phoneVerified: boolean;\n locale: string | null;\n timezone: string | null;\n consentEmail: boolean;\n consentPush: boolean;\n consentSms: boolean;\n createdAt: string;\n}\n\nexport interface RecipientPage {\n items: RecipientSummary[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface RecipientAdminPanelProps {\n basePath?: string;\n className?: string;\n}\n\nconst LIMIT = 20;\n\n/**\n * Recipient search with GDPR actions. Paginated, searchable recipient table\n * with per-row data export and erase (confirmed). All mutations surface\n * ApiError-aware toasts; erase refetches the list.\n */\nexport function RecipientAdminPanel({ basePath = '/api', className }: RecipientAdminPanelProps) {\n const toast = useToast();\n const [page, setPage] = useState(1);\n const [search, setSearch] = useState('');\n const [query, setQuery] = useState('');\n\n const { data, isLoading, isError, refetch } = useApiQuery<RecipientPage>(\n ['recipients', page, query],\n (client) =>\n client.get(\n `${basePath}/v1/admin/recipients?page=${page}&limit=${LIMIT}&search=${encodeURIComponent(query)}`,\n ),\n );\n\n const onMutationError = (error: {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n }) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n\n const exportData = useApiMutation<void, string>(\n (client, userId) => client.post(`${basePath}/v1/admin/recipients/${userId}/export`, {}),\n {\n onSuccess: () => toast.success('Export ready'),\n onError: onMutationError,\n },\n );\n\n const erase = useApiMutation<void, string>(\n (client, userId) => client.delete(`${basePath}/v1/admin/recipients/${userId}/erase`),\n {\n invalidates: [['recipients']],\n onSuccess: () => {\n toast.success('Recipient erased');\n void refetch();\n },\n onError: onMutationError,\n },\n );\n\n const onSearch = (event: React.FormEvent) => {\n event.preventDefault();\n setPage(1);\n setQuery(search.trim());\n };\n\n const onErase = (userId: string) => {\n if (window.confirm('Erase all data for this recipient? This cannot be undone.')) {\n erase.mutate(userId);\n }\n };\n\n const consents = (row: RecipientSummary): string => {\n const active: string[] = [];\n if (row.consentEmail) active.push('email');\n if (row.consentPush) active.push('push');\n if (row.consentSms) active.push('sms');\n return active.length > 0 ? active.join(', ') : 'none';\n };\n\n const searchForm = (\n <form onSubmit={onSearch} className=\"flex flex-wrap items-end gap-3\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"recipient-search\" className=\"text-sm font-medium text-foreground\">\n Search recipients\n </label>\n <input\n id=\"recipient-search\"\n type=\"text\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <button\n type=\"submit\"\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Search\n </button>\n </form>\n );\n\n let body: React.ReactNode;\n\n if (isLoading) {\n body = (\n <div role=\"status\" aria-label=\"Loading recipients\" className=\"flex flex-col gap-2 p-4\">\n <span className=\"sr-only\">Loading recipients</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n } else if (isError) {\n body = (\n <div className=\"flex flex-col items-start gap-3 p-4\">\n <p className=\"text-sm text-foreground\">Failed to load recipients</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n } else {\n const rows = data?.items ?? [];\n const totalPages = data?.totalPages ?? 1;\n\n if (rows.length === 0) {\n body = <div className=\"p-6 text-center text-sm text-muted-foreground\">No recipients</div>;\n } else {\n body = (\n <>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n User\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Email\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Phone\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Consents\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n <span className=\"sr-only\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.userId} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 font-mono text-foreground\">{row.userId}</td>\n <td className=\"px-4 py-3 text-foreground\">{row.email ?? '—'}</td>\n <td className=\"px-4 py-3 text-foreground\">{row.phone ?? '—'}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{consents(row)}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {formatDateTime(row.createdAt)}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n disabled={exportData.isPending}\n onClick={() => exportData.mutate(row.userId)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Export\n </button>\n <button\n type=\"button\"\n disabled={erase.isPending}\n onClick={() => onErase(row.userId)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Erase\n </button>\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n <nav aria-label=\"Recipient pagination\" className=\"flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n disabled={page <= 1}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Previous\n </button>\n <span className=\"text-xs text-muted-foreground\">\n Page {page} of {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.min(totalPages, p + 1))}\n disabled={page >= totalPages}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Next\n </button>\n </nav>\n </>\n );\n }\n }\n\n return (\n <section aria-label=\"Recipient administration\" className={cn('flex flex-col gap-4', className)}>\n {searchForm}\n {body}\n </section>\n );\n}\n","import { Fragment, useState } from 'react';\nimport { cn, formatDateTime, useToast, StatusBadge } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface WebhookEndpoint {\n id: string;\n url: string;\n events: string[];\n active: boolean;\n createdAt: string;\n}\n\ninterface WebhookListResponse {\n items?: WebhookEndpoint[];\n}\n\nexport interface WebhookDelivery {\n id: string;\n status: string;\n createdAt: string;\n}\n\ninterface WebhookDeliveryResponse {\n items?: WebhookDelivery[];\n}\n\nexport interface WebhookEndpointManagerProps {\n basePath?: string;\n className?: string;\n}\n\ninterface CreatePayload {\n url: string;\n events: string[];\n active: boolean;\n}\n\ninterface TogglePayload {\n id: string;\n active: boolean;\n}\n\nconst EVENT_TYPES = [\n 'notification.sent',\n 'notification.delivered',\n 'notification.failed',\n 'notification.bounced',\n] as const;\n\nfunction normalizeEndpoints(\n data: WebhookListResponse | WebhookEndpoint[] | undefined,\n): WebhookEndpoint[] {\n if (Array.isArray(data)) return data;\n return data?.items ?? [];\n}\n\nfunction normalizeDeliveries(\n data: WebhookDeliveryResponse | WebhookDelivery[] | undefined,\n): WebhookDelivery[] {\n if (Array.isArray(data)) return data;\n return data?.items ?? [];\n}\n\ntype ToastError = {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n};\n\nfunction toastError(toast: ReturnType<typeof useToast>, error: ToastError) {\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n}\n\n/** Lazily fetches and renders recent delivery attempts for a single endpoint. */\nfunction WebhookDeliveries({ endpointId, basePath }: { endpointId: string; basePath: string }) {\n const { data, isLoading, isError, refetch } = useApiQuery<\n WebhookDeliveryResponse | WebhookDelivery[]\n >(['webhook-deliveries', endpointId], (client) =>\n client.get(`${basePath}/webhook-endpoints/${endpointId}/deliveries`),\n );\n\n if (isLoading) {\n return (\n <div role=\"status\" aria-label=\"Loading deliveries\" className=\"flex flex-col gap-2 p-3\">\n <span className=\"sr-only\">Loading deliveries</span>\n {[0, 1].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-8 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className=\"flex flex-col items-start gap-2 p-3\">\n <p className=\"text-sm text-foreground\">Failed to load deliveries</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const rows = normalizeDeliveries(data);\n\n if (rows.length === 0) {\n return <div className=\"p-3 text-center text-sm text-muted-foreground\">No deliveries</div>;\n }\n\n return (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Delivery\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border\">\n <td className=\"py-2 pe-4 font-mono text-foreground\">{row.id}</td>\n <td className=\"px-4 py-2 text-muted-foreground\">{row.status}</td>\n <td className=\"px-4 py-2 text-muted-foreground\">{formatDateTime(row.createdAt)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n\n/**\n * Manage webhook endpoints. Lists endpoints with create form, per-row active\n * toggle, delete (confirmed), and a lazy deliveries expander. All mutations\n * refetch and surface ApiError-aware toasts.\n */\nexport function WebhookEndpointManager({\n basePath = '/api',\n className,\n}: WebhookEndpointManagerProps) {\n const toast = useToast();\n const [url, setUrl] = useState('');\n const [events, setEvents] = useState<string[]>([]);\n const [active, setActive] = useState(true);\n const [urlError, setUrlError] = useState<string | undefined>();\n const [expandedId, setExpandedId] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useApiQuery<\n WebhookListResponse | WebhookEndpoint[]\n >(['webhook-endpoints'], (client) => client.get(`${basePath}/webhook-endpoints`));\n\n const create = useApiMutation<void, CreatePayload>(\n (client, payload) => client.post(`${basePath}/webhook-endpoints`, payload),\n {\n invalidates: [['webhook-endpoints']],\n onSuccess: () => {\n toast.success('Endpoint created');\n setUrl('');\n setEvents([]);\n setActive(true);\n void refetch();\n },\n onError: (error) => toastError(toast, error),\n },\n );\n\n const toggle = useApiMutation<void, TogglePayload>(\n (client, payload) =>\n client.patch(`${basePath}/webhook-endpoints/${payload.id}`, { active: payload.active }),\n {\n invalidates: [['webhook-endpoints']],\n onSuccess: () => {\n toast.success('Endpoint updated');\n void refetch();\n },\n onError: (error) => toastError(toast, error),\n },\n );\n\n const remove = useApiMutation<void, string>(\n (client, id) => client.delete(`${basePath}/webhook-endpoints/${id}`),\n {\n invalidates: [['webhook-endpoints']],\n onSuccess: () => {\n toast.success('Endpoint deleted');\n void refetch();\n },\n onError: (error) => toastError(toast, error),\n },\n );\n\n const toggleEvent = (event: string) => {\n setEvents((prev) =>\n prev.includes(event) ? prev.filter((e) => e !== event) : [...prev, event],\n );\n };\n\n const onCreate = (event: React.FormEvent) => {\n event.preventDefault();\n const trimmed = url.trim();\n if (!trimmed) {\n setUrlError('URL is required');\n return;\n }\n if (!trimmed.startsWith('http')) {\n setUrlError('URL must start with http');\n return;\n }\n setUrlError(undefined);\n create.mutate({ url: trimmed, events, active });\n };\n\n const onDelete = (id: string) => {\n if (window.confirm('Delete this webhook endpoint?')) {\n remove.mutate(id);\n }\n };\n\n const createForm = (\n <form onSubmit={onCreate} className=\"flex flex-col gap-3\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"webhook-url\" className=\"text-sm font-medium text-foreground\">\n Endpoint URL\n </label>\n <input\n id=\"webhook-url\"\n type=\"text\"\n value={url}\n aria-invalid={urlError ? 'true' : undefined}\n aria-describedby={urlError ? 'webhook-url-error' : undefined}\n onChange={(e) => setUrl(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n {urlError && (\n <p id=\"webhook-url-error\" className=\"text-xs text-destructive\">\n {urlError}\n </p>\n )}\n </div>\n <fieldset className=\"flex flex-col gap-2\">\n <legend className=\"text-sm font-medium text-foreground\">Events</legend>\n <div className=\"flex flex-wrap gap-3\">\n {EVENT_TYPES.map((evt) => {\n const id = `webhook-event-${evt}`;\n return (\n <label\n key={evt}\n htmlFor={id}\n className=\"flex items-center gap-2 text-sm text-foreground\"\n >\n <input\n id={id}\n type=\"checkbox\"\n checked={events.includes(evt)}\n onChange={() => toggleEvent(evt)}\n className=\"focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n {evt}\n </label>\n );\n })}\n </div>\n </fieldset>\n <label htmlFor=\"webhook-active\" className=\"flex items-center gap-2 text-sm text-foreground\">\n <input\n id=\"webhook-active\"\n type=\"checkbox\"\n checked={active}\n onChange={(e) => setActive(e.target.checked)}\n className=\"focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n Active\n </label>\n <div>\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {create.isPending ? 'Creating…' : 'Create endpoint'}\n </button>\n </div>\n </form>\n );\n\n let body: React.ReactNode;\n\n if (isLoading) {\n body = (\n <div role=\"status\" aria-label=\"Loading webhook endpoints\" className=\"flex flex-col gap-2 p-4\">\n <span className=\"sr-only\">Loading webhook endpoints</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n } else if (isError) {\n body = (\n <div className=\"flex flex-col items-start gap-3 p-4\">\n <p className=\"text-sm text-foreground\">Failed to load webhook endpoints</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n } else {\n const rows = normalizeEndpoints(data);\n\n if (rows.length === 0) {\n body = (\n <div className=\"p-6 text-center text-sm text-muted-foreground\">No webhook endpoints</div>\n );\n } else {\n body = (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n URL\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Events\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Active\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n <span className=\"sr-only\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => {\n const isExpanded = expandedId === row.id;\n return (\n <Fragment key={row.id}>\n <tr className=\"border-b border-border\">\n <td className=\"py-3 pe-4 font-mono text-foreground\">{row.url}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {row.events.length > 0 ? row.events.join(', ') : '—'}\n </td>\n <td className=\"px-4 py-3\">\n <StatusBadge variant={row.active ? 'success' : 'neutral'} appearance=\"dot\">\n {row.active ? 'active' : 'inactive'}\n </StatusBadge>\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {formatDateTime(row.createdAt)}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n disabled={toggle.isPending}\n onClick={() => toggle.mutate({ id: row.id, active: !row.active })}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {row.active ? 'Disable' : 'Enable'}\n </button>\n <button\n type=\"button\"\n onClick={() => setExpandedId(isExpanded ? null : row.id)}\n aria-expanded={isExpanded}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Deliveries\n </button>\n <button\n type=\"button\"\n disabled={remove.isPending}\n onClick={() => onDelete(row.id)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Delete\n </button>\n </div>\n </td>\n </tr>\n {isExpanded && (\n <tr className=\"border-b border-border\">\n <td colSpan={5} className=\"bg-muted px-4 py-3\">\n <WebhookDeliveries endpointId={row.id} basePath={basePath} />\n </td>\n </tr>\n )}\n </Fragment>\n );\n })}\n </tbody>\n </table>\n );\n }\n }\n\n return (\n <section aria-label=\"Webhook endpoints\" className={cn('flex flex-col gap-4', className)}>\n {createForm}\n {body}\n </section>\n );\n}\n","import { cn, formatDateTime, StatusBadge } from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\n\nexport interface OperationsChannelStat {\n channel: string;\n sends: number;\n delivered: number;\n failed: number;\n}\n\nexport interface OperationsOverviewResponse {\n windowHours: number;\n channels: OperationsChannelStat[];\n totalSends: number;\n totalDelivered: number;\n totalFailed: number;\n dlqPending: number;\n broadcastsInFlight: number;\n queueHealthy: boolean;\n generatedAt: string;\n}\n\nexport interface OperationsOverviewProps {\n basePath?: string;\n className?: string;\n}\n\n/**\n * Operations overview dashboard. Renders summary stat cards (sends / delivered\n * / failed over the reporting window), a per-channel breakdown table, and\n * health indicators (DLQ pending, broadcasts in flight, queue health).\n */\nexport function OperationsOverview({ basePath = '/api', className }: OperationsOverviewProps) {\n const { data, isLoading, isError, refetch } = useApiQuery<OperationsOverviewResponse>(\n ['operations-overview'],\n (client) => client.get(`${basePath}/v1/admin/overview`),\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading operations overview\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading operations overview</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-20 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load operations overview</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n if (!data) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No overview data\n </div>\n );\n }\n\n const windowHours = data.windowHours;\n const channels = data.channels ?? [];\n const dlqPending = data.dlqPending;\n\n const cards: Array<{ label: string; value: number }> = [\n { label: `Sends (${windowHours}h)`, value: data.totalSends },\n { label: `Delivered (${windowHours}h)`, value: data.totalDelivered },\n { label: `Failed (${windowHours}h)`, value: data.totalFailed },\n ];\n\n return (\n <section aria-label=\"Operations overview\" className={cn('flex flex-col gap-4', className)}>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-3\">\n {cards.map((card) => (\n <div key={card.label} className=\"rounded-md border border-border bg-card p-4\">\n <p className=\"text-xs font-medium text-muted-foreground\">{card.label}</p>\n <p className=\"mt-1 text-2xl font-semibold text-foreground\">{card.value}</p>\n </div>\n ))}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-4\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">DLQ pending</span>\n <StatusBadge variant={dlqPending > 0 ? 'destructive' : 'success'}>\n {dlqPending}\n </StatusBadge>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">Broadcasts in flight</span>\n <span className=\"text-sm font-medium text-foreground\">{data.broadcastsInFlight}</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">Queue</span>\n <StatusBadge variant={data.queueHealthy ? 'success' : 'destructive'}>\n {data.queueHealthy ? 'Healthy' : 'Unhealthy'}\n </StatusBadge>\n </div>\n </div>\n\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Channel\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Sends\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Delivered\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Failed\n </th>\n </tr>\n </thead>\n <tbody>\n {channels.length === 0 ? (\n <tr className=\"border-b border-border\">\n <td colSpan={4} className=\"py-3 text-center text-muted-foreground\">\n No channel activity\n </td>\n </tr>\n ) : (\n channels.map((row) => (\n <tr key={row.channel} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 text-foreground\">{row.channel}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.sends}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.delivered}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.failed}</td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n\n <p className=\"text-xs text-muted-foreground\">Generated {formatDateTime(data.generatedAt)}</p>\n </section>\n );\n}\n","import { useState } from 'react';\nimport { cn, formatDateTime, StatusBadge, type StatusBadgeVariant } from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\n\nexport interface DeliveryLogExplorerRow {\n id: string;\n channel: string;\n userId: string;\n recipient: string | null;\n status: string;\n provider: string | null;\n attempts: number;\n sentAt: string | null;\n createdAt: string;\n}\n\nexport interface DeliveryLogExplorerPage {\n items: DeliveryLogExplorerRow[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface DeliveryLogExplorerProps {\n basePath?: string;\n className?: string;\n}\n\ninterface Filters {\n channel: string;\n status: string;\n recipient: string;\n userId: string;\n from: string;\n to: string;\n}\n\nconst LIMIT = 20;\n\nconst EMPTY_FILTERS: Filters = {\n channel: '',\n status: '',\n recipient: '',\n userId: '',\n from: '',\n to: '',\n};\n\nfunction channelVariant(channel: string): StatusBadgeVariant {\n switch (channel) {\n case 'email':\n return 'neutral';\n case 'sms':\n return 'warning';\n default:\n return 'neutral';\n }\n}\n\n/**\n * Cross-channel delivery log explorer. Filterable by channel, status,\n * recipient, user, and date range; paginated. Recipients are masked\n * server-side. Changing any filter resets to page 1.\n */\nexport function DeliveryLogExplorer({ basePath = '/api', className }: DeliveryLogExplorerProps) {\n const [page, setPage] = useState(1);\n const [draft, setDraft] = useState<Filters>(EMPTY_FILTERS);\n const [applied, setApplied] = useState<Filters>(EMPTY_FILTERS);\n\n const queryString = (() => {\n const params = new URLSearchParams();\n params.set('page', String(page));\n params.set('limit', String(LIMIT));\n if (applied.channel) params.set('channel', applied.channel);\n if (applied.status) params.set('status', applied.status);\n if (applied.userId) params.set('userId', applied.userId);\n if (applied.recipient) params.set('recipient', applied.recipient);\n if (applied.from) params.set('from', applied.from);\n if (applied.to) params.set('to', applied.to);\n return params.toString();\n })();\n\n const { data, isLoading, isError, refetch } = useApiQuery<DeliveryLogExplorerPage>(\n ['delivery-logs', page, applied],\n (client) => client.get(`${basePath}/v1/admin/delivery-logs?${queryString}`),\n );\n\n const onApply = (event: React.FormEvent) => {\n event.preventDefault();\n setPage(1);\n setApplied({\n channel: draft.channel,\n status: draft.status.trim(),\n recipient: draft.recipient.trim(),\n userId: draft.userId.trim(),\n from: draft.from,\n to: draft.to,\n });\n };\n\n const setField = (key: keyof Filters, value: string) =>\n setDraft((prev) => ({ ...prev, [key]: value }));\n\n const filterForm = (\n <form onSubmit={onApply} className=\"flex flex-wrap items-end gap-3\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"dle-channel\" className=\"text-sm font-medium text-foreground\">\n Channel\n </label>\n <select\n id=\"dle-channel\"\n value={draft.channel}\n onChange={(e) => setField('channel', e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <option value=\"\">All</option>\n <option value=\"email\">Email</option>\n <option value=\"sms\">SMS</option>\n </select>\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"dle-status\" className=\"text-sm font-medium text-foreground\">\n Status\n </label>\n <input\n id=\"dle-status\"\n type=\"text\"\n value={draft.status}\n onChange={(e) => setField('status', e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"dle-recipient\" className=\"text-sm font-medium text-foreground\">\n Recipient\n </label>\n <input\n id=\"dle-recipient\"\n type=\"text\"\n value={draft.recipient}\n onChange={(e) => setField('recipient', e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"dle-user\" className=\"text-sm font-medium text-foreground\">\n User ID\n </label>\n <input\n id=\"dle-user\"\n type=\"text\"\n value={draft.userId}\n onChange={(e) => setField('userId', e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"dle-from\" className=\"text-sm font-medium text-foreground\">\n From\n </label>\n <input\n id=\"dle-from\"\n type=\"date\"\n value={draft.from}\n onChange={(e) => setField('from', e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"dle-to\" className=\"text-sm font-medium text-foreground\">\n To\n </label>\n <input\n id=\"dle-to\"\n type=\"date\"\n value={draft.to}\n onChange={(e) => setField('to', e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <button\n type=\"submit\"\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Apply\n </button>\n </form>\n );\n\n let body: React.ReactNode;\n\n if (isLoading) {\n body = (\n <div role=\"status\" aria-label=\"Loading delivery logs\" className=\"flex flex-col gap-2 p-4\">\n <span className=\"sr-only\">Loading delivery logs</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n } else if (isError) {\n body = (\n <div className=\"flex flex-col items-start gap-3 p-4\">\n <p className=\"text-sm text-foreground\">Failed to load delivery logs</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n } else {\n const rows = data?.items ?? [];\n const totalPages = data?.totalPages ?? 1;\n\n if (rows.length === 0) {\n body = <div className=\"p-6 text-center text-sm text-muted-foreground\">No delivery logs</div>;\n } else {\n body = (\n <>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Channel\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Recipient\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n User\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Provider\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Attempts\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border\">\n <td className=\"py-3 pe-4\">\n <StatusBadge variant={channelVariant(row.channel)} appearance=\"dot\">\n {row.channel}\n </StatusBadge>\n </td>\n <td className=\"px-4 py-3 text-foreground\">{row.recipient ?? '—'}</td>\n <td className=\"px-4 py-3 font-mono text-foreground\">{row.userId}</td>\n <td className=\"px-4 py-3 text-foreground\">{row.status}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.provider ?? '—'}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.attempts}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {formatDateTime(row.createdAt)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n <nav aria-label=\"Delivery log pagination\" className=\"flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n disabled={page <= 1}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Previous\n </button>\n <span className=\"text-xs text-muted-foreground\">\n Page {page} of {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.min(totalPages, p + 1))}\n disabled={page >= totalPages}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Next\n </button>\n </nav>\n </>\n );\n }\n }\n\n return (\n <section aria-label=\"Delivery log explorer\" className={cn('flex flex-col gap-4', className)}>\n {filterForm}\n {body}\n </section>\n );\n}\n","import { useEffect, useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface QuietHours {\n enabled: boolean;\n start: string;\n end: string;\n timezone: string;\n}\n\nexport interface QuietHoursFormProps {\n basePath?: string;\n className?: string;\n}\n\nconst DEFAULTS: QuietHours = {\n enabled: false,\n start: '22:00',\n end: '08:00',\n timezone: 'UTC',\n};\n\n/** Normalizes a loosely-typed quiet-hours payload into the strict shape. */\nfunction normalize(raw: unknown): QuietHours {\n const obj = (raw ?? {}) as Record<string, unknown>;\n return {\n enabled: typeof obj.enabled === 'boolean' ? obj.enabled : DEFAULTS.enabled,\n start:\n typeof obj.start === 'string'\n ? obj.start\n : typeof obj.startHour === 'string'\n ? obj.startHour\n : DEFAULTS.start,\n end:\n typeof obj.end === 'string'\n ? obj.end\n : typeof obj.endHour === 'string'\n ? obj.endHour\n : DEFAULTS.end,\n timezone: typeof obj.timezone === 'string' ? obj.timezone : DEFAULTS.timezone,\n };\n}\n\n/**\n * Quiet-hours configuration form. Loads the current window via GET and saves\n * via PUT. Tolerates absent/legacy fields (startHour/endHour) and falls back\n * to sensible defaults. ApiError-aware toasts on save.\n */\nexport function QuietHoursForm({ basePath = '/api', className }: QuietHoursFormProps) {\n const toast = useToast();\n const url = `${basePath}/notifications/config/quiet-hours`;\n\n const { data, isLoading, isError, refetch } = useApiQuery<unknown>(['quiet-hours'], (client) =>\n client.get(url),\n );\n\n const [form, setForm] = useState<QuietHours>(DEFAULTS);\n\n useEffect(() => {\n if (data !== undefined) {\n setForm(normalize(data));\n }\n }, [data]);\n\n const save = useApiMutation<unknown, QuietHours>((client, payload) => client.put(url, payload), {\n invalidates: [['quiet-hours']],\n onSuccess: () => toast.success('Quiet hours saved'),\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n });\n\n const onSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n save.mutate(form);\n };\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading quiet hours\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading quiet hours</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load quiet hours</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n return (\n <form onSubmit={onSubmit} className={cn('flex flex-col gap-4', className)} noValidate>\n <h2 className=\"text-sm font-semibold text-foreground\">Quiet hours</h2>\n\n <label className=\"flex items-center gap-2 text-sm text-foreground\">\n <input\n type=\"checkbox\"\n checked={form.enabled}\n onChange={(e) => setForm((prev) => ({ ...prev, enabled: e.target.checked }))}\n className=\"focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n Enable quiet hours\n </label>\n\n <div className=\"flex flex-wrap gap-4\">\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"qh-start\" className=\"text-sm font-medium text-foreground\">\n Start\n </label>\n <input\n id=\"qh-start\"\n type=\"time\"\n value={form.start}\n onChange={(e) => setForm((prev) => ({ ...prev, start: e.target.value }))}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"qh-end\" className=\"text-sm font-medium text-foreground\">\n End\n </label>\n <input\n id=\"qh-end\"\n type=\"time\"\n value={form.end}\n onChange={(e) => setForm((prev) => ({ ...prev, end: e.target.value }))}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"qh-tz\" className=\"text-sm font-medium text-foreground\">\n Timezone\n </label>\n <input\n id=\"qh-tz\"\n type=\"text\"\n value={form.timezone}\n onChange={(e) => setForm((prev) => ({ ...prev, timezone: e.target.value }))}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n </div>\n\n <div>\n <button\n type=\"submit\"\n disabled={save.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {save.isPending ? 'Saving…' : 'Save'}\n </button>\n </div>\n </form>\n );\n}\n","import { useEffect, useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface Cap {\n type: string;\n maxPerDay: number;\n}\n\nexport interface FrequencyCapTableProps {\n basePath?: string;\n className?: string;\n}\n\n/** Normalizes an array | { caps } payload (with limit/maxPerDay/perDay) into Cap[]. */\nfunction normalize(raw: unknown): Cap[] {\n const list = Array.isArray(raw)\n ? raw\n : Array.isArray((raw as Record<string, unknown>)?.caps)\n ? ((raw as Record<string, unknown>).caps as unknown[])\n : [];\n return list.map((entry) => {\n const obj = (entry ?? {}) as Record<string, unknown>;\n const max =\n typeof obj.maxPerDay === 'number'\n ? obj.maxPerDay\n : typeof obj.limit === 'number'\n ? obj.limit\n : typeof obj.perDay === 'number'\n ? obj.perDay\n : 0;\n return { type: typeof obj.type === 'string' ? obj.type : '', maxPerDay: max };\n });\n}\n\n/**\n * Frequency-cap editor. Loads the current per-type caps via GET, renders an\n * editable table with add/remove rows, and saves the full list via PUT.\n * Tolerates array | { caps } shapes and limit/maxPerDay/perDay field names.\n */\nexport function FrequencyCapTable({ basePath = '/api', className }: FrequencyCapTableProps) {\n const toast = useToast();\n const url = `${basePath}/notifications/config/frequency-cap`;\n\n const { data, isLoading, isError, refetch } = useApiQuery<unknown>(['frequency-cap'], (client) =>\n client.get(url),\n );\n\n const [caps, setCaps] = useState<Cap[]>([]);\n const [newType, setNewType] = useState('');\n const [newMax, setNewMax] = useState(0);\n\n useEffect(() => {\n if (data !== undefined) {\n setCaps(normalize(data));\n }\n }, [data]);\n\n const save = useApiMutation<unknown, { caps: Cap[] }>(\n (client, payload) => client.put(url, payload),\n {\n invalidates: [['frequency-cap']],\n onSuccess: () => toast.success('Frequency caps saved'),\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n const updateRow = (index: number, value: number) =>\n setCaps((prev) => prev.map((cap, i) => (i === index ? { ...cap, maxPerDay: value } : cap)));\n\n const removeRow = (index: number) => setCaps((prev) => prev.filter((_, i) => i !== index));\n\n const addRow = (event: React.FormEvent) => {\n event.preventDefault();\n const type = newType.trim();\n if (!type) return;\n setCaps((prev) => [...prev, { type, maxPerDay: newMax }]);\n setNewType('');\n setNewMax(0);\n };\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading frequency caps\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading frequency caps</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load frequency caps</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n return (\n <section aria-label=\"Frequency caps\" className={cn('flex flex-col gap-4', className)}>\n <h2 className=\"text-sm font-semibold text-foreground\">Frequency caps</h2>\n\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Type\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Max per day\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n <span className=\"sr-only\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {caps.map((cap, index) => {\n const inputId = `cap-${index}`;\n return (\n <tr key={`${cap.type}-${index}`} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 text-foreground\">{cap.type}</td>\n <td className=\"px-4 py-3\">\n <label htmlFor={inputId} className=\"sr-only\">\n Max per day for {cap.type}\n </label>\n <input\n id={inputId}\n type=\"number\"\n min={0}\n value={cap.maxPerDay}\n onChange={(e) => updateRow(index, Number(e.target.value))}\n className=\"w-24 rounded-md border border-border bg-background px-3 py-1.5 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </td>\n <td className=\"px-4 py-3\">\n <button\n type=\"button\"\n onClick={() => removeRow(index)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Remove\n </button>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n\n <form onSubmit={addRow} className=\"flex flex-wrap items-end gap-3\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"cap-new-type\" className=\"text-sm font-medium text-foreground\">\n New type\n </label>\n <input\n id=\"cap-new-type\"\n type=\"text\"\n value={newType}\n onChange={(e) => setNewType(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"cap-new-max\" className=\"text-sm font-medium text-foreground\">\n Max per day\n </label>\n <input\n id=\"cap-new-max\"\n type=\"number\"\n min={0}\n value={newMax}\n onChange={(e) => setNewMax(Number(e.target.value))}\n className=\"w-24 rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <button\n type=\"submit\"\n className=\"rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Add\n </button>\n </form>\n\n <div>\n <button\n type=\"button\"\n disabled={save.isPending}\n onClick={() => save.mutate({ caps })}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {save.isPending ? 'Saving…' : 'Save'}\n </button>\n </div>\n </section>\n );\n}\n","import { useEffect, useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface TenantConfig {\n notificationTypes: string[];\n immediateEmailTypes: string[];\n}\n\nexport interface TenantConfigFormProps {\n basePath?: string;\n className?: string;\n}\n\n/** Normalizes the tenant-config payload, defaulting both lists to []. */\nfunction normalize(raw: unknown): TenantConfig {\n const obj = (raw ?? {}) as Record<string, unknown>;\n const toList = (value: unknown): string[] =>\n Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string') : [];\n return {\n notificationTypes: toList(obj.notificationTypes),\n immediateEmailTypes: toList(obj.immediateEmailTypes),\n };\n}\n\ninterface TagEditorProps {\n id: string;\n label: string;\n values: string[];\n onAdd: (value: string) => void;\n onRemove: (value: string) => void;\n}\n\nfunction TagEditor({ id, label, values, onAdd, onRemove }: TagEditorProps) {\n const [draft, setDraft] = useState('');\n\n const add = (event: React.FormEvent) => {\n event.preventDefault();\n const value = draft.trim();\n if (!value) return;\n onAdd(value);\n setDraft('');\n };\n\n return (\n <div className=\"flex flex-col gap-2\">\n <span className=\"text-sm font-medium text-foreground\">{label}</span>\n <ul className=\"flex flex-wrap gap-2\">\n {values.length === 0 ? (\n <li className=\"text-sm text-muted-foreground\">None</li>\n ) : (\n values.map((value) => (\n <li\n key={value}\n className=\"flex items-center gap-1 rounded-md border border-border bg-card px-2 py-1 text-sm text-foreground\"\n >\n {value}\n <button\n type=\"button\"\n aria-label={`Remove ${value}`}\n onClick={() => onRemove(value)}\n className=\"rounded text-muted-foreground hover:text-destructive focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n ×\n </button>\n </li>\n ))\n )}\n </ul>\n <form onSubmit={add} className=\"flex items-end gap-2\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor={id} className=\"sr-only\">\n Add to {label}\n </label>\n <input\n id={id}\n type=\"text\"\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <button\n type=\"submit\"\n className=\"rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Add\n </button>\n </form>\n </div>\n );\n}\n\n/**\n * Tenant notification-config form. Edits the set of notification types and the\n * subset enabled for immediate email. Enforces (matching the backend rule)\n * that immediateEmailTypes is a subset of notificationTypes.\n */\nexport function TenantConfigForm({ basePath = '/api', className }: TenantConfigFormProps) {\n const toast = useToast();\n const url = `${basePath}/admin/notification-config`;\n\n const { data, isLoading, isError, refetch } = useApiQuery<unknown>(['tenant-config'], (client) =>\n client.get(url),\n );\n\n const [config, setConfig] = useState<TenantConfig>({\n notificationTypes: [],\n immediateEmailTypes: [],\n });\n const [subsetError, setSubsetError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (data !== undefined) {\n setConfig(normalize(data));\n }\n }, [data]);\n\n const save = useApiMutation<unknown, TenantConfig>(\n (client, payload) => client.put(url, payload),\n {\n invalidates: [['tenant-config']],\n onSuccess: () => toast.success('Configuration saved'),\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n const addType = (value: string) =>\n setConfig((prev) =>\n prev.notificationTypes.includes(value)\n ? prev\n : { ...prev, notificationTypes: [...prev.notificationTypes, value] },\n );\n\n const removeType = (value: string) =>\n setConfig((prev) => ({\n ...prev,\n notificationTypes: prev.notificationTypes.filter((t) => t !== value),\n }));\n\n const addImmediate = (value: string) =>\n setConfig((prev) =>\n prev.immediateEmailTypes.includes(value)\n ? prev\n : { ...prev, immediateEmailTypes: [...prev.immediateEmailTypes, value] },\n );\n\n const removeImmediate = (value: string) =>\n setConfig((prev) => ({\n ...prev,\n immediateEmailTypes: prev.immediateEmailTypes.filter((t) => t !== value),\n }));\n\n const onSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n const invalid = config.immediateEmailTypes.filter((t) => !config.notificationTypes.includes(t));\n if (invalid.length > 0) {\n setSubsetError(\n `Immediate email types must be a subset of notification types. Not allowed: ${invalid.join(', ')}`,\n );\n return;\n }\n setSubsetError(undefined);\n save.mutate(config);\n };\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading tenant configuration\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading tenant configuration</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load tenant configuration</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const errorId = 'tenant-config-subset-error';\n\n return (\n <form\n onSubmit={onSubmit}\n className={cn('flex flex-col gap-5', className)}\n noValidate\n aria-invalid={subsetError ? 'true' : undefined}\n aria-describedby={subsetError ? errorId : undefined}\n >\n <h2 className=\"text-sm font-semibold text-foreground\">Notification configuration</h2>\n\n <TagEditor\n id=\"tc-notification-types\"\n label=\"Notification types\"\n values={config.notificationTypes}\n onAdd={addType}\n onRemove={removeType}\n />\n\n <TagEditor\n id=\"tc-immediate-email-types\"\n label=\"Immediate email types\"\n values={config.immediateEmailTypes}\n onAdd={addImmediate}\n onRemove={removeImmediate}\n />\n\n {subsetError && (\n <p id={errorId} className=\"text-xs text-destructive\">\n {subsetError}\n </p>\n )}\n\n <div>\n <button\n type=\"submit\"\n disabled={save.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {save.isPending ? 'Saving…' : 'Save'}\n </button>\n </div>\n </form>\n );\n}\n","import { useEffect, useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface TrackingConfig {\n openTrackingEnabled: boolean;\n clickTrackingEnabled: boolean;\n}\n\nexport interface TrackingConfigFormProps {\n basePath?: string;\n className?: string;\n}\n\n/** Normalizes the tracking-config payload, tolerating opensEnabled/clicksEnabled. */\nfunction normalize(raw: unknown): TrackingConfig {\n const obj = (raw ?? {}) as Record<string, unknown>;\n const bool = (...keys: string[]): boolean => {\n for (const key of keys) {\n if (typeof obj[key] === 'boolean') return obj[key] as boolean;\n }\n return false;\n };\n return {\n openTrackingEnabled: bool('openTrackingEnabled', 'opensEnabled'),\n clickTrackingEnabled: bool('clickTrackingEnabled', 'clicksEnabled'),\n };\n}\n\n/**\n * Email tracking-config form. Loads open/click tracking flags via GET and\n * persists them via POST. Tolerates absent or legacy field names and defaults\n * both flags to off. ApiError-aware toasts on save.\n */\nexport function TrackingConfigForm({ basePath = '/api', className }: TrackingConfigFormProps) {\n const toast = useToast();\n const url = `${basePath}/analytics/notifications/tracking-config`;\n\n const { data, isLoading, isError, refetch } = useApiQuery<unknown>(\n ['tracking-config'],\n (client) => client.get(url),\n );\n\n const [form, setForm] = useState<TrackingConfig>({\n openTrackingEnabled: false,\n clickTrackingEnabled: false,\n });\n\n useEffect(() => {\n if (data !== undefined) {\n setForm(normalize(data));\n }\n }, [data]);\n\n const save = useApiMutation<unknown, TrackingConfig>(\n (client, payload) => client.post(url, payload),\n {\n invalidates: [['tracking-config']],\n onSuccess: () => toast.success('Tracking configuration saved'),\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n const onSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n save.mutate(form);\n };\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading tracking configuration\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading tracking configuration</span>\n {[0, 1].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load tracking configuration</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n return (\n <form onSubmit={onSubmit} className={cn('flex flex-col gap-4', className)} noValidate>\n <h2 className=\"text-sm font-semibold text-foreground\">Tracking configuration</h2>\n\n <label className=\"flex items-center gap-2 text-sm text-foreground\">\n <input\n type=\"checkbox\"\n checked={form.openTrackingEnabled}\n onChange={(e) => setForm((prev) => ({ ...prev, openTrackingEnabled: e.target.checked }))}\n className=\"focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n Open tracking\n </label>\n\n <label className=\"flex items-center gap-2 text-sm text-foreground\">\n <input\n type=\"checkbox\"\n checked={form.clickTrackingEnabled}\n onChange={(e) => setForm((prev) => ({ ...prev, clickTrackingEnabled: e.target.checked }))}\n className=\"focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n Click tracking\n </label>\n\n <div>\n <button\n type=\"submit\"\n disabled={save.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {save.isPending ? 'Saving…' : 'Save'}\n </button>\n </div>\n </form>\n );\n}\n","/**\n * NOTE: The backend does NOT yet expose the `/v1/admin/api-keys` endpoint.\n * This component targets that contract so it is ready when the endpoint lands.\n * Until then the list query will 404 and the component renders its error state\n * (\"Failed to load API keys\" + Try again) gracefully.\n */\nimport { useState } from 'react';\nimport { cn, formatDateTime, StatusBadge, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface ApiKey {\n id: string;\n name: string;\n prefix?: string;\n /** Bound application slug (SPEC-application-scoping); null/absent = unscoped. */\n applicationKey?: string | null;\n createdAt: string;\n lastUsedAt?: string | null;\n revoked?: boolean;\n}\n\nexport interface ApiKeyCreateResponse {\n id?: string;\n name?: string;\n key?: string;\n secret?: string;\n}\n\nexport interface ApiKeyManagerProps {\n basePath?: string;\n className?: string;\n}\n\n/** Normalizes an array | { items } payload into ApiKey[]. */\nfunction normalize(raw: unknown): ApiKey[] {\n const list = Array.isArray(raw)\n ? raw\n : Array.isArray((raw as Record<string, unknown>)?.items)\n ? ((raw as Record<string, unknown>).items as unknown[])\n : [];\n return list as ApiKey[];\n}\n\n/**\n * API key manager. Lists keys, creates new keys (surfacing the one-time secret\n * in a toast), and revokes keys (confirmed). All mutations surface\n * ApiError-aware toasts. See file-level note re: backend availability.\n */\nexport function ApiKeyManager({ basePath = '/api', className }: ApiKeyManagerProps) {\n const toast = useToast();\n const url = `${basePath}/v1/admin/api-keys`;\n\n const { data, isLoading, isError, refetch } = useApiQuery<unknown>(['api-keys'], (client) =>\n client.get(url),\n );\n\n const [name, setName] = useState('');\n const [applicationKey, setApplicationKey] = useState('');\n\n const onMutationError = (error: {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n }) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n\n const create = useApiMutation<ApiKeyCreateResponse, { name: string; applicationKey?: string }>(\n (client, vars) =>\n client.post(url, {\n name: vars.name,\n ...(vars.applicationKey ? { applicationKey: vars.applicationKey } : {}),\n }),\n {\n invalidates: [['api-keys']],\n onSuccess: (result) => {\n const secret = result?.key ?? result?.secret;\n if (secret) {\n toast.success('API key created — copy it now', {\n description: `This secret is shown only once: ${secret}`,\n });\n } else {\n toast.success('API key created');\n }\n setName('');\n setApplicationKey('');\n },\n onError: onMutationError,\n },\n );\n\n const revoke = useApiMutation<void, string>((client, id) => client.delete(`${url}/${id}`), {\n invalidates: [['api-keys']],\n onSuccess: () => {\n toast.success('API key revoked');\n void refetch();\n },\n onError: onMutationError,\n });\n\n const onCreate = (event: React.FormEvent) => {\n event.preventDefault();\n const trimmed = name.trim();\n if (!trimmed) return;\n create.mutate({ name: trimmed, applicationKey: applicationKey.trim() || undefined });\n };\n\n const onRevoke = (id: string) => {\n if (window.confirm('Revoke this API key? Applications using it will lose access.')) {\n revoke.mutate(id);\n }\n };\n\n const createForm = (\n <form onSubmit={onCreate} className=\"flex flex-wrap items-end gap-3\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"api-key-name\" className=\"text-sm font-medium text-foreground\">\n New key name\n </label>\n <input\n id=\"api-key-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"api-key-app\" className=\"text-sm font-medium text-foreground\">\n Application (optional)\n </label>\n <input\n id=\"api-key-app\"\n type=\"text\"\n value={applicationKey}\n onChange={(e) => setApplicationKey(e.target.value)}\n placeholder=\"delivery-hub\"\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {create.isPending ? 'Creating…' : 'Create key'}\n </button>\n </form>\n );\n\n let body: React.ReactNode;\n\n if (isLoading) {\n body = (\n <div role=\"status\" aria-label=\"Loading API keys\" className=\"flex flex-col gap-2 p-4\">\n <span className=\"sr-only\">Loading API keys</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n } else if (isError) {\n body = (\n <div className=\"flex flex-col items-start gap-3 p-4\">\n <p className=\"text-sm text-foreground\">Failed to load API keys</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n } else {\n const rows = normalize(data);\n if (rows.length === 0) {\n body = <div className=\"p-6 text-center text-sm text-muted-foreground\">No API keys</div>;\n } else {\n body = (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Name\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Prefix\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Application\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Last used\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n <span className=\"sr-only\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 text-foreground\">{row.name}</td>\n <td className=\"px-4 py-3 font-mono text-muted-foreground\">{row.prefix ?? '—'}</td>\n <td className=\"px-4 py-3 font-mono text-muted-foreground\">\n {row.applicationKey ?? '—'}\n </td>\n <td className=\"px-4 py-3\">\n <StatusBadge variant={row.revoked ? 'destructive' : 'success'}>\n {row.revoked ? 'Revoked' : 'Active'}\n </StatusBadge>\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">{formatDateTime(row.createdAt)}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {row.lastUsedAt ? formatDateTime(row.lastUsedAt) : '—'}\n </td>\n <td className=\"px-4 py-3\">\n <button\n type=\"button\"\n disabled={revoke.isPending || row.revoked}\n onClick={() => onRevoke(row.id)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Revoke\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n }\n }\n\n return (\n <section aria-label=\"API key management\" className={cn('flex flex-col gap-4', className)}>\n {createForm}\n {body}\n </section>\n );\n}\n","import { useState } from 'react';\nimport { cn, formatDateTime, StatusBadge, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface Application {\n id: string;\n key: string;\n displayName: string;\n description: string | null;\n status: 'active' | 'disabled';\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface ApplicationRegistryPanelProps {\n /** API path prefix (BFF). Endpoints are mounted at `${basePath}/admin/applications`. */\n basePath?: string;\n className?: string;\n}\n\ninterface MutationError {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n}\n\n/** Normalizes an array | { items } payload into Application[]. */\nfunction normalize(raw: unknown): Application[] {\n const list = Array.isArray(raw)\n ? raw\n : Array.isArray((raw as Record<string, unknown>)?.items)\n ? ((raw as Record<string, unknown>).items as unknown[])\n : [];\n return list as Application[];\n}\n\n/**\n * Global application registry manager (SPEC-application-scoping-and-registry).\n * Lists registered applications, registers new ones, and enables/disables them.\n * Platform-admin only (the backend gates `notification:platform-admin`). All\n * mutations surface ApiError-aware toasts.\n */\nexport function ApplicationRegistryPanel({\n basePath = '/api',\n className,\n}: ApplicationRegistryPanelProps) {\n const toast = useToast();\n const url = `${basePath}/admin/applications`;\n\n const { data, isLoading, isError, refetch } = useApiQuery<unknown>(['applications'], (client) =>\n client.get(url),\n );\n\n const [key, setKey] = useState('');\n const [displayName, setDisplayName] = useState('');\n const [description, setDescription] = useState('');\n\n const onMutationError = (error: MutationError) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n\n const register = useApiMutation<\n Application,\n { key: string; displayName: string; description?: string }\n >((client, body) => client.post(url, body), {\n invalidates: [['applications']],\n onSuccess: () => {\n toast.success('Application registered');\n setKey('');\n setDisplayName('');\n setDescription('');\n },\n onError: onMutationError,\n });\n\n const setStatus = useApiMutation<\n Application,\n { key: string; status: 'active' | 'disabled' }\n >((client, body) => client.patch(`${url}/${body.key}`, { status: body.status }), {\n invalidates: [['applications']],\n onSuccess: () => {\n toast.success('Application updated');\n void refetch();\n },\n onError: onMutationError,\n });\n\n const onRegister = (event: React.FormEvent) => {\n event.preventDefault();\n const k = key.trim();\n const name = displayName.trim();\n if (!k || !name) return;\n register.mutate({ key: k, displayName: name, description: description.trim() || undefined });\n };\n\n const registerForm = (\n <form onSubmit={onRegister} className=\"flex flex-wrap items-end gap-3\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"application-key\" className=\"text-sm font-medium text-foreground\">\n Key (slug)\n </label>\n <input\n id=\"application-key\"\n type=\"text\"\n value={key}\n onChange={(e) => setKey(e.target.value)}\n placeholder=\"delivery-hub\"\n className=\"rounded border border-border bg-background px-3 py-1.5 text-sm text-foreground\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"application-name\" className=\"text-sm font-medium text-foreground\">\n Display name\n </label>\n <input\n id=\"application-name\"\n type=\"text\"\n value={displayName}\n onChange={(e) => setDisplayName(e.target.value)}\n placeholder=\"DeliveryHub\"\n className=\"rounded border border-border bg-background px-3 py-1.5 text-sm text-foreground\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"application-description\" className=\"text-sm font-medium text-foreground\">\n Description (optional)\n </label>\n <input\n id=\"application-description\"\n type=\"text\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n className=\"rounded border border-border bg-background px-3 py-1.5 text-sm text-foreground\"\n />\n </div>\n <button\n type=\"submit\"\n disabled={register.isPending}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Register\n </button>\n </form>\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading applications\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading applications</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load applications</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const apps = normalize(data);\n\n return (\n <section aria-label=\"Applications\" className={cn('flex flex-col gap-4 p-4', className)}>\n {registerForm}\n\n {apps.length === 0 ? (\n <p className=\"p-6 text-center text-sm text-muted-foreground\">No applications registered</p>\n ) : (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th className=\"py-2 font-medium\">Key</th>\n <th className=\"py-2 font-medium\">Name</th>\n <th className=\"py-2 font-medium\">Status</th>\n <th className=\"py-2 font-medium\">Created</th>\n <th className=\"py-2 font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {apps.map((app) => (\n <tr key={app.id} className=\"border-b border-border\">\n <td className=\"py-2 font-mono text-foreground\">{app.key}</td>\n <td className=\"py-2 text-foreground\">{app.displayName}</td>\n <td className=\"py-2\">\n <StatusBadge variant={app.status === 'active' ? 'success' : 'neutral'}>\n {app.status}\n </StatusBadge>\n </td>\n <td className=\"py-2 text-muted-foreground\">{formatDateTime(app.createdAt)}</td>\n <td className=\"py-2\">\n <button\n type=\"button\"\n disabled={setStatus.isPending}\n onClick={() =>\n setStatus.mutate({\n key: app.key,\n status: app.status === 'active' ? 'disabled' : 'active',\n })\n }\n className=\"text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {app.status === 'active' ? 'Disable' : 'Enable'}\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </section>\n );\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","import_react","import_react_query","import_jsx_runtime","import_react_query","import_react","import_react_query","import_react_ui","import_react_ui","import_jsx_runtime","import_react_ui","import_jsx_runtime","import_react","import_react_ui","import_jsx_runtime","import_react","import_react_ui","import_react_query","import_react_query","import_react_query","import_react_ui","import_jsx_runtime","import_react_ui","import_jsx_runtime","import_react_ui","import_jsx_runtime","pct","import_jsx_runtime","import_react_ui","import_jsx_runtime","import_react_ui","import_react_query","import_jsx_runtime","import_react","import_react_ui","import_react_query","import_jsx_runtime","import_react","import_react_ui","import_react_query","import_jsx_runtime","import_react_ui","import_react_query","import_jsx_runtime","import_react","import_react_ui","import_react_query","import_jsx_runtime","import_react_query","LIMIT","import_react","import_react_ui","import_jsx_runtime","import_react_ui","import_react_query","import_jsx_runtime","statusVariant","pct","import_react","import_react_ui","import_react_query","import_jsx_runtime","CHANNELS","import_react_ui","import_react_query","import_jsx_runtime","import_react","import_react_ui","import_react_query","import_jsx_runtime","import_react","import_react_ui","import_react_query","import_jsx_runtime","LIMIT","CHANNELS","import_react","import_react_ui","import_react_query","import_jsx_runtime","LIMIT","statusVariant","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react","import_react_ui","import_react_query","import_jsx_runtime","LIMIT","import_react","import_react_ui","import_react_query","import_jsx_runtime","import_react_ui","import_react_query","import_jsx_runtime","import_react","import_react_ui","import_react_query","import_jsx_runtime","LIMIT","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/notification-provider.tsx","../src/notification-realtime-provider.tsx","../src/notification-preferences.tsx","../src/use-unread-count.ts","../src/use-notification-feed.ts","../src/notification-bell.tsx","../src/notification-inbox.tsx","../src/notification-center.tsx","../src/delivery-analytics-page.tsx","../src/use-delivery-analytics.ts","../src/use-funnel-stats.ts","../src/use-delivery-types.ts","../src/funnel-stats.tsx","../src/trend-chart.tsx","../src/type-table.tsx","../src/template-status-badge.tsx","../src/template-list.tsx","../src/template-editor.tsx","../src/template-preview-pane.tsx","../src/template-version-history.tsx","../src/delivery-log-viewer.tsx","../src/use-broadcasts.ts","../src/broadcast-list.tsx","../src/broadcast-progress.tsx","../src/broadcast-composer.tsx","../src/segment-list.tsx","../src/segment-builder.tsx","../src/suppression-manager.tsx","../src/admin-panel.tsx","../src/dlq-console.tsx","../src/catalog-editor.tsx","../src/missing-translations-panel.tsx","../src/fallback-report-panel.tsx","../src/recipient-admin-panel.tsx","../src/webhook-endpoint-manager.tsx","../src/operations-overview.tsx","../src/delivery-log-explorer.tsx","../src/quiet-hours-form.tsx","../src/frequency-cap-table.tsx","../src/tenant-config-form.tsx","../src/tracking-config-form.tsx","../src/api-key-manager.tsx","../src/application-registry-panel.tsx"],"sourcesContent":["export {\n NotificationProvider,\n useNotificationConfig,\n type NotificationProviderProps,\n type NotificationConfig,\n} from './notification-provider';\n\nexport {\n NotificationPreferences,\n type NotificationPreferencesProps,\n type NotificationPreferenceDto,\n type NotificationChannel,\n type DigestPeriod,\n} from './notification-preferences';\n\nexport {\n NotificationRealtimeProvider,\n useRealtimeContext,\n type NotificationRealtimeProviderProps,\n type RealtimeStatus,\n} from './notification-realtime-provider';\n\nexport { useUnreadCount, type UseUnreadCountOptions } from './use-unread-count';\n\nexport {\n useNotificationFeed,\n type UseNotificationFeedOptions,\n type NotificationFeedItem,\n type PaginatedFeed,\n} from './use-notification-feed';\n\nexport { NotificationBell, type NotificationBellProps } from './notification-bell';\n\nexport { NotificationInbox, type NotificationInboxProps } from './notification-inbox';\n\nexport { NotificationCenter, type NotificationCenterProps } from './notification-center';\n\nexport { DeliveryAnalyticsPage, type DeliveryAnalyticsPageProps } from './delivery-analytics-page';\nexport { FunnelStats, type FunnelStatsProps } from './funnel-stats';\nexport { TrendChart, type TrendChartProps } from './trend-chart';\nexport { TypeTable, type TypeTableProps } from './type-table';\nexport {\n useDeliveryAnalytics,\n type UseDeliveryAnalyticsOptions,\n type DailyDeliveryStats,\n type DeliveryAnalyticsFilters,\n} from './use-delivery-analytics';\nexport {\n useFunnelStats,\n type UseFunnelStatsOptions,\n type DeliveryFunnel,\n} from './use-funnel-stats';\nexport {\n useDeliveryTypes,\n type UseDeliveryTypesOptions,\n type DeliveryTypeBreakdown,\n} from './use-delivery-types';\n\nexport { TemplateStatusBadge, type TemplateStatus } from './template-status-badge';\n\nexport { TemplateList, type TemplateListProps, type TemplateListItem } from './template-list';\n\nexport {\n TemplateEditor,\n type TemplateEditorProps,\n type TemplateEditorFields,\n type TemplateVersionResponse,\n} from './template-editor';\n\nexport {\n TemplatePreviewPane,\n type TemplatePreviewPaneProps,\n type PreviewResult,\n} from './template-preview-pane';\n\nexport {\n TemplateVersionHistory,\n type TemplateVersionHistoryProps,\n type TemplateVersion,\n} from './template-version-history';\n\nexport {\n DeliveryLogViewer,\n type DeliveryLogViewerProps,\n type DeliveryLogRow,\n type DeliveryLogPage,\n} from './delivery-log-viewer';\n\n// ─── Management console admin components (SPEC-notification-management-console) ───\n\nexport {\n useBroadcasts,\n type UseBroadcastsOptions,\n type BroadcastListItem,\n type BroadcastListPage,\n} from './use-broadcasts';\nexport { BroadcastList, type BroadcastListProps } from './broadcast-list';\nexport {\n BroadcastProgress,\n type BroadcastProgressProps,\n type BroadcastDetail,\n} from './broadcast-progress';\nexport {\n BroadcastComposer,\n type BroadcastComposerProps,\n type BroadcastCreatedResult,\n} from './broadcast-composer';\n\nexport { SegmentList, type SegmentListProps, type Segment } from './segment-list';\nexport {\n SegmentBuilder,\n type SegmentBuilderProps,\n type SegmentForm,\n type SegmentType,\n} from './segment-builder';\n\nexport {\n SuppressionManager,\n type SuppressionManagerProps,\n type Suppression,\n type SuppressionPage,\n type SuppressionChannel,\n} from './suppression-manager';\n\nexport {\n DlqConsole,\n type DlqConsoleProps,\n type DlqMessage,\n type DlqPage,\n type DlqMessageDetail,\n type DlqStatusFilter,\n} from './dlq-console';\n\nexport { CatalogEditor, type CatalogEditorProps, type CatalogEntry } from './catalog-editor';\nexport {\n MissingTranslationsPanel,\n type MissingTranslationsPanelProps,\n type MissingEntry,\n} from './missing-translations-panel';\nexport {\n FallbackReportPanel,\n type FallbackReportPanelProps,\n type FallbackEntry,\n} from './fallback-report-panel';\n\nexport {\n RecipientAdminPanel,\n type RecipientAdminPanelProps,\n type RecipientSummary,\n type RecipientPage,\n} from './recipient-admin-panel';\n\nexport {\n WebhookEndpointManager,\n type WebhookEndpointManagerProps,\n type WebhookEndpoint,\n type WebhookDelivery,\n} from './webhook-endpoint-manager';\n\nexport {\n OperationsOverview,\n type OperationsOverviewProps,\n type OperationsOverviewResponse,\n type OperationsChannelStat,\n} from './operations-overview';\nexport {\n DeliveryLogExplorer,\n type DeliveryLogExplorerProps,\n type DeliveryLogExplorerRow,\n type DeliveryLogExplorerPage,\n} from './delivery-log-explorer';\n\nexport { QuietHoursForm, type QuietHoursFormProps, type QuietHours } from './quiet-hours-form';\nexport { FrequencyCapTable, type FrequencyCapTableProps, type Cap } from './frequency-cap-table';\nexport {\n TenantConfigForm,\n type TenantConfigFormProps,\n type TenantConfig,\n} from './tenant-config-form';\nexport {\n TrackingConfigForm,\n type TrackingConfigFormProps,\n type TrackingConfig,\n} from './tracking-config-form';\n\nexport {\n ApiKeyManager,\n type ApiKeyManagerProps,\n type ApiKey,\n type ApiKeyCreateResponse,\n} from './api-key-manager';\n\nexport {\n ApplicationRegistryPanel,\n type ApplicationRegistryPanelProps,\n type Application,\n} from './application-registry-panel';\n","import { createContext, useContext, useMemo, type ReactNode } from 'react';\nimport {\n NotificationRealtimeProvider,\n type NotificationRealtimeProviderProps,\n} from './notification-realtime-provider';\n\n/**\n * Resolved notification config shared with every bell / inbox / hook below the\n * provider. A consumer app sets these once; components and hooks read them from\n * context, so the bell dropped into `AppShell`'s `TopBar.actions` scopes to the\n * registered app without prop-drilling `appId` everywhere.\n */\nexport interface NotificationConfig {\n /**\n * The registered application slug this app's notifications are scoped to\n * (must match a row in the engine's application registry). Flows to `?appId=`\n * on list / unread-count / read-all and filters realtime events. Omit on a\n * shell / portal to get the unified cross-app inbox.\n */\n appId?: string;\n /** API path prefix the engine's notification endpoints are mounted on. Default `/notifications`. */\n basePath: string;\n /** Unread-count / feed poll interval in ms when the socket is down. Default 60_000. */\n pollIntervalMs: number;\n}\n\nconst DEFAULT_CONFIG: NotificationConfig = {\n appId: undefined,\n basePath: '/notifications',\n pollIntervalMs: 60_000,\n};\n\nconst NotificationConfigContext = createContext<NotificationConfig>(DEFAULT_CONFIG);\n\n/**\n * Reads the ambient notification config. Returns framework defaults when no\n * `NotificationProvider` is mounted, so components still work with explicit\n * props in isolation (and in tests).\n */\nexport function useNotificationConfig(): NotificationConfig {\n return useContext(NotificationConfigContext);\n}\n\nexport interface NotificationProviderProps\n extends Pick<NotificationRealtimeProviderProps, 'serverUrl' | 'disabled'> {\n /**\n * The consumer app's registered slug — the one thing an app must declare to\n * scope its bell. Omit on a shell / portal for the unified inbox.\n */\n appId?: string;\n /** Endpoint path prefix (through the host BFF). Default `/notifications`. */\n basePath?: string;\n /** Poll interval (ms) used while the realtime socket is unavailable. Default 60_000. */\n pollIntervalMs?: number;\n children: ReactNode;\n}\n\n/**\n * Single registration point for notifications. Wrap the app (above `AppShell`)\n * once:\n *\n * ```tsx\n * <NotificationProvider appId=\"delivery-hub\">\n * <AppShell topBar={{ actions: <NotificationBell /> }}>…</AppShell>\n * </NotificationProvider>\n * ```\n *\n * It opens the shared realtime socket (app-filtered) and publishes `appId` /\n * `basePath` / `pollIntervalMs` to every notification component and hook below.\n */\nexport function NotificationProvider({\n appId,\n basePath = '/notifications',\n pollIntervalMs = 60_000,\n serverUrl,\n disabled,\n children,\n}: NotificationProviderProps) {\n const config = useMemo<NotificationConfig>(\n () => ({ appId, basePath, pollIntervalMs }),\n [appId, basePath, pollIntervalMs],\n );\n\n return (\n <NotificationConfigContext.Provider value={config}>\n <NotificationRealtimeProvider appId={appId} serverUrl={serverUrl} disabled={disabled}>\n {children}\n </NotificationRealtimeProvider>\n </NotificationConfigContext.Provider>\n );\n}\n","import { createContext, useContext, useEffect, useRef, useState, type ReactNode } from 'react';\nimport { useQueryClient } from '@tanstack/react-query';\nimport { io, type Socket } from 'socket.io-client';\n\nexport type RealtimeStatus = 'connected' | 'reconnecting' | 'disconnected' | 'disabled';\n\ninterface RealtimeContextValue {\n socket: Socket | null;\n status: RealtimeStatus;\n}\n\nconst RealtimeContext = createContext<RealtimeContextValue>({ socket: null, status: 'disabled' });\n\nexport interface NotificationRealtimeProviderProps {\n /** Socket.IO server base URL — defaults to current origin (BFF proxy). */\n serverUrl?: string;\n /** Disable WebSocket (falls back to polling). Default: false. */\n disabled?: boolean;\n /**\n * Scope realtime invalidation to a producing app (SPEC-application-scoping).\n * When set, `notification:new` events for other apps are ignored; events for\n * this app or system-wide (`appId: null`) still refresh the feed/badge. Omit\n * for a portal that reacts to every app's events.\n */\n appId?: string;\n children: ReactNode;\n className?: string;\n}\n\n/**\n * Mounts a single shared Socket.IO connection to the engine's `/realtime`\n * namespace using only the BFF httpOnly session cookie (`withCredentials`).\n * On `notification:new` / `unread-count:changed` it invalidates the relevant\n * TanStack Query keys (leading-edge debounced over a 200 ms window) so existing\n * fetch logic is reused rather than patching caches. Exposes connection status\n * via context so hooks can switch to REST polling when the socket is down.\n */\nexport function NotificationRealtimeProvider({\n serverUrl = '',\n disabled = false,\n appId,\n children,\n}: NotificationRealtimeProviderProps) {\n const queryClient = useQueryClient();\n const [socket, setSocket] = useState<Socket | null>(null);\n const [status, setStatus] = useState<RealtimeStatus>(disabled ? 'disabled' : 'disconnected');\n const invalidateTimers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());\n\n useEffect(() => {\n if (disabled) {\n setStatus('disabled');\n return;\n }\n\n const debounceInvalidate = (key: readonly unknown[]) => {\n const cacheKey = JSON.stringify(key);\n if (invalidateTimers.current.has(cacheKey)) return; // leading-edge: ignore within window\n void queryClient.invalidateQueries({ queryKey: key as unknown[] });\n const timer = setTimeout(() => invalidateTimers.current.delete(cacheKey), 200);\n invalidateTimers.current.set(cacheKey, timer);\n };\n\n const s = io(`${serverUrl}/realtime`, {\n withCredentials: true,\n transports: ['websocket'],\n reconnectionDelay: 1_000,\n reconnectionDelayMax: 30_000,\n randomizationFactor: 0.5,\n });\n setSocket(s);\n\n s.on('connect', () => {\n setStatus('connected');\n // Full invalidation covers any gap during the disconnect window.\n void queryClient.invalidateQueries({ queryKey: ['notifications'] });\n });\n\n s.on('notification:new', (payload?: { appId?: string | null }) => {\n // App-scoped provider: ignore events for other apps. A system-wide event\n // (appId null/absent) always refreshes; an event for THIS app refreshes.\n const eventAppId = payload?.appId ?? null;\n if (appId && eventAppId && eventAppId !== appId) return;\n debounceInvalidate(['notifications']);\n debounceInvalidate(['notifications', 'unread-count']);\n });\n\n s.on('unread-count:changed', () => {\n debounceInvalidate(['notifications', 'unread-count']);\n });\n\n s.io.on('reconnect_attempt', () => setStatus('reconnecting'));\n\n s.on('disconnect', (reason: string) => {\n // Server-initiated disconnect (logout): auth is gone — do not reconnect.\n if (reason === 'io server disconnect') {\n s.io.opts.reconnection = false;\n setStatus('disabled');\n return;\n }\n setStatus('disconnected');\n });\n\n s.on('connect_error', () => setStatus('disconnected'));\n\n const timers = invalidateTimers.current;\n return () => {\n for (const t of timers.values()) clearTimeout(t);\n timers.clear();\n s.disconnect();\n setSocket(null);\n setStatus('disconnected');\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [disabled, serverUrl, appId]);\n\n return (\n <RealtimeContext.Provider value={{ socket, status }}>{children}</RealtimeContext.Provider>\n );\n}\n\nexport function useRealtimeContext(): RealtimeContextValue {\n return useContext(RealtimeContext);\n}\n","import { useEffect, useMemo, useState } from 'react';\nimport { useApiQuery, useApiMutation } from '@quanticjs/react-query';\nimport { useToast, cn } from '@quanticjs/react-ui';\n\nexport type NotificationChannel = 'inapp' | 'email';\nexport type DigestPeriod = 'none' | 'hourly' | 'daily';\n\nexport interface NotificationPreferenceDto {\n channel: NotificationChannel;\n type: string;\n enabled: boolean;\n digest: DigestPeriod;\n}\n\nexport interface NotificationPreferencesProps {\n /** API path prefix the engine's preference endpoints are mounted on (through the host app's BFF). */\n basePath?: string;\n /** Optional friendly labels per type key; unknown keys fall back to a derived label. */\n typeLabels?: Record<string, string>;\n className?: string;\n}\n\ninterface RowState {\n type: string;\n inappEnabled: boolean;\n emailEnabled: boolean;\n digest: DigestPeriod;\n}\n\nfunction deriveLabel(type: string): string {\n const stripped = type.replace(/^wfl_/, '').replace(/_/g, ' ');\n return stripped.charAt(0).toUpperCase() + stripped.slice(1);\n}\n\nfunction toRows(prefs: NotificationPreferenceDto[]): RowState[] {\n const byType = new Map<string, RowState>();\n for (const pref of prefs) {\n const row = byType.get(pref.type) ?? {\n type: pref.type,\n inappEnabled: true,\n emailEnabled: true,\n digest: 'none' as DigestPeriod,\n };\n if (pref.channel === 'inapp') {\n row.inappEnabled = pref.enabled;\n } else {\n row.emailEnabled = pref.enabled;\n row.digest = pref.digest;\n }\n byType.set(pref.type, row);\n }\n return [...byType.values()];\n}\n\nfunction toEntries(rows: RowState[]): Array<{\n channel: NotificationChannel;\n type: string;\n enabled: boolean;\n digest?: DigestPeriod;\n}> {\n return rows.flatMap((row) => [\n { channel: 'inapp' as const, type: row.type, enabled: row.inappEnabled },\n { channel: 'email' as const, type: row.type, enabled: row.emailEnabled, digest: row.digest },\n ]);\n}\n\n/**\n * Type × channel preference matrix with per-type email digest selection.\n * Embeddable in any app fronting the QuanticJS notification engine — the\n * host wraps it in its own page chrome and providers (QuanticProvider,\n * QuanticQueryProvider, ToastProvider).\n */\nexport function NotificationPreferences({\n basePath = '/notifications',\n typeLabels,\n className,\n}: NotificationPreferencesProps) {\n const toast = useToast();\n const { data, isLoading, isError, refetch } = useApiQuery<NotificationPreferenceDto[]>(\n ['notifications', 'preferences'],\n (client) => client.get(`${basePath}/preferences`),\n );\n\n const serverRows = useMemo(() => (data ? toRows(data) : []), [data]);\n const [rows, setRows] = useState<RowState[]>(serverRows);\n useEffect(() => setRows(serverRows), [serverRows]);\n\n const mutation = useApiMutation<\n NotificationPreferenceDto[],\n ReturnType<typeof toEntries>\n >((client, entries) => client.put(`${basePath}/preferences`, { entries }), {\n invalidates: [['notifications', 'preferences']],\n onSuccess: () => {\n toast.success('Notification preferences saved');\n },\n onError: (error) => {\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n },\n });\n\n const update = (type: string, patch: Partial<RowState>) => {\n setRows((prev) => prev.map((row) => (row.type === type ? { ...row, ...patch } : row)));\n };\n\n if (isLoading) {\n return (\n <div role=\"status\" aria-label=\"Loading notification preferences\" className={cn('space-y-2', className)}>\n {[0, 1, 2, 3].map((i) => (\n <div key={i} className=\"h-10 animate-pulse rounded-md bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('rounded-md border border-border p-6 text-center', className)}>\n <p className=\"text-sm text-muted-foreground\">Failed to load notification preferences.</p>\n <button\n type=\"button\"\n onClick={() => refetch()}\n className=\"mt-3 rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n if (rows.length === 0) {\n return (\n <div className={cn('rounded-md border border-border p-6 text-center', className)}>\n <p className=\"text-sm text-muted-foreground\">No notification preferences available.</p>\n </div>\n );\n }\n\n return (\n <div className={cn('space-y-4', className)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Notification\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n In-app\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Email\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Email digest\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => {\n const label = typeLabels?.[row.type] ?? deriveLabel(row.type);\n return (\n <tr key={row.type} className=\"border-b border-border\">\n <td className=\"py-3 pe-4\">{label}</td>\n <td className=\"px-4 py-3\">\n <input\n type=\"checkbox\"\n aria-label={`${label} in-app notifications`}\n checked={row.inappEnabled}\n onChange={(e) => update(row.type, { inappEnabled: e.target.checked })}\n />\n </td>\n <td className=\"px-4 py-3\">\n <input\n type=\"checkbox\"\n aria-label={`${label} email notifications`}\n checked={row.emailEnabled}\n onChange={(e) => update(row.type, { emailEnabled: e.target.checked })}\n />\n </td>\n <td className=\"px-4 py-3\">\n <select\n aria-label={`${label} email digest`}\n value={row.digest}\n disabled={!row.emailEnabled}\n onChange={(e) => update(row.type, { digest: e.target.value as DigestPeriod })}\n className=\"rounded-md border border-border bg-background px-2 py-1\"\n >\n <option value=\"none\">Immediately</option>\n <option value=\"hourly\">Hourly digest</option>\n <option value=\"daily\">Daily digest</option>\n </select>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n <button\n type=\"button\"\n onClick={() => mutation.mutate(toEntries(rows))}\n disabled={mutation.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground disabled:opacity-50\"\n >\n {mutation.isPending ? 'Saving…' : 'Save preferences'}\n </button>\n </div>\n );\n}\n","import { useApiQuery } from '@quanticjs/react-query';\nimport { useRealtimeContext } from './notification-realtime-provider';\nimport { useNotificationConfig } from './notification-provider';\n\nexport interface UseUnreadCountOptions {\n /** API path prefix the engine's notification endpoints are mounted on. */\n basePath?: string;\n /** Polling interval in ms when the socket is unavailable. Default: 60_000. */\n pollIntervalMs?: number;\n /** Scope the count to a producing app (its rows + system-wide). Omit for all. */\n appId?: string;\n}\n\n/**\n * Reads the unread badge count. When the realtime socket is connected, the\n * count is kept fresh by socket-driven cache invalidation and polling is\n * disabled; when the socket is down it transparently falls back to REST polling\n * at `pollIntervalMs`. Any option omitted falls back to the ambient\n * `NotificationProvider` config (where the consumer registered its `appId`).\n */\nexport function useUnreadCount(options: UseUnreadCountOptions = {}) {\n const config = useNotificationConfig();\n const basePath = options.basePath ?? config.basePath;\n const pollIntervalMs = options.pollIntervalMs ?? config.pollIntervalMs;\n const appId = options.appId ?? config.appId;\n const { status } = useRealtimeContext();\n const socketUp = status === 'connected';\n const key = appId\n ? ['notifications', 'unread-count', appId]\n : ['notifications', 'unread-count'];\n const url = appId\n ? `${basePath}/unread-count?appId=${encodeURIComponent(appId)}`\n : `${basePath}/unread-count`;\n\n return useApiQuery<{ count: number }>(key, (client) => client.get(url), {\n refetchInterval: socketUp ? false : pollIntervalMs,\n staleTime: socketUp ? Infinity : pollIntervalMs / 2,\n });\n}\n","import { useEffect } from 'react';\nimport { useApiQuery, useApiMutation } from '@quanticjs/react-query';\nimport { useToast } from '@quanticjs/react-ui';\nimport { useRealtimeContext } from './notification-realtime-provider';\nimport { useNotificationConfig } from './notification-provider';\n\nexport interface NotificationFeedItem {\n id: string;\n userId: string;\n type: string;\n title: string;\n body: string;\n metadata: Record<string, unknown> | null;\n isRead: boolean;\n createdAt: string;\n}\n\nexport interface PaginatedFeed {\n items: NotificationFeedItem[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface UseNotificationFeedOptions {\n basePath?: string;\n /** Polling interval in ms when the socket is unavailable. Default: 60_000. */\n pollIntervalMs?: number;\n limit?: number;\n /**\n * Scope the feed to a producing application (SPEC-application-scoping). When\n * set, every request carries `?appId=` so the bell shows only that app's rows\n * plus system-wide notifications. Omit for the unified portal view.\n */\n appId?: string;\n}\n\n/**\n * Fetches the notification feed (list) and exposes mark-read / mark-all-read\n * mutations. Falls back to REST polling when the socket is down. On socket\n * reconnect it emits `backfill:request` with the newest known timestamp so any\n * notifications created during the disconnect gap are pulled in.\n */\nexport function useNotificationFeed(options: UseNotificationFeedOptions = {}) {\n const config = useNotificationConfig();\n const basePath = options.basePath ?? config.basePath;\n const pollIntervalMs = options.pollIntervalMs ?? config.pollIntervalMs;\n const appId = options.appId ?? config.appId;\n const limit = options.limit ?? 50;\n const { socket, status } = useRealtimeContext();\n const socketUp = status === 'connected';\n const toast = useToast();\n const appParam = appId ? `&appId=${encodeURIComponent(appId)}` : '';\n const readAllPath = appId ? `${basePath}/read-all?appId=${encodeURIComponent(appId)}` : `${basePath}/read-all`;\n\n // The engine list endpoint reads `pageSize` (not `limit`); send pageSize so\n // the requested page size is actually honored.\n const query = useApiQuery<PaginatedFeed>(\n ['notifications', { limit, appId }],\n (client) => client.get(`${basePath}?page=1&pageSize=${limit}${appParam}`),\n {\n refetchInterval: socketUp ? false : pollIntervalMs,\n staleTime: socketUp ? Infinity : pollIntervalMs / 2,\n },\n );\n\n // Backfill on (re)connect — ask the server for anything created since the\n // newest item we currently hold.\n useEffect(() => {\n if (!socket) return;\n const onConnect = () => {\n const newest = query.data?.items?.[0]?.createdAt ?? new Date(0).toISOString();\n socket.emit('backfill:request', { since: newest });\n };\n socket.on('connect', onConnect);\n return () => {\n socket.off('connect', onConnect);\n };\n }, [socket, query.data]);\n\n const markRead = useApiMutation<void, string>(\n (client, id) => client.post(`${basePath}/${id}/read`, {}),\n {\n invalidates: [['notifications'], ['notifications', 'unread-count']],\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n const markAllRead = useApiMutation<void, void>(\n (client) => client.post(readAllPath, {}),\n {\n invalidates: [['notifications'], ['notifications', 'unread-count']],\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n return { ...query, markRead, markAllRead };\n}\n","import { cn } from '@quanticjs/react-ui';\nimport { useUnreadCount } from './use-unread-count';\n\nexport interface NotificationBellProps {\n basePath?: string;\n pollIntervalMs?: number;\n /** Scope the unread badge to a producing app (its rows + system-wide). */\n appId?: string;\n /** Invoked when the bell is activated (e.g. to open the inbox panel). */\n onClick?: () => void;\n className?: string;\n}\n\n/**\n * Accessible notification bell with an unread badge. The badge is hidden at\n * zero; the wrapper exposes a live `role=\"status\"` with an `aria-label`\n * describing the count so assistive tech announces changes.\n */\nexport function NotificationBell({\n basePath,\n pollIntervalMs,\n appId,\n onClick,\n className,\n}: NotificationBellProps) {\n // Omitted props fall back to the ambient NotificationProvider config.\n const { data } = useUnreadCount({ basePath, pollIntervalMs, appId });\n const count = data?.count ?? 0;\n const label = count === 0 ? 'No unread notifications' : `${count} unread notifications`;\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label=\"Notifications\"\n className={cn(\n 'relative inline-flex h-10 w-10 items-center justify-center rounded-full text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring',\n className,\n )}\n >\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n className=\"h-5 w-5\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M15 17h5l-1.4-1.4A2 2 0 0118 14.2V11a6 6 0 10-12 0v3.2a2 2 0 01-.6 1.4L4 17h5m6 0a3 3 0 11-6 0m6 0H9\"\n />\n </svg>\n <span role=\"status\" aria-label={label} className=\"sr-only\">\n {label}\n </span>\n {count > 0 && (\n <span\n aria-hidden=\"true\"\n className=\"absolute -end-0.5 -top-0.5 inline-flex min-w-5 items-center justify-center rounded-full bg-coral px-1.5 text-xs font-semibold text-coral-foreground ring-2 ring-background\"\n >\n {count > 99 ? '99+' : count}\n </span>\n )}\n </button>\n );\n}\n","import type { ReactNode } from 'react';\nimport { Button, Card, EmptyState, Skeleton, cn } from '@quanticjs/react-ui';\nimport { useNotificationFeed, type NotificationFeedItem } from './use-notification-feed';\n\nexport interface NotificationInboxProps {\n basePath?: string;\n pollIntervalMs?: number;\n /** Scope the inbox to a producing app (its rows + system-wide). Omit for all. */\n appId?: string;\n className?: string;\n}\n\n/**\n * Notification inbox panel: renders the feed with loading / error / empty\n * states, marks individual items read on click, and offers a \"Mark all read\"\n * action. All reads invalidate `['notifications']` and\n * `['notifications','unread-count']` so the bell badge converges.\n */\nexport function NotificationInbox({\n basePath,\n pollIntervalMs,\n appId,\n className,\n}: NotificationInboxProps) {\n // Omitted props fall back to the ambient NotificationProvider config.\n const { data, isLoading, isError, refetch, markRead, markAllRead } = useNotificationFeed({\n basePath,\n pollIntervalMs,\n appId,\n });\n\n if (isLoading) {\n return (\n <div role=\"status\" aria-label=\"Loading notifications\" className={cn(className)}>\n <span className=\"sr-only\">Loading notifications</span>\n <Card aria-hidden=\"true\">\n <InboxHeader />\n <ul className=\"divide-y divide-border\">\n {[0, 1, 2, 3].map((i) => (\n <li key={i} className=\"flex items-start gap-3 px-4 py-3.5\">\n <Skeleton className=\"mt-1 h-2 w-2 rounded-full\" />\n <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n <Skeleton className=\"h-3.5 w-2/3\" />\n <Skeleton className=\"h-3 w-1/2\" />\n </div>\n </li>\n ))}\n </ul>\n </Card>\n </div>\n );\n }\n\n if (isError) {\n return (\n <Card className={className}>\n <InboxHeader />\n <div className=\"flex flex-col items-center gap-3 px-6 py-12 text-center\">\n <span\n aria-hidden=\"true\"\n className=\"grid size-12 place-items-center rounded-full bg-destructive/10 text-destructive [&_svg]:size-6\"\n >\n <AlertIcon />\n </span>\n <div className=\"flex flex-col gap-1\">\n <p className=\"text-sm font-medium text-foreground\">Failed to load notifications</p>\n <p className=\"text-sm text-muted-foreground\">\n Something went wrong while loading your inbox.\n </p>\n </div>\n <Button type=\"button\" onClick={() => void refetch()}>\n Try again\n </Button>\n </div>\n </Card>\n );\n }\n\n const items = data?.items ?? [];\n\n if (items.length === 0) {\n return (\n <Card className={className}>\n <InboxHeader />\n <EmptyState\n icon={<BellOffIcon />}\n title=\"No notifications yet\"\n description=\"New alerts and updates will appear here.\"\n />\n </Card>\n );\n }\n\n return (\n <Card role=\"region\" aria-label=\"Notifications\" className={className}>\n <InboxHeader\n action={\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => markAllRead.mutate()}\n disabled={markAllRead.isPending}\n >\n Mark all read\n </Button>\n }\n />\n <ul className=\"divide-y divide-border\">\n {items.map((item) => (\n <InboxRow key={item.id} item={item} onMarkRead={() => markRead.mutate(item.id)} />\n ))}\n </ul>\n </Card>\n );\n}\n\n/** Card header strip: title plus an optional right-aligned action. */\nfunction InboxHeader({ action }: { action?: ReactNode }) {\n return (\n <div className=\"flex items-center justify-between gap-2 border-b border-border px-4 py-3\">\n <h2 className=\"text-sm font-semibold text-foreground\">Notifications</h2>\n {action}\n </div>\n );\n}\n\nfunction InboxRow({\n item,\n onMarkRead,\n}: {\n item: NotificationFeedItem;\n onMarkRead: () => void;\n}) {\n return (\n <li>\n <button\n type=\"button\"\n onClick={onMarkRead}\n aria-label={`${item.title}${item.isRead ? '' : ' (unread)'}`}\n className=\"flex w-full items-start gap-3 px-4 py-3.5 text-start transition-colors hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <span aria-hidden=\"true\" className=\"mt-1.5 flex size-2 shrink-0 items-center justify-center\">\n {!item.isRead && <span className=\"size-2 rounded-full bg-coral\" />}\n </span>\n <span className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <span\n className={cn(\n 'truncate text-sm',\n item.isRead ? 'font-normal text-muted-foreground' : 'font-semibold text-foreground',\n )}\n >\n {item.title}\n </span>\n {item.body && (\n <span className=\"truncate text-xs text-muted-foreground\">{item.body}</span>\n )}\n </span>\n </button>\n </li>\n );\n}\n\n/* Decorative inline icons — `lucide-react` is not a dependency of this package. */\n\nfunction AlertIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z\" />\n <line x1=\"12\" x2=\"12\" y1=\"9\" y2=\"13\" />\n <line x1=\"12\" x2=\"12.01\" y1=\"17\" y2=\"17\" />\n </svg>\n );\n}\n\nfunction BellOffIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M8.7 3A6 6 0 0 1 18 8a21.3 21.3 0 0 0 .6 5\" />\n <path d=\"M17 17H3s3-2 3-9a4.67 4.67 0 0 1 .3-1.7\" />\n <path d=\"M10.3 21a1.94 1.94 0 0 0 3.4 0\" />\n <line x1=\"2\" x2=\"22\" y1=\"2\" y2=\"22\" />\n </svg>\n );\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { cn, useExitAnimation, useFocusTrap } from '@quanticjs/react-ui';\nimport { useUnreadCount } from './use-unread-count';\nimport { NotificationInbox } from './notification-inbox';\n\nexport interface NotificationCenterProps {\n /**\n * Registered app slug to scope to. Omitted → falls back to the ambient\n * `NotificationProvider` config (omit there too, on a shell/portal, for the\n * unified inbox).\n */\n appId?: string;\n basePath?: string;\n pollIntervalMs?: number;\n className?: string;\n /** Class applied to the popover panel. */\n panelClassName?: string;\n}\n\nfunction BellIcon() {\n return (\n <svg\n aria-hidden\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"h-5 w-5\"\n >\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\" />\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\" />\n </svg>\n );\n}\n\n/**\n * Drop-in notification bell with an integrated inbox popover — badge **and**\n * dropdown in one component (the all-in-one shape consumer shells expect). Wrap\n * the app in `<NotificationProvider appId=…>` (or pass `appId` here) so it scopes\n * to the registered app; omit `appId` on a shell/portal for the unified inbox.\n *\n * Focus moves into the panel on open and returns to the trigger on close (the\n * focus trap keys off `open`, not the exit hook's `mounted`, so keyboard users\n * are never trapped during the exit animation).\n *\n * For a bare badge button you compose yourself (custom dropdown), use\n * `NotificationBell` + `NotificationInbox` directly instead.\n */\nexport function NotificationCenter({\n appId,\n basePath,\n pollIntervalMs,\n className,\n panelClassName,\n}: NotificationCenterProps) {\n const [open, setOpen] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const { data } = useUnreadCount({ appId, basePath, pollIntervalMs });\n\n const unreadCount = data?.count ?? 0;\n const badge = unreadCount > 99 ? '99+' : String(unreadCount);\n const label =\n unreadCount === 0 ? 'No unread notifications' : `${unreadCount} unread notifications`;\n\n const close = useCallback(() => setOpen(false), []);\n\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') close();\n };\n const onPointer = (e: MouseEvent) => {\n const c = containerRef.current;\n if (c && e.target instanceof Node && !c.contains(e.target)) close();\n };\n document.addEventListener('keydown', onKey);\n document.addEventListener('mousedown', onPointer);\n return () => {\n document.removeEventListener('keydown', onKey);\n document.removeEventListener('mousedown', onPointer);\n };\n }, [open, close]);\n\n useFocusTrap(panelRef, open);\n const panelExit = useExitAnimation(open);\n\n return (\n <div ref={containerRef} className={cn('relative inline-block', className)}>\n <button\n type=\"button\"\n aria-label={label}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n onClick={() => setOpen((p) => !p)}\n className=\"relative inline-flex h-10 w-10 items-center justify-center rounded-full text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <BellIcon />\n <span role=\"status\" className=\"sr-only\">\n {label}\n </span>\n {unreadCount > 0 && (\n <span\n aria-hidden\n className=\"absolute -end-0.5 -top-0.5 inline-flex min-w-5 items-center justify-center rounded-full bg-coral px-1.5 text-xs font-semibold text-coral-foreground ring-2 ring-background\"\n >\n {badge}\n </span>\n )}\n </button>\n\n {panelExit.mounted && (\n <div\n ref={panelRef}\n role=\"dialog\"\n aria-label=\"Notifications\"\n tabIndex={-1}\n data-state={panelExit.state}\n onAnimationEnd={panelExit.onAnimationEnd}\n className={cn(\n 'absolute end-0 z-(--z-popover) mt-2 w-96 overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-raised',\n panelExit.state === 'open'\n ? 'animate-pop-in'\n : 'animate-pop-out [animation-fill-mode:forwards]',\n panelClassName,\n )}\n >\n <NotificationInbox\n appId={appId}\n basePath={basePath}\n pollIntervalMs={pollIntervalMs}\n className=\"max-h-[28rem] overflow-y-auto\"\n />\n </div>\n )}\n </div>\n );\n}\n","import { useState } from 'react';\nimport { cn } from '@quanticjs/react-ui';\nimport { useDeliveryAnalytics } from './use-delivery-analytics';\nimport { useFunnelStats } from './use-funnel-stats';\nimport { useDeliveryTypes } from './use-delivery-types';\nimport { FunnelStats } from './funnel-stats';\nimport { TrendChart } from './trend-chart';\nimport { TypeTable } from './type-table';\n\nexport interface DeliveryAnalyticsPageProps {\n basePath?: string;\n organizationId?: string;\n className?: string;\n}\n\nconst DEFAULT_FROM = '2026-06-01';\nconst DEFAULT_TO = '2026-06-30';\n\nconst CHANNELS = ['', 'email', 'inapp', 'push', 'sms'] as const;\n\n/**\n * Admin delivery-analytics dashboard: channel/date-range filter, funnel stat\n * cards, per-day trend chart, and a per-type table. Implements the standard\n * loading / error / empty data-list states.\n */\nexport function DeliveryAnalyticsPage({\n basePath = '/analytics/notifications',\n organizationId,\n className,\n}: DeliveryAnalyticsPageProps) {\n const [channel, setChannel] = useState<string>('');\n const [from, setFrom] = useState<string>(DEFAULT_FROM);\n const [to, setTo] = useState<string>(DEFAULT_TO);\n\n const filters = { from, to, channel: channel || undefined, organizationId, basePath };\n const summary = useDeliveryAnalytics(filters);\n const funnel = useFunnelStats(filters);\n const types = useDeliveryTypes({ from, to, organizationId, basePath });\n\n const isLoading = summary.isLoading || funnel.isLoading || types.isLoading;\n const isError = summary.isError || funnel.isError || types.isError;\n\n return (\n <main className={cn('flex flex-col gap-6 p-4 sm:p-6', className)}>\n <header className=\"flex flex-col gap-1\">\n <h1 className=\"text-xl font-semibold text-foreground\">Delivery Analytics</h1>\n <p className=\"text-sm text-muted-foreground\">\n Cross-channel send, open, and click performance.\n </p>\n </header>\n\n <div className=\"flex flex-wrap items-end gap-3\">\n <label className=\"flex flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">Channel</span>\n <select\n value={channel}\n onChange={(e) => setChannel(e.target.value)}\n className=\"rounded border border-border bg-background px-2 py-1.5 text-foreground\"\n >\n {CHANNELS.map((c) => (\n <option key={c || 'all'} value={c}>\n {c === '' ? 'All channels' : c}\n </option>\n ))}\n </select>\n </label>\n <label className=\"flex flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">From</span>\n <input\n type=\"date\"\n value={from}\n onChange={(e) => setFrom(e.target.value)}\n className=\"rounded border border-border bg-background px-2 py-1.5 text-foreground\"\n />\n </label>\n <label className=\"flex flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">To</span>\n <input\n type=\"date\"\n value={to}\n onChange={(e) => setTo(e.target.value)}\n className=\"rounded border border-border bg-background px-2 py-1.5 text-foreground\"\n />\n </label>\n </div>\n\n {isLoading ? (\n <div role=\"status\" aria-label=\"Loading delivery analytics\" className=\"flex flex-col gap-3\">\n <span className=\"sr-only\">Loading delivery analytics</span>\n <div aria-hidden=\"true\" className=\"h-24 animate-pulse rounded bg-muted\" />\n <div aria-hidden=\"true\" className=\"h-72 animate-pulse rounded bg-muted\" />\n </div>\n ) : isError ? (\n <div className=\"flex flex-col items-start gap-3\">\n <p className=\"text-sm text-foreground\">Failed to load delivery analytics</p>\n <button\n type=\"button\"\n onClick={() => {\n void summary.refetch();\n void funnel.refetch();\n void types.refetch();\n }}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n ) : (summary.data?.length ?? 0) === 0 ? (\n <p className=\"rounded border border-border p-6 text-center text-sm text-muted-foreground\">\n No delivery data for the selected range\n </p>\n ) : (\n <div className=\"flex flex-col gap-6\">\n {funnel.data ? <FunnelStats funnel={funnel.data} /> : null}\n <section aria-label=\"Delivery trend\" className=\"rounded-lg border border-border p-4\">\n <h2 className=\"mb-3 text-sm font-semibold text-foreground\">Trend</h2>\n <TrendChart data={summary.data ?? []} />\n </section>\n <section aria-label=\"Delivery by type\" className=\"rounded-lg border border-border p-4\">\n <h2 className=\"mb-3 text-sm font-semibold text-foreground\">By type</h2>\n <TypeTable rows={types.data ?? []} />\n </section>\n </div>\n )}\n </main>\n );\n}\n","import { useApiQuery } from '@quanticjs/react-query';\n\nexport interface DailyDeliveryStats {\n day: string;\n sends: number;\n delivered: number;\n opened: number;\n clicked: number;\n bounced: number;\n failed: number;\n deliveryRate: number;\n openRate: number;\n clickRate: number;\n bounceRate: number;\n}\n\nexport interface DeliveryAnalyticsFilters {\n from: string;\n to: string;\n channel?: string;\n type?: string;\n organizationId?: string;\n}\n\nexport interface UseDeliveryAnalyticsOptions extends DeliveryAnalyticsFilters {\n basePath?: string;\n}\n\nfunction toQuery(filters: DeliveryAnalyticsFilters): string {\n const params = new URLSearchParams();\n params.set('from', filters.from);\n params.set('to', filters.to);\n if (filters.channel) params.set('channel', filters.channel);\n if (filters.type) params.set('type', filters.type);\n if (filters.organizationId) params.set('organizationId', filters.organizationId);\n return params.toString();\n}\n\n/** Per-day delivery summary stats for the selected filters. */\nexport function useDeliveryAnalytics({\n basePath = '/analytics/notifications',\n ...filters\n}: UseDeliveryAnalyticsOptions) {\n return useApiQuery<DailyDeliveryStats[]>(\n ['delivery-analytics', 'summary', filters],\n (client) => client.get(`${basePath}/summary?${toQuery(filters)}`),\n );\n}\n\nexport { toQuery as buildDeliveryAnalyticsQuery };\n","import { useApiQuery } from '@quanticjs/react-query';\nimport { buildDeliveryAnalyticsQuery, type DeliveryAnalyticsFilters } from './use-delivery-analytics';\n\nexport interface DeliveryFunnel {\n sends: number;\n delivered: number;\n opened: number;\n clicked: number;\n bounced: number;\n failed: number;\n openRate: number;\n clickRate: number;\n bounceRate: number;\n deliveryRate: number;\n}\n\nexport interface UseFunnelStatsOptions extends DeliveryAnalyticsFilters {\n basePath?: string;\n}\n\n/** Single aggregated funnel over the selected date range. */\nexport function useFunnelStats({\n basePath = '/analytics/notifications',\n ...filters\n}: UseFunnelStatsOptions) {\n return useApiQuery<DeliveryFunnel>(\n ['delivery-analytics', 'funnel', filters],\n (client) => client.get(`${basePath}/funnel?${buildDeliveryAnalyticsQuery(filters)}`),\n );\n}\n","import { useApiQuery } from '@quanticjs/react-query';\nimport type { DeliveryAnalyticsFilters } from './use-delivery-analytics';\n\nexport interface DeliveryTypeBreakdown {\n type: string;\n sends: number;\n delivered: number;\n opened: number;\n clicked: number;\n bounced: number;\n failed: number;\n openRate: number;\n clickRate: number;\n}\n\nexport interface UseDeliveryTypesOptions\n extends Pick<DeliveryAnalyticsFilters, 'from' | 'to' | 'organizationId'> {\n basePath?: string;\n}\n\n/** Per-type breakdown sorted by send volume descending. */\nexport function useDeliveryTypes({\n basePath = '/analytics/notifications',\n ...filters\n}: UseDeliveryTypesOptions) {\n const params = new URLSearchParams();\n params.set('from', filters.from);\n params.set('to', filters.to);\n if (filters.organizationId) params.set('organizationId', filters.organizationId);\n\n return useApiQuery<DeliveryTypeBreakdown[]>(\n ['delivery-analytics', 'types', filters],\n (client) => client.get(`${basePath}/types?${params.toString()}`),\n );\n}\n","import { cn } from '@quanticjs/react-ui';\nimport type { DeliveryFunnel } from './use-funnel-stats';\n\nexport interface FunnelStatsProps {\n funnel: DeliveryFunnel;\n className?: string;\n}\n\nconst pct = (n: number) => `${(n * 100).toFixed(1)}%`;\n\n/** Funnel stat cards: sends → delivered → opened → clicked, plus key rates. */\nexport function FunnelStats({ funnel, className }: FunnelStatsProps) {\n const cards: Array<{ label: string; value: string }> = [\n { label: 'Sends', value: String(funnel.sends) },\n { label: 'Delivered', value: String(funnel.delivered) },\n { label: 'Opened', value: String(funnel.opened) },\n { label: 'Clicked', value: String(funnel.clicked) },\n { label: 'Open rate', value: pct(funnel.openRate) },\n { label: 'Click rate', value: pct(funnel.clickRate) },\n { label: 'Bounce rate', value: pct(funnel.bounceRate) },\n { label: 'Delivery rate', value: pct(funnel.deliveryRate) },\n ];\n\n return (\n <ul className={cn('grid grid-cols-2 gap-3 sm:grid-cols-4', className)} aria-label=\"Delivery funnel\">\n {cards.map((c) => (\n <li\n key={c.label}\n className=\"flex flex-col gap-1 rounded-lg border border-border bg-card p-4\"\n >\n <span className=\"text-xs font-medium text-muted-foreground\">{c.label}</span>\n <span className=\"text-2xl font-semibold text-foreground\">{c.value}</span>\n </li>\n ))}\n </ul>\n );\n}\n","import { cn } from '@quanticjs/react-ui';\nimport {\n CartesianGrid,\n Line,\n LineChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from 'recharts';\nimport type { DailyDeliveryStats } from './use-delivery-analytics';\n\nexport interface TrendChartProps {\n data: DailyDeliveryStats[];\n className?: string;\n}\n\n/**\n * Per-day delivery trend line chart (sends / delivered / opened / clicked).\n * Route-split-friendly — recharts is only loaded with the analytics page.\n */\nexport function TrendChart({ data, className }: TrendChartProps) {\n return (\n <div className={cn('h-72 w-full', className)} role=\"img\" aria-label=\"Delivery trend over time\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <LineChart data={data} margin={{ top: 8, right: 16, bottom: 8, left: 0 }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke=\"var(--border)\" />\n <XAxis dataKey=\"day\" stroke=\"var(--muted-foreground)\" fontSize={12} />\n <YAxis stroke=\"var(--muted-foreground)\" fontSize={12} allowDecimals={false} />\n <Tooltip />\n <Line type=\"monotone\" dataKey=\"sends\" stroke=\"var(--primary)\" dot={false} />\n <Line type=\"monotone\" dataKey=\"delivered\" stroke=\"var(--chart-2, var(--primary))\" dot={false} />\n <Line type=\"monotone\" dataKey=\"opened\" stroke=\"var(--chart-3, var(--primary))\" dot={false} />\n <Line type=\"monotone\" dataKey=\"clicked\" stroke=\"var(--chart-4, var(--primary))\" dot={false} />\n </LineChart>\n </ResponsiveContainer>\n </div>\n );\n}\n","import { cn } from '@quanticjs/react-ui';\nimport type { DeliveryTypeBreakdown } from './use-delivery-types';\n\nexport interface TypeTableProps {\n rows: DeliveryTypeBreakdown[];\n className?: string;\n}\n\nconst pct = (n: number) => `${(n * 100).toFixed(1)}%`;\n\n/** Per-notification-type delivery breakdown, sorted by send volume. */\nexport function TypeTable({ rows, className }: TypeTableProps) {\n return (\n <table className={cn('w-full border-collapse text-sm', className)}>\n <caption className=\"sr-only\">Delivery breakdown by notification type</caption>\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">Type</th>\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">Sends</th>\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">Delivered</th>\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">Open rate</th>\n <th scope=\"col\" className=\"py-2 font-medium\">Click rate</th>\n </tr>\n </thead>\n <tbody>\n {rows.map((r) => (\n <tr key={r.type} className=\"border-b border-border/50\">\n <td className=\"py-2 pe-4 font-medium text-foreground\">{r.type}</td>\n <td className=\"py-2 pe-4 text-foreground\">{r.sends}</td>\n <td className=\"py-2 pe-4 text-foreground\">{r.delivered}</td>\n <td className=\"py-2 pe-4 text-foreground\">{pct(r.openRate)}</td>\n <td className=\"py-2 text-foreground\">{pct(r.clickRate)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n","import { cn } from '@quanticjs/react-ui';\n\nexport type TemplateStatus = 'draft' | 'published' | 'archived' | string;\n\nconst STATUS_STYLES: Record<string, string> = {\n draft: 'bg-muted text-muted-foreground',\n published: 'bg-primary text-primary-foreground',\n archived: 'bg-secondary text-secondary-foreground',\n};\n\n/**\n * Small status pill shared across the template admin components. Falls back to\n * a neutral style for unknown status values. Semantic tokens only — no hex.\n */\nexport function TemplateStatusBadge({\n status,\n className,\n}: {\n status: TemplateStatus;\n className?: string;\n}) {\n const style = STATUS_STYLES[status] ?? 'bg-muted text-muted-foreground';\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize',\n style,\n className,\n )}\n >\n {status}\n </span>\n );\n}\n","import type { ReactNode } from 'react';\nimport { Button, Card, EmptyState, Skeleton, cn } from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\nimport { TemplateStatusBadge, type TemplateStatus } from './template-status-badge';\n\nexport interface TemplateListItem {\n templateId: string;\n locales: string[];\n latestStatus: TemplateStatus;\n versionCount: number;\n}\n\nexport interface TemplateListProps {\n /** API path the template admin endpoints are mounted on (through the BFF). */\n basePath?: string;\n className?: string;\n}\n\n/**\n * Admin data-list of notification templates. Renders the template id, the\n * latest version status, available locales, and version count with full\n * loading / error / empty / happy coverage.\n */\nexport function TemplateList({ basePath = '/api/templates', className }: TemplateListProps) {\n const { data, isLoading, isError, refetch } = useApiQuery<TemplateListItem[]>(\n ['templates', basePath],\n (client) => client.get(basePath),\n );\n\n if (isLoading) {\n return (\n <div role=\"status\" aria-label=\"Loading templates\" className={cn(className)}>\n <span className=\"sr-only\">Loading templates</span>\n <Card aria-hidden=\"true\">\n <ListHeader />\n <ul className=\"divide-y divide-border\">\n {[0, 1, 2, 3, 4].map((i) => (\n <li key={i} className=\"flex flex-col gap-2 px-4 py-3.5\">\n <div className=\"flex items-center gap-2.5\">\n <Skeleton className=\"h-3.5 w-40\" />\n <Skeleton className=\"h-5 w-16 rounded-full\" />\n </div>\n <Skeleton className=\"h-3 w-56\" />\n </li>\n ))}\n </ul>\n </Card>\n </div>\n );\n }\n\n if (isError) {\n return (\n <Card className={className}>\n <ListHeader />\n <div className=\"flex flex-col items-center gap-3 px-6 py-12 text-center\">\n <span\n aria-hidden=\"true\"\n className=\"grid size-12 place-items-center rounded-full bg-destructive/10 text-destructive [&_svg]:size-6\"\n >\n <AlertIcon />\n </span>\n <div className=\"flex flex-col gap-1\">\n <p className=\"text-sm font-medium text-foreground\">Failed to load templates</p>\n <p className=\"text-sm text-muted-foreground\">\n Something went wrong while loading your templates.\n </p>\n </div>\n <Button type=\"button\" onClick={() => void refetch()}>\n Try again\n </Button>\n </div>\n </Card>\n );\n }\n\n const items = data ?? [];\n\n if (items.length === 0) {\n return (\n <Card className={className}>\n <ListHeader />\n <EmptyState\n icon={<FileIcon />}\n title=\"No templates found\"\n description=\"This workspace doesn't have any notification templates yet.\"\n />\n </Card>\n );\n }\n\n return (\n <Card role=\"region\" aria-label=\"Templates\" className={className}>\n <ListHeader count={items.length} />\n <ul className=\"divide-y divide-border\">\n {items.map((item) => (\n <TemplateRow key={item.templateId} item={item} />\n ))}\n </ul>\n </Card>\n );\n}\n\n/** Card header strip: title, a muted subtitle, and an optional count pill. */\nfunction ListHeader({ count }: { count?: number }) {\n return (\n <div className=\"flex items-center justify-between gap-2 border-b border-border px-4 py-3\">\n <div className=\"flex flex-col\">\n <h2 className=\"text-sm font-semibold text-foreground\">Templates</h2>\n <p className=\"text-xs text-muted-foreground\">Read-only view of all notification templates</p>\n </div>\n {count != null && count > 0 && (\n <span className=\"inline-flex items-center rounded-full bg-muted px-2 py-0.5 text-xs font-medium tabular-nums text-muted-foreground\">\n {count} templates\n </span>\n )}\n </div>\n );\n}\n\nfunction TemplateRow({ item }: { item: TemplateListItem }) {\n return (\n <li className=\"flex flex-col gap-1.5 px-4 py-3.5\">\n <div className=\"flex items-center gap-2.5\">\n <span className=\"truncate text-sm font-medium text-foreground\">{item.templateId}</span>\n <TemplateStatusBadge status={item.latestStatus} />\n </div>\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground\">\n <span className=\"tabular-nums\">{item.versionCount} versions</span>\n <span aria-hidden=\"true\" className=\"text-border\">\n ·\n </span>\n <span className=\"flex flex-wrap items-center gap-1\">\n <span>Locales:</span>\n {item.locales.map((locale) => (\n <span\n key={locale}\n className=\"inline-flex items-center rounded bg-muted px-1.5 py-0.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground\"\n >\n {locale}\n </span>\n ))}\n </span>\n </div>\n </li>\n );\n}\n\n/* Decorative inline icons — `lucide-react` is not a dependency of this package. */\n\nfunction AlertIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z\" />\n <line x1=\"12\" x2=\"12\" y1=\"9\" y2=\"13\" />\n <line x1=\"12\" x2=\"12.01\" y1=\"17\" y2=\"17\" />\n </svg>\n );\n}\n\nfunction FileIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\" />\n <path d=\"M14 2v4a2 2 0 0 0 2 2h4\" />\n <path d=\"M10 9H8\" />\n <path d=\"M16 13H8\" />\n <path d=\"M16 17H8\" />\n </svg>\n );\n}\n","import { useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation } from '@quanticjs/react-query';\nimport { TemplateStatusBadge, type TemplateStatus } from './template-status-badge';\n\nexport interface TemplateEditorFields {\n subject: string;\n heading: string;\n body: string;\n cta: string;\n html: string;\n}\n\nexport interface TemplateVersionResponse {\n id: string;\n versionNumber: number;\n status: TemplateStatus;\n}\n\nexport interface TemplateEditorProps {\n templateId: string;\n /** Existing version id to publish; falls back to the id returned by the draft save. */\n versionId?: string;\n initialFields?: Partial<TemplateEditorFields>;\n initialStatus?: TemplateStatus;\n basePath?: string;\n className?: string;\n}\n\nconst FIELD_DEFS: Array<{ key: keyof TemplateEditorFields; label: string; multiline: boolean }> = [\n { key: 'subject', label: 'Subject', multiline: false },\n { key: 'heading', label: 'Heading', multiline: false },\n { key: 'body', label: 'Body', multiline: true },\n { key: 'cta', label: 'CTA label', multiline: false },\n { key: 'html', label: 'HTML', multiline: true },\n];\n\n/** Returns true when {{ and }} counts are balanced. */\nfunction bracesBalanced(value: string): boolean {\n const open = (value.match(/\\{\\{/g) ?? []).length;\n const close = (value.match(/\\}\\}/g) ?? []).length;\n return open === close;\n}\n\n/**\n * Template draft editor. Validates Handlebars brace balance client-side before\n * submitting; saves a draft via PUT and offers a publish action. Surfaces\n * field-level errors and ApiError-aware toasts.\n */\nexport function TemplateEditor({\n templateId,\n versionId,\n initialFields,\n initialStatus = 'draft',\n basePath = '/api/templates',\n className,\n}: TemplateEditorProps) {\n const toast = useToast();\n const [fields, setFields] = useState<TemplateEditorFields>({\n subject: initialFields?.subject ?? '',\n heading: initialFields?.heading ?? '',\n body: initialFields?.body ?? '',\n cta: initialFields?.cta ?? '',\n html: initialFields?.html ?? '',\n });\n const [errors, setErrors] = useState<Partial<Record<keyof TemplateEditorFields, string>>>({});\n const [status, setStatus] = useState<TemplateStatus>(initialStatus);\n const [activeVersionId, setActiveVersionId] = useState<string | undefined>(versionId);\n\n const save = useApiMutation<TemplateVersionResponse, TemplateEditorFields>(\n (client, payload) => client.put(`${basePath}/${templateId}`, payload),\n {\n invalidates: [['templates']],\n onSuccess: (result) => {\n setStatus(result.status);\n setActiveVersionId(result.id);\n toast.success('Draft saved');\n },\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n const publish = useApiMutation<TemplateVersionResponse, string>(\n (client, vid) => client.post(`${basePath}/${templateId}/versions/${vid}/publish`, {}),\n {\n invalidates: [['templates']],\n onSuccess: () => {\n setStatus('published');\n toast.success('Version published');\n },\n onError: (error) =>\n toast.error(\n error.isConflict\n ? 'Version already published'\n : error.isServerError\n ? 'Something went wrong'\n : error.title,\n { description: `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})` },\n ),\n },\n );\n\n const validate = (): boolean => {\n const next: Partial<Record<keyof TemplateEditorFields, string>> = {};\n for (const { key } of FIELD_DEFS) {\n if (!bracesBalanced(fields[key])) {\n next[key] = 'Unbalanced Handlebars braces — every {{ needs a matching }}';\n }\n }\n setErrors(next);\n return Object.keys(next).length === 0;\n };\n\n const onSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n if (!validate()) return;\n save.mutate(fields);\n };\n\n return (\n <form onSubmit={onSubmit} className={cn('flex flex-col gap-4', className)} noValidate>\n <header className=\"flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold text-foreground\">Edit template: {templateId}</h2>\n <TemplateStatusBadge status={status} />\n </header>\n\n {FIELD_DEFS.map(({ key, label, multiline }) => {\n const fieldId = `template-${key}`;\n const errorId = `${fieldId}-error`;\n const error = errors[key];\n return (\n <div key={key} className=\"flex flex-col gap-1\">\n <label htmlFor={fieldId} className=\"text-sm font-medium text-foreground\">\n {label}\n </label>\n {multiline ? (\n <textarea\n id={fieldId}\n value={fields[key]}\n rows={4}\n aria-invalid={error ? 'true' : undefined}\n aria-describedby={error ? errorId : undefined}\n onChange={(e) => setFields((prev) => ({ ...prev, [key]: e.target.value }))}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n ) : (\n <input\n id={fieldId}\n type=\"text\"\n value={fields[key]}\n aria-invalid={error ? 'true' : undefined}\n aria-describedby={error ? errorId : undefined}\n onChange={(e) => setFields((prev) => ({ ...prev, [key]: e.target.value }))}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n )}\n {error && (\n <p id={errorId} className=\"text-xs text-destructive\">\n {error}\n </p>\n )}\n </div>\n );\n })}\n\n <div className=\"flex items-center gap-3\">\n <button\n type=\"submit\"\n disabled={save.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {save.isPending ? 'Saving…' : 'Save draft'}\n </button>\n <button\n type=\"button\"\n disabled={!activeVersionId || publish.isPending}\n onClick={() => activeVersionId && publish.mutate(activeVersionId)}\n className=\"rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {publish.isPending ? 'Publishing…' : 'Publish'}\n </button>\n </div>\n </form>\n );\n}\n","import { useEffect } from 'react';\nimport { cn } from '@quanticjs/react-ui';\nimport { useApiMutation } from '@quanticjs/react-query';\n\nexport interface PreviewResult {\n subject: string;\n html: string;\n text: string;\n}\n\nexport interface TemplatePreviewPaneProps {\n templateId: string;\n versionId: string;\n /** Sample variables passed to the render. */\n vars?: Record<string, unknown>;\n basePath?: string;\n className?: string;\n}\n\n/**\n * Renders a server-side preview of a template version. POSTs the version id and\n * sample vars, then displays the rendered subject, sandboxed HTML, and plaintext.\n */\nexport function TemplatePreviewPane({\n templateId,\n versionId,\n vars = {},\n basePath = '/api/templates',\n className,\n}: TemplatePreviewPaneProps) {\n const preview = useApiMutation<PreviewResult, { versionId: string; vars: Record<string, unknown> }>(\n (client, payload) => client.post(`${basePath}/${templateId}/preview`, payload),\n );\n\n const { mutate, data, isPending, isError } = preview;\n\n useEffect(() => {\n mutate({ versionId, vars });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [templateId, versionId]);\n\n if (isPending) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading preview\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading preview</span>\n <div aria-hidden=\"true\" className=\"h-6 w-1/2 animate-pulse rounded bg-muted\" />\n <div aria-hidden=\"true\" className=\"h-40 animate-pulse rounded bg-muted\" />\n </div>\n );\n }\n\n if (isError || !data) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load preview</p>\n <button\n type=\"button\"\n onClick={() => mutate({ versionId, vars })}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n return (\n <section aria-label=\"Template preview\" className={cn('flex flex-col gap-4', className)}>\n <h2 className=\"text-sm font-semibold text-foreground\">{data.subject}</h2>\n <iframe\n title=\"Email preview\"\n sandbox=\"\"\n srcDoc={data.html}\n className=\"h-96 w-full rounded-md border border-border bg-background\"\n />\n <div className=\"flex flex-col gap-1\">\n <h3 className=\"text-xs font-medium text-muted-foreground\">Plain text</h3>\n <pre className=\"overflow-auto whitespace-pre-wrap rounded-md border border-border bg-muted p-3 text-xs text-foreground\">\n {data.text}\n </pre>\n </div>\n </section>\n );\n}\n","import { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiQuery, useApiMutation } from '@quanticjs/react-query';\nimport { TemplateStatusBadge, type TemplateStatus } from './template-status-badge';\n\nexport interface TemplateVersion {\n id: string;\n versionNumber: number;\n status: TemplateStatus;\n createdBy: string;\n createdAt: string;\n locale: string;\n}\n\nexport interface TemplateVersionHistoryProps {\n templateId: string;\n basePath?: string;\n className?: string;\n /** Whether the roll back action is offered for archived versions. */\n canRollback?: boolean;\n}\n\n/**\n * Version history data-list for a template. Lists every version with its status,\n * author, and date, and offers a roll back action for archived versions.\n */\nexport function TemplateVersionHistory({\n templateId,\n basePath = '/api/templates',\n className,\n canRollback = true,\n}: TemplateVersionHistoryProps) {\n const toast = useToast();\n const versionsKey = ['templates', templateId, 'versions'] as const;\n\n const { data, isLoading, isError, refetch } = useApiQuery<TemplateVersion[]>(\n versionsKey,\n (client) => client.get(`${basePath}/${templateId}/versions`),\n );\n\n const rollback = useApiMutation<TemplateVersion, string>(\n (client, id) => client.post(`${basePath}/${templateId}/versions/${id}/rollback`, {}),\n {\n invalidates: [[...versionsKey], ['templates']],\n onSuccess: () => toast.success('Version rolled back'),\n onError: (error) =>\n toast.error(\n error.isConflict\n ? 'Version cannot be rolled back'\n : error.isServerError\n ? 'Something went wrong'\n : error.title,\n { description: `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})` },\n ),\n },\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading versions\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading versions</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load versions</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const versions = data ?? [];\n\n if (versions.length === 0) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No versions\n </div>\n );\n }\n\n return (\n <section aria-label=\"Version history\" className={cn('flex flex-col', className)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Version\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Author\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Date\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n <span className=\"sr-only\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {versions.map((version) => (\n <tr key={version.id} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 font-medium text-foreground\">v{version.versionNumber}</td>\n <td className=\"px-4 py-3\">\n <TemplateStatusBadge status={version.status} />\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">{version.createdBy}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{version.createdAt}</td>\n <td className=\"px-4 py-3 text-end\">\n {canRollback && version.status === 'archived' && (\n <button\n type=\"button\"\n disabled={rollback.isPending}\n onClick={() => rollback.mutate(version.id)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Roll back\n </button>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </section>\n );\n}\n","import { useState } from 'react';\nimport { cn } from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\nimport { TemplateStatusBadge, type TemplateStatus } from './template-status-badge';\n\nexport interface DeliveryLogRow {\n id: string;\n recipientEmail: string;\n status: TemplateStatus;\n attempts: number;\n lastError: string | null;\n createdAt: string;\n}\n\nexport interface DeliveryLogPage {\n items: DeliveryLogRow[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface DeliveryLogViewerProps {\n templateId: string;\n basePath?: string;\n className?: string;\n}\n\nconst LIMIT = 20;\n\n/**\n * Paginated viewer for email delivery logs filtered by template. Renders\n * recipient, status, attempt count, and the last error per row.\n */\nexport function DeliveryLogViewer({\n templateId,\n basePath = '/api/templates',\n className,\n}: DeliveryLogViewerProps) {\n const [page, setPage] = useState(1);\n\n const { data, isLoading, isError, refetch } = useApiQuery<DeliveryLogPage>(\n ['templates', templateId, 'delivery-logs', page],\n (client) => client.get(`${basePath}/${templateId}/delivery-logs?page=${page}&limit=${LIMIT}`),\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading delivery logs\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading delivery logs</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load delivery logs</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const rows = data?.items ?? [];\n const totalPages = data?.totalPages ?? 1;\n\n if (rows.length === 0) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No delivery logs\n </div>\n );\n }\n\n return (\n <section aria-label=\"Delivery logs\" className={cn('flex flex-col gap-3', className)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Recipient\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Attempts\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Last error\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 text-foreground\">{row.recipientEmail}</td>\n <td className=\"px-4 py-3\">\n <TemplateStatusBadge status={row.status} />\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.attempts}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.lastError ?? '—'}</td>\n </tr>\n ))}\n </tbody>\n </table>\n <nav aria-label=\"Delivery log pagination\" className=\"flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n disabled={page <= 1}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Previous\n </button>\n <span className=\"text-xs text-muted-foreground\">\n Page {page} of {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.min(totalPages, p + 1))}\n disabled={page >= totalPages}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Next\n </button>\n </nav>\n </section>\n );\n}\n","import { useApiQuery } from '@quanticjs/react-query';\n\nexport interface BroadcastListItem {\n id: string;\n templateId: string;\n type: string | null;\n status: string;\n channels: string[];\n totalRecipients: number;\n sentCount: number;\n failedCount: number;\n skippedCount: number;\n createdBy: string;\n startedAt: string | null;\n completedAt: string | null;\n createdAt: string;\n}\n\nexport interface BroadcastListPage {\n items: BroadcastListItem[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface UseBroadcastsOptions {\n page?: number;\n status?: string;\n basePath?: string;\n}\n\nconst LIMIT = 20;\n\n/** Paginated broadcast history. Optionally filters by status. */\nexport function useBroadcasts({ page = 1, status, basePath = '/api' }: UseBroadcastsOptions = {}) {\n const statusParam = status ? `&status=${encodeURIComponent(status)}` : '';\n return useApiQuery<BroadcastListPage>(['broadcasts', { page, status }], (client) =>\n client.get(`${basePath}/v1/broadcasts?page=${page}&limit=${LIMIT}${statusParam}`),\n );\n}\n","import { useState } from 'react';\nimport { cn, formatDateTime, StatusBadge, type StatusBadgeVariant } from '@quanticjs/react-ui';\nimport { useBroadcasts, type BroadcastListItem } from './use-broadcasts';\n\nexport interface BroadcastListProps {\n basePath?: string;\n status?: string;\n onSelect?: (id: string) => void;\n className?: string;\n}\n\nfunction statusVariant(status: string): StatusBadgeVariant {\n switch (status) {\n case 'completed':\n return 'success';\n case 'completed_with_errors':\n return 'warning';\n case 'failed':\n return 'destructive';\n case 'cancelled':\n return 'neutral';\n case 'in_progress':\n case 'running':\n case 'pending':\n return 'info';\n default:\n return 'neutral';\n }\n}\n\n/**\n * Paginated table of broadcast history. Renders template, status, channels,\n * sent/failed/skipped counts, creator, and creation time. When `onSelect` is\n * supplied each row becomes a button to drill into that broadcast.\n */\nexport function BroadcastList({\n basePath = '/api',\n status,\n onSelect,\n className,\n}: BroadcastListProps) {\n const [page, setPage] = useState(1);\n const { data, isLoading, isError, refetch } = useBroadcasts({ page, status, basePath });\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading broadcasts\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading broadcasts</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load broadcasts</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const rows = data?.items ?? [];\n const totalPages = data?.totalPages ?? 1;\n\n if (rows.length === 0) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No broadcasts\n </div>\n );\n }\n\n const renderTemplateCell = (row: BroadcastListItem) =>\n onSelect ? (\n <button\n type=\"button\"\n onClick={() => onSelect(row.id)}\n className=\"rounded text-start font-medium text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n {row.templateId}\n </button>\n ) : (\n <span className=\"text-foreground\">{row.templateId}</span>\n );\n\n return (\n <section aria-label=\"Broadcasts\" className={cn('flex flex-col gap-3', className)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Template\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Channels\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Sent / Failed / Skipped\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created by\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border\">\n <td className=\"py-3 pe-4\">{renderTemplateCell(row)}</td>\n <td className=\"px-4 py-3\">\n <StatusBadge variant={statusVariant(row.status)}>{row.status}</StatusBadge>\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {row.channels.length > 0 ? row.channels.join(', ') : '—'}\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {row.sentCount} / {row.failedCount} / {row.skippedCount}\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.createdBy}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{formatDateTime(row.createdAt)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n <nav aria-label=\"Broadcast pagination\" className=\"flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n disabled={page <= 1}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Previous\n </button>\n <span className=\"text-xs text-muted-foreground\">\n Page {page} of {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.min(totalPages, p + 1))}\n disabled={page >= totalPages}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Next\n </button>\n </nav>\n </section>\n );\n}\n","import { cn, useToast, StatusBadge, type StatusBadgeVariant } from '@quanticjs/react-ui';\nimport { useApiQuery, useApiMutation } from '@quanticjs/react-query';\n\nexport interface BroadcastDetail {\n id: string;\n templateId: string;\n status: string;\n channels: string[];\n totalRecipients: number;\n sentCount: number;\n failedCount: number;\n skippedCount: number;\n startedAt: string | null;\n completedAt: string | null;\n createdAt: string;\n}\n\nexport interface BroadcastProgressProps {\n broadcastId: string;\n basePath?: string;\n onCancelled?: () => void;\n className?: string;\n}\n\nconst TERMINAL_STATUSES = ['completed', 'completed_with_errors', 'failed', 'cancelled'];\n\nfunction isTerminalStatus(status: string | undefined): boolean {\n return status !== undefined && TERMINAL_STATUSES.includes(status);\n}\n\nfunction statusVariant(status: string): StatusBadgeVariant {\n switch (status) {\n case 'completed':\n return 'success';\n case 'completed_with_errors':\n return 'warning';\n case 'failed':\n return 'destructive';\n case 'cancelled':\n return 'neutral';\n default:\n return 'info';\n }\n}\n\n/**\n * Live progress for a single broadcast. Polls every 5s while the status is\n * non-terminal, then stops. Shows sent/failed/skipped/total counters, a\n * progress bar, and a Cancel action.\n */\nexport function BroadcastProgress({\n broadcastId,\n basePath = '/api',\n onCancelled,\n className,\n}: BroadcastProgressProps) {\n const toast = useToast();\n\n const { data, isLoading, isError, refetch } = useApiQuery<BroadcastDetail>(\n ['broadcasts', broadcastId],\n (client) => client.get(`${basePath}/v1/broadcasts/${broadcastId}`),\n {\n refetchInterval: (query) => (isTerminalStatus(query.state.data?.status) ? false : 5000),\n },\n );\n\n const cancel = useApiMutation<void, void>(\n (client) => client.delete(`${basePath}/v1/broadcasts/${broadcastId}`),\n {\n invalidates: [['broadcasts']],\n onSuccess: () => {\n toast.success('Broadcast cancelled');\n onCancelled?.();\n },\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading broadcast\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading broadcast</span>\n {[0, 1].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load broadcast</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n if (!data) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No broadcast\n </div>\n );\n }\n\n const total = data.totalRecipients;\n const processed = data.sentCount + data.failedCount + data.skippedCount;\n const pct = total > 0 ? Math.min(100, Math.round((processed / total) * 100)) : 0;\n const terminal = isTerminalStatus(data.status);\n\n return (\n <section aria-label=\"Broadcast progress\" className={cn('flex flex-col gap-4 p-4', className)}>\n <header className=\"flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold text-foreground\">Broadcast {data.templateId}</h2>\n <StatusBadge variant={statusVariant(data.status)} appearance=\"solid\">\n {data.status}\n </StatusBadge>\n </header>\n\n <div\n role=\"progressbar\"\n aria-valuenow={pct}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label=\"Broadcast completion\"\n className=\"h-2 w-full overflow-hidden rounded-full bg-muted\"\n >\n <div className=\"h-full rounded-full bg-primary\" style={{ width: `${pct}%` }} />\n </div>\n <p className=\"text-xs text-muted-foreground\">\n {processed} of {total} processed ({pct}%)\n </p>\n\n <dl className=\"grid grid-cols-2 gap-3 text-sm sm:grid-cols-4\">\n <div className=\"flex flex-col rounded-md border border-border bg-card p-3\">\n <dt className=\"text-xs text-muted-foreground\">Sent</dt>\n <dd className=\"text-foreground\">{data.sentCount}</dd>\n </div>\n <div className=\"flex flex-col rounded-md border border-border bg-card p-3\">\n <dt className=\"text-xs text-muted-foreground\">Failed</dt>\n <dd className=\"text-foreground\">{data.failedCount}</dd>\n </div>\n <div className=\"flex flex-col rounded-md border border-border bg-card p-3\">\n <dt className=\"text-xs text-muted-foreground\">Skipped</dt>\n <dd className=\"text-foreground\">{data.skippedCount}</dd>\n </div>\n <div className=\"flex flex-col rounded-md border border-border bg-card p-3\">\n <dt className=\"text-xs text-muted-foreground\">Total</dt>\n <dd className=\"text-foreground\">{total}</dd>\n </div>\n </dl>\n\n <div>\n <button\n type=\"button\"\n disabled={terminal || cancel.isPending}\n onClick={() => cancel.mutate()}\n className=\"rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {cancel.isPending ? 'Cancelling…' : 'Cancel'}\n </button>\n </div>\n </section>\n );\n}\n","import { useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiQuery, useApiMutation } from '@quanticjs/react-query';\n\nexport interface TemplateOption {\n id: string;\n name?: string;\n}\n\nexport interface SegmentOption {\n id: string;\n name: string;\n}\n\ninterface ItemsWrapper<T> {\n items: T[];\n}\n\nexport interface BroadcastCreatedResult {\n id: string;\n}\n\ninterface BroadcastCreateBody {\n templateId: string;\n channels: string[];\n type: string | null;\n segmentId: string | null;\n recipientIds: string[] | null;\n idempotencyKey: string;\n}\n\nexport interface BroadcastComposerProps {\n basePath?: string;\n onCreated?: (id: string) => void;\n className?: string;\n}\n\ntype AudienceMode = 'segment' | 'recipients';\n\nconst CHANNELS = ['inapp', 'email', 'push', 'sms', 'webhook', 'slack', 'teams'] as const;\n\ninterface ComposerErrors {\n templateId?: string;\n channels?: string;\n audience?: string;\n}\n\n/** Normalizes either an array or an `{ items }` wrapper into a plain array. */\nfunction normalizeList<T>(data: T[] | ItemsWrapper<T> | undefined): T[] {\n if (!data) return [];\n if (Array.isArray(data)) return data;\n return data.items ?? [];\n}\n\nfunction parseRecipients(raw: string): string[] {\n return raw\n .split(/[\\n,]/)\n .map((r) => r.trim())\n .filter((r) => r.length > 0);\n}\n\n/**\n * Compose and dispatch a broadcast. Loads templates and segments, lets the user\n * pick channels and either a segment or an explicit recipient list, and submits\n * with a stable idempotency key per compose session.\n */\nexport function BroadcastComposer({\n basePath = '/api',\n onCreated,\n className,\n}: BroadcastComposerProps) {\n const toast = useToast();\n const [idempotencyKey] = useState(() => crypto.randomUUID());\n\n const [templateId, setTemplateId] = useState('');\n const [channels, setChannels] = useState<string[]>([]);\n const [audienceMode, setAudienceMode] = useState<AudienceMode>('segment');\n const [segmentId, setSegmentId] = useState('');\n const [recipientsRaw, setRecipientsRaw] = useState('');\n const [type, setType] = useState('');\n const [errors, setErrors] = useState<ComposerErrors>({});\n\n const templatesQuery = useApiQuery<TemplateOption[] | ItemsWrapper<TemplateOption>>(\n ['templates'],\n (client) => client.get(`${basePath}/templates`),\n );\n\n const segmentsQuery = useApiQuery<SegmentOption[] | ItemsWrapper<SegmentOption>>(\n ['segments'],\n (client) => client.get(`${basePath}/v1/segments`),\n );\n\n const create = useApiMutation<BroadcastCreatedResult, BroadcastCreateBody>(\n (client, payload) => client.post(`${basePath}/v1/broadcasts`, payload),\n {\n invalidates: [['broadcasts']],\n onSuccess: (result) => {\n toast.success('Broadcast created');\n onCreated?.(result.id);\n },\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n const isLoading = templatesQuery.isLoading || segmentsQuery.isLoading;\n const isError = templatesQuery.isError || segmentsQuery.isError;\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading broadcast composer\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading broadcast composer</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load broadcast composer</p>\n <button\n type=\"button\"\n onClick={() => {\n void templatesQuery.refetch();\n void segmentsQuery.refetch();\n }}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const templates = normalizeList(templatesQuery.data);\n const segments = normalizeList(segmentsQuery.data);\n\n const toggleChannel = (channel: string) => {\n setChannels((prev) =>\n prev.includes(channel) ? prev.filter((c) => c !== channel) : [...prev, channel],\n );\n };\n\n const validate = (recipientIds: string[]): boolean => {\n const next: ComposerErrors = {};\n if (!templateId) next.templateId = 'Select a template';\n if (channels.length === 0) next.channels = 'Select at least one channel';\n if (audienceMode === 'segment' && !segmentId) {\n next.audience = 'Select a segment';\n }\n if (audienceMode === 'recipients' && recipientIds.length === 0) {\n next.audience = 'Add at least one recipient id';\n }\n setErrors(next);\n return Object.keys(next).length === 0;\n };\n\n const onSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n const recipientIds = parseRecipients(recipientsRaw);\n if (!validate(recipientIds)) return;\n create.mutate({\n templateId,\n channels,\n type: type.trim() ? type.trim() : null,\n segmentId: audienceMode === 'segment' ? segmentId : null,\n recipientIds: audienceMode === 'recipients' ? recipientIds : null,\n idempotencyKey,\n });\n };\n\n return (\n <form onSubmit={onSubmit} className={cn('flex flex-col gap-4 p-4', className)} noValidate>\n <h2 className=\"text-sm font-semibold text-foreground\">New broadcast</h2>\n\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"composer-template\" className=\"text-sm font-medium text-foreground\">\n Template\n </label>\n <select\n id=\"composer-template\"\n value={templateId}\n aria-invalid={errors.templateId ? 'true' : undefined}\n aria-describedby={errors.templateId ? 'composer-template-error' : undefined}\n onChange={(e) => setTemplateId(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <option value=\"\">Select a template…</option>\n {templates.map((t) => (\n <option key={t.id} value={t.id}>\n {t.name ?? t.id}\n </option>\n ))}\n </select>\n {errors.templateId && (\n <p id=\"composer-template-error\" className=\"text-xs text-destructive\">\n {errors.templateId}\n </p>\n )}\n </div>\n\n <fieldset\n className=\"flex flex-col gap-2\"\n aria-invalid={errors.channels ? 'true' : undefined}\n aria-describedby={errors.channels ? 'composer-channels-error' : undefined}\n >\n <legend className=\"text-sm font-medium text-foreground\">Channels</legend>\n <div className=\"flex flex-wrap gap-3\">\n {CHANNELS.map((channel) => {\n const checkboxId = `composer-channel-${channel}`;\n return (\n <label\n key={channel}\n htmlFor={checkboxId}\n className=\"flex items-center gap-2 text-sm text-foreground\"\n >\n <input\n id={checkboxId}\n type=\"checkbox\"\n checked={channels.includes(channel)}\n onChange={() => toggleChannel(channel)}\n className=\"rounded border-border focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n {channel}\n </label>\n );\n })}\n </div>\n {errors.channels && (\n <p id=\"composer-channels-error\" className=\"text-xs text-destructive\">\n {errors.channels}\n </p>\n )}\n </fieldset>\n\n <fieldset className=\"flex flex-col gap-2\">\n <legend className=\"text-sm font-medium text-foreground\">Audience</legend>\n <div className=\"flex gap-4\">\n <label\n htmlFor=\"composer-audience-segment\"\n className=\"flex items-center gap-2 text-sm text-foreground\"\n >\n <input\n id=\"composer-audience-segment\"\n type=\"radio\"\n name=\"composer-audience\"\n checked={audienceMode === 'segment'}\n onChange={() => setAudienceMode('segment')}\n className=\"border-border focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n Segment\n </label>\n <label\n htmlFor=\"composer-audience-recipients\"\n className=\"flex items-center gap-2 text-sm text-foreground\"\n >\n <input\n id=\"composer-audience-recipients\"\n type=\"radio\"\n name=\"composer-audience\"\n checked={audienceMode === 'recipients'}\n onChange={() => setAudienceMode('recipients')}\n className=\"border-border focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n Recipients\n </label>\n </div>\n\n {audienceMode === 'segment' ? (\n <select\n id=\"composer-segment\"\n aria-label=\"Segment\"\n value={segmentId}\n aria-invalid={errors.audience ? 'true' : undefined}\n aria-describedby={errors.audience ? 'composer-audience-error' : undefined}\n onChange={(e) => setSegmentId(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <option value=\"\">Select a segment…</option>\n {segments.map((s) => (\n <option key={s.id} value={s.id}>\n {s.name}\n </option>\n ))}\n </select>\n ) : (\n <textarea\n id=\"composer-recipients\"\n aria-label=\"Recipient ids\"\n value={recipientsRaw}\n rows={4}\n placeholder=\"Recipient ids separated by commas or new lines\"\n aria-invalid={errors.audience ? 'true' : undefined}\n aria-describedby={errors.audience ? 'composer-audience-error' : undefined}\n onChange={(e) => setRecipientsRaw(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n )}\n {errors.audience && (\n <p id=\"composer-audience-error\" className=\"text-xs text-destructive\">\n {errors.audience}\n </p>\n )}\n </fieldset>\n\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"composer-type\" className=\"text-sm font-medium text-foreground\">\n Type (optional)\n </label>\n <input\n id=\"composer-type\"\n type=\"text\"\n value={type}\n onChange={(e) => setType(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n\n <div>\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {create.isPending ? 'Creating…' : 'Create broadcast'}\n </button>\n </div>\n </form>\n );\n}\n","import { cn, formatDateTime, StatusBadge, type StatusBadgeVariant } from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\n\nexport interface Segment {\n id: string;\n name: string;\n type: string;\n description: string | null;\n recipientIds: string[] | null;\n createdBy: string;\n createdAt: string;\n}\n\nexport interface SegmentListProps {\n basePath?: string;\n onSelect?: (id: string) => void;\n onCreate?: () => void;\n className?: string;\n}\n\n/** Normalize the API response, which may be a bare array or `{ items: [...] }`. */\nfunction normalize(data: Segment[] | { items?: Segment[] } | undefined): Segment[] {\n if (Array.isArray(data)) return data;\n return data?.items ?? [];\n}\n\nfunction typeVariant(type: string): StatusBadgeVariant {\n switch (type) {\n case 'dynamic':\n return 'info';\n case 'static':\n return 'neutral';\n default:\n return 'neutral';\n }\n}\n\n/**\n * Table of audience segments. Renders name, type, description, recipient count,\n * and creation time. When `onSelect` is supplied each name becomes a button.\n * When `onCreate` is supplied a \"New segment\" button is rendered in the header.\n */\nexport function SegmentList({\n basePath = '/api',\n onSelect,\n onCreate,\n className,\n}: SegmentListProps) {\n const { data, isLoading, isError, refetch } = useApiQuery<Segment[] | { items?: Segment[] }>(\n ['segments'],\n (client) => client.get(`${basePath}/v1/segments`),\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading segments\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading segments</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load segments</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const rows = normalize(data);\n\n const header = onCreate ? (\n <header className=\"flex items-center justify-end\">\n <button\n type=\"button\"\n onClick={() => onCreate()}\n className=\"rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n New segment\n </button>\n </header>\n ) : null;\n\n if (rows.length === 0) {\n return (\n <section aria-label=\"Segments\" className={cn('flex flex-col gap-3', className)}>\n {header}\n <div className=\"p-6 text-center text-sm text-muted-foreground\">No segments</div>\n </section>\n );\n }\n\n const renderNameCell = (row: Segment) =>\n onSelect ? (\n <button\n type=\"button\"\n onClick={() => onSelect(row.id)}\n className=\"rounded text-start font-medium text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n {row.name}\n </button>\n ) : (\n <span className=\"text-foreground\">{row.name}</span>\n );\n\n return (\n <section aria-label=\"Segments\" className={cn('flex flex-col gap-3', className)}>\n {header}\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Name\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Type\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Description\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Recipients\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border\">\n <td className=\"py-3 pe-4\">{renderNameCell(row)}</td>\n <td className=\"px-4 py-3\">\n <StatusBadge variant={typeVariant(row.type)} appearance=\"dot\">\n {row.type}\n </StatusBadge>\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.description ?? '—'}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.recipientIds?.length ?? '—'}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{formatDateTime(row.createdAt)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </section>\n );\n}\n","import { useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation } from '@quanticjs/react-query';\n\nexport type SegmentType = 'static' | 'dynamic';\n\nexport interface SegmentForm {\n name: string;\n type: SegmentType;\n description: string;\n recipientIds: string[];\n}\n\nexport interface SegmentSaveResult {\n id: string;\n}\n\nexport interface SegmentBuilderProps {\n basePath?: string;\n segmentId?: string;\n initial?: Partial<SegmentForm>;\n onSaved?: (id: string) => void;\n onDeleted?: () => void;\n className?: string;\n}\n\ninterface SegmentPayload {\n name: string;\n type: SegmentType;\n description: string;\n recipientIds: string[];\n}\n\ntype SegmentFieldErrors = Partial<Record<'name' | 'recipientIds', string>>;\n\n/** Split a comma/newline-separated textarea value into a trimmed, non-empty list. */\nfunction parseRecipientIds(value: string): string[] {\n return value\n .split(/[\\n,]/)\n .map((id) => id.trim())\n .filter((id) => id.length > 0);\n}\n\n/**\n * Create/edit form for audience segments. Creates via POST and (when\n * `segmentId` is set) edits via PATCH with a guarded Delete action. Validates\n * client-side and surfaces field-level errors plus ApiError-aware toasts.\n */\nexport function SegmentBuilder({\n basePath = '/api',\n segmentId,\n initial,\n onSaved,\n onDeleted,\n className,\n}: SegmentBuilderProps) {\n const toast = useToast();\n const [name, setName] = useState(initial?.name ?? '');\n const [type, setType] = useState<SegmentType>(initial?.type ?? 'static');\n const [description, setDescription] = useState(initial?.description ?? '');\n const [recipientText, setRecipientText] = useState((initial?.recipientIds ?? []).join('\\n'));\n const [errors, setErrors] = useState<SegmentFieldErrors>({});\n\n const isEdit = Boolean(segmentId);\n\n const onMutationError = (error: {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n }) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n\n const save = useApiMutation<SegmentSaveResult, SegmentPayload>(\n (client, payload) =>\n segmentId\n ? client.patch(`${basePath}/v1/segments/${segmentId}`, payload)\n : client.post(`${basePath}/v1/segments`, payload),\n {\n invalidates: [['segments']],\n onSuccess: (result) => {\n toast.success(isEdit ? 'Segment updated' : 'Segment created');\n onSaved?.(result.id);\n },\n onError: onMutationError,\n },\n );\n\n const remove = useApiMutation<void, void>(\n (client) => client.delete(`${basePath}/v1/segments/${segmentId}`),\n {\n invalidates: [['segments']],\n onSuccess: () => {\n toast.success('Segment deleted');\n onDeleted?.();\n },\n onError: onMutationError,\n },\n );\n\n const validate = (recipientIds: string[]): boolean => {\n const next: SegmentFieldErrors = {};\n if (name.trim().length === 0) {\n next.name = 'Name is required';\n }\n if (type === 'static' && recipientIds.length === 0) {\n next.recipientIds = 'A static segment needs at least one recipient id';\n }\n setErrors(next);\n return Object.keys(next).length === 0;\n };\n\n const onSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n const recipientIds = parseRecipientIds(recipientText);\n if (!validate(recipientIds)) return;\n save.mutate({ name: name.trim(), type, description: description.trim(), recipientIds });\n };\n\n const onDelete = () => {\n if (!segmentId) return;\n if (!window.confirm('Delete this segment? This cannot be undone.')) return;\n remove.mutate();\n };\n\n return (\n <form onSubmit={onSubmit} className={cn('flex flex-col gap-4', className)} noValidate>\n <header className=\"flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold text-foreground\">\n {isEdit ? `Edit segment: ${segmentId}` : 'New segment'}\n </h2>\n </header>\n\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"segment-name\" className=\"text-sm font-medium text-foreground\">\n Name\n </label>\n <input\n id=\"segment-name\"\n type=\"text\"\n value={name}\n aria-invalid={errors.name ? 'true' : undefined}\n aria-describedby={errors.name ? 'segment-name-error' : undefined}\n onChange={(e) => setName(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n {errors.name && (\n <p id=\"segment-name-error\" className=\"text-xs text-destructive\">\n {errors.name}\n </p>\n )}\n </div>\n\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"segment-type\" className=\"text-sm font-medium text-foreground\">\n Type\n </label>\n <select\n id=\"segment-type\"\n value={type}\n onChange={(e) => setType(e.target.value as SegmentType)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <option value=\"static\">static</option>\n <option value=\"dynamic\">dynamic</option>\n </select>\n </div>\n\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"segment-description\" className=\"text-sm font-medium text-foreground\">\n Description\n </label>\n <textarea\n id=\"segment-description\"\n value={description}\n rows={3}\n onChange={(e) => setDescription(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n\n {type === 'static' && (\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"segment-recipients\" className=\"text-sm font-medium text-foreground\">\n Recipient ids\n </label>\n <textarea\n id=\"segment-recipients\"\n value={recipientText}\n rows={4}\n placeholder=\"Comma or newline separated\"\n aria-invalid={errors.recipientIds ? 'true' : undefined}\n aria-describedby={errors.recipientIds ? 'segment-recipients-error' : undefined}\n onChange={(e) => setRecipientText(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n {errors.recipientIds && (\n <p id=\"segment-recipients-error\" className=\"text-xs text-destructive\">\n {errors.recipientIds}\n </p>\n )}\n </div>\n )}\n\n <div className=\"flex items-center gap-3\">\n <button\n type=\"submit\"\n disabled={save.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {save.isPending ? 'Saving…' : isEdit ? 'Save changes' : 'Create segment'}\n </button>\n {isEdit && (\n <button\n type=\"button\"\n disabled={remove.isPending}\n onClick={onDelete}\n className=\"rounded-md border border-border px-4 py-2 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {remove.isPending ? 'Deleting…' : 'Delete'}\n </button>\n )}\n </div>\n </form>\n );\n}\n","import { useState } from 'react';\nimport { Button, Card, EmptyState, cn, formatDateTime, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\nimport { ErrorPanel, FIELD_CLASS, Pager, PanelHeader, SkeletonRows } from './admin-panel';\n\nexport type SuppressionChannel = 'inapp' | 'email' | 'push' | 'sms';\n\nexport interface Suppression {\n id: string;\n channel: string;\n address: string;\n reason: string;\n createdAt: string;\n}\n\nexport interface SuppressionPage {\n items: Suppression[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface SuppressionManagerProps {\n basePath?: string;\n className?: string;\n}\n\ninterface SuppressionPayload {\n channel: SuppressionChannel;\n address: string;\n reason: string;\n}\n\nconst LIMIT = 20;\nconst CHANNELS: SuppressionChannel[] = ['inapp', 'email', 'push', 'sms'];\n\n/**\n * Manage the delivery suppression list. Lists suppressed addresses (paginated)\n * with per-row removal, and an inline add form. All mutations refetch the list\n * and surface ApiError-aware toasts.\n */\nexport function SuppressionManager({ basePath = '/api', className }: SuppressionManagerProps) {\n const toast = useToast();\n const [page, setPage] = useState(1);\n const [channel, setChannel] = useState<SuppressionChannel>('email');\n const [address, setAddress] = useState('');\n const [reason, setReason] = useState('');\n\n const { data, isLoading, isError, refetch } = useApiQuery<SuppressionPage>(\n ['suppression', page],\n (client) => client.get(`${basePath}/v1/admin/suppression?page=${page}&limit=${LIMIT}`),\n );\n\n const onMutationError = (error: {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n }) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n\n const add = useApiMutation<void, SuppressionPayload>(\n (client, payload) => client.post(`${basePath}/v1/admin/suppression`, payload),\n {\n invalidates: [['suppression']],\n onSuccess: () => {\n toast.success('Suppression added');\n setAddress('');\n setReason('');\n void refetch();\n },\n onError: onMutationError,\n },\n );\n\n const remove = useApiMutation<void, string>(\n (client, id) => client.delete(`${basePath}/v1/admin/suppression/${id}`),\n {\n invalidates: [['suppression']],\n onSuccess: () => {\n toast.success('Suppression removed');\n void refetch();\n },\n onError: onMutationError,\n },\n );\n\n const onAdd = (event: React.FormEvent) => {\n event.preventDefault();\n add.mutate({ channel, address: address.trim(), reason: reason.trim() });\n };\n\n const rows = data?.items ?? [];\n const totalPages = data?.totalPages ?? 1;\n\n return (\n <section aria-label=\"Suppression list\" className={cn('flex flex-col gap-4', className)}>\n <Card>\n <form onSubmit={onAdd} className=\"flex flex-wrap items-end gap-3 p-4\" noValidate>\n <label className=\"flex flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">Channel</span>\n <select\n value={channel}\n onChange={(e) => setChannel(e.target.value as SuppressionChannel)}\n className={FIELD_CLASS}\n >\n {CHANNELS.map((c) => (\n <option key={c} value={c}>\n {c}\n </option>\n ))}\n </select>\n </label>\n <label className=\"flex flex-1 flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">Address</span>\n <input type=\"text\" value={address} onChange={(e) => setAddress(e.target.value)} className={FIELD_CLASS} />\n </label>\n <label className=\"flex flex-1 flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">Reason</span>\n <input type=\"text\" value={reason} onChange={(e) => setReason(e.target.value)} className={FIELD_CLASS} />\n </label>\n <Button type=\"submit\" disabled={add.isPending}>\n {add.isPending ? 'Adding…' : 'Add suppression'}\n </Button>\n </form>\n </Card>\n\n <Card>\n <PanelHeader title=\"Suppressions\" subtitle={`${data?.total ?? rows.length} entries`} />\n {isLoading ? (\n <SkeletonRows label=\"Loading suppressions\" />\n ) : isError ? (\n <ErrorPanel message=\"Failed to load suppressions\" onRetry={() => void refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState icon={<BanIcon />} title=\"No suppressions\" description=\"No addresses are suppressed.\" />\n ) : (\n <>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Channel</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Address</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Reason</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Created</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\"><span className=\"sr-only\">Actions</span></th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border last:border-0 hover:bg-muted/40\">\n <td className=\"px-4 py-3\">\n <span className=\"inline-flex items-center rounded bg-muted px-1.5 py-0.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground\">\n {row.channel}\n </span>\n </td>\n <td className=\"px-4 py-3 text-foreground\">{row.address}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.reason}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{formatDateTime(row.createdAt)}</td>\n <td className=\"px-4 py-3 text-end\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-destructive\"\n disabled={remove.isPending}\n onClick={() => remove.mutate(row.id)}\n >\n Remove\n </Button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n <Pager\n label=\"Suppression pagination\"\n page={page}\n totalPages={totalPages}\n onPrev={() => setPage((p) => Math.max(1, p - 1))}\n onNext={() => setPage((p) => Math.min(totalPages, p + 1))}\n />\n </>\n )}\n </Card>\n </section>\n );\n}\n\n/* Decorative inline icon — `lucide-react` is not a dependency of this package. */\n\nfunction BanIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m4.9 4.9 14.2 14.2\" />\n </svg>\n );\n}\n","import { Button, Skeleton } from '@quanticjs/react-ui';\n\n/**\n * Internal layout primitives shared by the admin panels (delivery logs, DLQ,\n * API keys, suppression). NOT part of the package's public API — these are\n * notification-ui-internal and intentionally not re-exported from `index.ts`.\n */\n\n/** Card header strip: a bold title plus an optional muted subtitle/count. */\nexport function PanelHeader({ title, subtitle }: { title: string; subtitle?: string }) {\n return (\n <div className=\"flex items-center justify-between gap-2 border-b border-border px-4 py-3\">\n <div className=\"flex flex-col\">\n <h2 className=\"text-sm font-semibold text-foreground\">{title}</h2>\n {subtitle && <p className=\"text-xs text-muted-foreground tabular-nums\">{subtitle}</p>}\n </div>\n </div>\n );\n}\n\n/** Loading skeleton rows. Carries the `role=\"status\"` + label loading contract. */\nexport function SkeletonRows({ label, rows = 4 }: { label: string; rows?: number }) {\n return (\n <div role=\"status\" aria-label={label} className=\"flex flex-col gap-2 p-4\">\n <span className=\"sr-only\">{label}</span>\n {Array.from({ length: rows }).map((_, i) => (\n <Skeleton key={i} className=\"h-10 w-full\" />\n ))}\n </div>\n );\n}\n\n/** Centered error block with a destructive icon circle and a retry action. */\nexport function ErrorPanel({ message, onRetry }: { message: string; onRetry: () => void }) {\n return (\n <div className=\"flex flex-col items-center gap-3 px-6 py-12 text-center\">\n <span\n aria-hidden=\"true\"\n className=\"grid size-12 place-items-center rounded-full bg-destructive/10 text-destructive [&_svg]:size-6\"\n >\n <AlertIcon />\n </span>\n <p className=\"text-sm font-medium text-foreground\">{message}</p>\n <Button type=\"button\" onClick={onRetry}>\n Try again\n </Button>\n </div>\n );\n}\n\n/** Previous / page indicator / Next pager strip. */\nexport function Pager({\n label,\n page,\n totalPages,\n onPrev,\n onNext,\n}: {\n label: string;\n page: number;\n totalPages: number;\n onPrev: () => void;\n onNext: () => void;\n}) {\n return (\n <nav\n aria-label={label}\n className=\"flex items-center justify-between gap-2 border-t border-border px-4 py-3\"\n >\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={onPrev} disabled={page <= 1}>\n Previous\n </Button>\n <span className=\"text-xs text-muted-foreground tabular-nums\">\n Page {page} of {totalPages}\n </span>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={onNext} disabled={page >= totalPages}>\n Next\n </Button>\n </nav>\n );\n}\n\n/** Shared labeled-field input/select class. */\nexport const FIELD_CLASS =\n 'rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring';\n\n/* Decorative inline icons — `lucide-react` is not a dependency of this package. */\n\nexport function AlertIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z\" />\n <line x1=\"12\" x2=\"12\" y1=\"9\" y2=\"13\" />\n <line x1=\"12\" x2=\"12.01\" y1=\"17\" y2=\"17\" />\n </svg>\n );\n}\n","import { Fragment, useState } from 'react';\nimport {\n Button,\n Card,\n EmptyState,\n StatusBadge,\n cn,\n formatDateTime,\n type StatusBadgeVariant,\n useToast,\n} from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\nimport { ErrorPanel, FIELD_CLASS, Pager, PanelHeader, SkeletonRows } from './admin-panel';\n\nexport type DlqStatusFilter = 'queued' | 'replayed' | 'discarded';\n\nexport interface DlqMessage {\n id: string;\n requestId: string | null;\n failureReason: string;\n status: string;\n attemptCount: number;\n firstSeenAt: string;\n}\n\nexport interface DlqPage {\n items: DlqMessage[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface DlqMessageDetail {\n id: string;\n requestId: string | null;\n failureReason: string;\n errorMessage: string | null;\n status: string;\n attemptCount: number;\n firstSeenAt: string;\n replayedAt: string | null;\n payload?: unknown;\n}\n\nexport interface DlqConsoleProps {\n basePath?: string;\n className?: string;\n}\n\nconst LIMIT = 20;\nconst STATUS_FILTERS: DlqStatusFilter[] = ['queued', 'replayed', 'discarded'];\n\ninterface MutationErrorShape {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n}\n\nfunction buildErrorDescription(error: MutationErrorShape): string {\n return error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`;\n}\n\nfunction statusVariant(status: string): StatusBadgeVariant {\n switch (status) {\n case 'replayed':\n return 'success';\n case 'discarded':\n return 'neutral';\n case 'queued':\n return 'warning';\n default:\n return 'neutral';\n }\n}\n\n/** Lazily fetches and renders the detail/payload for a single expanded row. */\nfunction DlqMessageDetailRow({ id, basePath }: { id: string; basePath: string }) {\n const { data, isLoading, isError, refetch } = useApiQuery<DlqMessageDetail>(\n ['dlq', 'detail', id],\n (client) => client.get(`${basePath}/admin/dlq/${id}`),\n );\n\n if (isLoading) {\n return (\n <div role=\"status\" aria-label=\"Loading message detail\" className=\"p-4\">\n <span className=\"sr-only\">Loading message detail</span>\n <div aria-hidden=\"true\" className=\"h-16 animate-pulse rounded bg-muted motion-reduce:animate-none\" />\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className=\"flex flex-col items-start gap-3 p-4\">\n <p className=\"text-sm text-foreground\">Failed to load message detail</p>\n <Button type=\"button\" size=\"sm\" onClick={() => void refetch()}>\n Try again\n </Button>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col gap-3 px-5 py-4 text-sm\">\n <div>\n <div className=\"mb-1 text-[11px] font-medium uppercase tracking-wider text-muted-foreground\">Error</div>\n <div className=\"font-mono text-xs text-destructive\">{data?.errorMessage ?? '—'}</div>\n </div>\n <div>\n <div className=\"mb-1 text-[11px] font-medium uppercase tracking-wider text-muted-foreground\">Payload</div>\n <pre className=\"max-h-64 overflow-auto rounded-md border border-border bg-card p-3 font-mono text-xs leading-relaxed text-foreground\">\n {JSON.stringify(data?.payload ?? {}, null, 2)}\n </pre>\n </div>\n </div>\n );\n}\n\n/**\n * Dead-letter queue console. Lists failed messages (paginated, status-filtered)\n * with per-row expand to view payload/detail, plus Replay and Discard actions.\n * All mutations refetch the list and surface ApiError-aware toasts.\n */\nexport function DlqConsole({ basePath = '/api', className }: DlqConsoleProps) {\n const toast = useToast();\n const [page, setPage] = useState(1);\n const [statusFilter, setStatusFilter] = useState<DlqStatusFilter | ''>('');\n const [expandedId, setExpandedId] = useState<string | null>(null);\n\n const statusQuery = statusFilter ? `&status=${statusFilter}` : '';\n const { data, isLoading, isError, refetch } = useApiQuery<DlqPage>(\n ['dlq', page, statusFilter],\n (client) => client.get(`${basePath}/admin/dlq?page=${page}&limit=${LIMIT}${statusQuery}`),\n );\n\n const replay = useApiMutation<void, string>(\n (client, id) => client.post(`${basePath}/admin/dlq/${id}/replay`, {}),\n {\n invalidates: [['dlq']],\n onSuccess: () => {\n toast.success('Message queued for replay');\n void refetch();\n },\n onError: (error) => {\n if (error.isConflict) {\n toast.error('Message already replayed', {\n description: `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n void refetch();\n return;\n }\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: buildErrorDescription(error),\n });\n },\n },\n );\n\n const discard = useApiMutation<void, string>(\n (client, id) => client.delete(`${basePath}/admin/dlq/${id}`),\n {\n invalidates: [['dlq']],\n onSuccess: () => {\n toast.success('Message discarded');\n void refetch();\n },\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: buildErrorDescription(error),\n }),\n },\n );\n\n const rows = data?.items ?? [];\n const totalPages = data?.totalPages ?? 1;\n\n return (\n <section aria-label=\"Dead-letter queue\" className={cn('flex flex-col gap-4', className)}>\n <div className=\"flex items-center justify-end gap-2\">\n <label htmlFor=\"dlq-status\" className=\"text-sm font-medium text-foreground\">\n Status\n </label>\n <select\n id=\"dlq-status\"\n value={statusFilter}\n onChange={(e) => {\n setStatusFilter(e.target.value as DlqStatusFilter | '');\n setPage(1);\n }}\n className={FIELD_CLASS}\n >\n <option value=\"\">All</option>\n {STATUS_FILTERS.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n </div>\n\n <Card>\n <PanelHeader title=\"Messages\" subtitle={!isLoading && !isError ? `${data?.total ?? rows.length} messages` : undefined} />\n {isLoading ? (\n <SkeletonRows label=\"Loading dead-letter messages\" />\n ) : isError ? (\n <ErrorPanel message=\"Failed to load dead-letter messages\" onRetry={() => void refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState icon={<SkullIcon />} title=\"No dead-letter messages\" description=\"The queue is empty for the current filter.\" />\n ) : (\n <>\n <ul className=\"divide-y divide-border\">\n {rows.map((row) => {\n const isExpanded = expandedId === row.id;\n return (\n <Fragment key={row.id}>\n <li className=\"flex items-start gap-3 px-4 py-3.5\">\n <button\n type=\"button\"\n aria-expanded={isExpanded}\n aria-label={isExpanded ? 'Collapse' : 'Expand'}\n onClick={() => setExpandedId(isExpanded ? null : row.id)}\n className=\"mt-0.5 grid size-5 shrink-0 place-items-center rounded text-muted-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring [&_svg]:size-4\"\n >\n <ChevronIcon open={isExpanded} />\n </button>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-mono text-xs text-muted-foreground\">{row.requestId ?? row.id}</span>\n <StatusBadge variant={statusVariant(row.status)} appearance=\"dot\">\n {row.status}\n </StatusBadge>\n </div>\n <div className=\"mt-1 truncate text-sm font-medium text-foreground\">{row.failureReason}</div>\n <div className=\"mt-1 flex flex-wrap items-center gap-x-3 text-xs text-muted-foreground\">\n <span className=\"tabular-nums\">{row.attemptCount} attempts</span>\n <span aria-hidden=\"true\" className=\"text-border\">·</span>\n <span className=\"tabular-nums\">first seen {formatDateTime(row.firstSeenAt)}</span>\n </div>\n </div>\n <div className=\"flex shrink-0 items-center gap-1.5\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" disabled={replay.isPending} onClick={() => replay.mutate(row.id)}>\n Replay\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" className=\"text-destructive\" disabled={discard.isPending} onClick={() => discard.mutate(row.id)}>\n Discard\n </Button>\n </div>\n </li>\n {isExpanded && (\n <li className=\"border-t border-border bg-muted/40\">\n <DlqMessageDetailRow id={row.id} basePath={basePath} />\n </li>\n )}\n </Fragment>\n );\n })}\n </ul>\n <Pager\n label=\"Dead-letter pagination\"\n page={page}\n totalPages={totalPages}\n onPrev={() => setPage((p) => Math.max(1, p - 1))}\n onNext={() => setPage((p) => Math.min(totalPages, p + 1))}\n />\n </>\n )}\n </Card>\n </section>\n );\n}\n\n/* Decorative inline icons — `lucide-react` is not a dependency of this package. */\n\nfunction ChevronIcon({ open }: { open: boolean }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn('transition-transform motion-reduce:transition-none', open && 'rotate-90')}\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n );\n}\n\nfunction SkullIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"9\" cy=\"12\" r=\"1\" />\n <circle cx=\"15\" cy=\"12\" r=\"1\" />\n <path d=\"M8 20v2h8v-2\" />\n <path d=\"m12.5 17-.5-1-.5 1h1Z\" />\n <path d=\"M16 20a2 2 0 0 0 1.56-3.25 8 8 0 1 0-11.12 0A2 2 0 0 0 8 20\" />\n </svg>\n );\n}\n","import { useMemo, useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface CatalogEntry {\n key: string;\n locale: string;\n value: string;\n}\n\ninterface CatalogResponse {\n entries?: CatalogEntry[];\n}\n\nexport interface CatalogEditorProps {\n basePath?: string;\n className?: string;\n}\n\ninterface UpsertPayload {\n key: string;\n locale: string;\n value: string;\n}\n\ninterface DeletePayload {\n key: string;\n locale: string;\n}\n\nfunction normalize(\n data: CatalogResponse | CatalogEntry[] | Record<string, CatalogEntry> | undefined,\n): CatalogEntry[] {\n if (!data) return [];\n if (Array.isArray(data)) return data;\n if ('entries' in data && Array.isArray((data as CatalogResponse).entries)) {\n return (data as CatalogResponse).entries ?? [];\n }\n return Object.values(data as Record<string, CatalogEntry>).filter(\n (entry): entry is CatalogEntry =>\n typeof entry === 'object' &&\n entry !== null &&\n 'key' in entry &&\n 'locale' in entry &&\n 'value' in entry,\n );\n}\n\n/**\n * i18n catalog editor. Lists catalog entries with a key filter, supports inline\n * value editing, per-entry delete, and an add form. All mutations refetch and\n * surface ApiError-aware toasts.\n */\nexport function CatalogEditor({ basePath = '/api', className }: CatalogEditorProps) {\n const toast = useToast();\n const [filter, setFilter] = useState('');\n const [editingId, setEditingId] = useState<string | null>(null);\n const [editValue, setEditValue] = useState('');\n const [newKey, setNewKey] = useState('');\n const [newLocale, setNewLocale] = useState('');\n const [newValue, setNewValue] = useState('');\n\n const { data, isLoading, isError, refetch } = useApiQuery<\n CatalogResponse | CatalogEntry[] | Record<string, CatalogEntry>\n >(['i18n-catalog'], (client) => client.get(`${basePath}/i18n/catalog/export`));\n\n const onMutationError = (error: {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n }) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n\n const upsert = useApiMutation<void, UpsertPayload>(\n (client, payload) =>\n client.put(`${basePath}/i18n/catalog/entries/${encodeURIComponent(payload.key)}`, {\n locale: payload.locale,\n value: payload.value,\n }),\n {\n invalidates: [['i18n-catalog']],\n onSuccess: () => {\n toast.success('Entry saved');\n setEditingId(null);\n void refetch();\n },\n onError: onMutationError,\n },\n );\n\n const add = useApiMutation<void, UpsertPayload>(\n (client, payload) =>\n client.put(`${basePath}/i18n/catalog/entries/${encodeURIComponent(payload.key)}`, {\n locale: payload.locale,\n value: payload.value,\n }),\n {\n invalidates: [['i18n-catalog']],\n onSuccess: () => {\n toast.success('Entry added');\n setNewKey('');\n setNewLocale('');\n setNewValue('');\n void refetch();\n },\n onError: onMutationError,\n },\n );\n\n const remove = useApiMutation<void, DeletePayload>(\n (client, payload) =>\n client.delete(\n `${basePath}/i18n/catalog/entries/${encodeURIComponent(payload.key)}?locale=${encodeURIComponent(payload.locale)}`,\n ),\n {\n invalidates: [['i18n-catalog']],\n onSuccess: () => {\n toast.success('Entry removed');\n void refetch();\n },\n onError: onMutationError,\n },\n );\n\n const entries = useMemo(() => normalize(data), [data]);\n const filtered = useMemo(() => {\n const q = filter.trim().toLowerCase();\n if (!q) return entries;\n return entries.filter((e) => e.key.toLowerCase().includes(q));\n }, [entries, filter]);\n\n const onAdd = (event: React.FormEvent) => {\n event.preventDefault();\n add.mutate({ key: newKey.trim(), locale: newLocale.trim(), value: newValue });\n };\n\n const startEdit = (entry: CatalogEntry) => {\n setEditingId(`${entry.key}:${entry.locale}`);\n setEditValue(entry.value);\n };\n\n const addForm = (\n <form onSubmit={onAdd} className=\"flex flex-wrap items-end gap-3\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"catalog-new-key\" className=\"text-sm font-medium text-foreground\">\n Key\n </label>\n <input\n id=\"catalog-new-key\"\n type=\"text\"\n value={newKey}\n onChange={(e) => setNewKey(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"catalog-new-locale\" className=\"text-sm font-medium text-foreground\">\n Locale\n </label>\n <input\n id=\"catalog-new-locale\"\n type=\"text\"\n value={newLocale}\n onChange={(e) => setNewLocale(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"catalog-new-value\" className=\"text-sm font-medium text-foreground\">\n Value\n </label>\n <input\n id=\"catalog-new-value\"\n type=\"text\"\n value={newValue}\n onChange={(e) => setNewValue(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <button\n type=\"submit\"\n disabled={add.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {add.isPending ? 'Adding…' : 'Add entry'}\n </button>\n </form>\n );\n\n const filterInput = (\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"catalog-filter\" className=\"text-sm font-medium text-foreground\">\n Filter by key\n </label>\n <input\n id=\"catalog-filter\"\n type=\"text\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n );\n\n let body: React.ReactNode;\n\n if (isLoading) {\n body = (\n <div role=\"status\" aria-label=\"Loading catalog\" className=\"flex flex-col gap-2 p-4\">\n <span className=\"sr-only\">Loading catalog</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n } else if (isError) {\n body = (\n <div className=\"flex flex-col items-start gap-3 p-4\">\n <p className=\"text-sm text-foreground\">Failed to load catalog</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n } else if (filtered.length === 0) {\n body = (\n <div className=\"p-6 text-center text-sm text-muted-foreground\">\n {entries.length === 0 ? 'No catalog entries' : 'No entries match your filter'}\n </div>\n );\n } else {\n body = (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Key\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Locale\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Value\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n <span className=\"sr-only\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {filtered.map((entry) => {\n const rowId = `${entry.key}:${entry.locale}`;\n const isEditing = editingId === rowId;\n return (\n <tr key={rowId} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 font-mono text-foreground\">{entry.key}</td>\n <td className=\"px-4 py-3 text-foreground\">{entry.locale}</td>\n <td className=\"px-4 py-3 text-foreground\">\n {isEditing ? (\n <input\n type=\"text\"\n aria-label={`Value for ${entry.key} (${entry.locale})`}\n value={editValue}\n onChange={(e) => setEditValue(e.target.value)}\n className=\"w-full rounded-md border border-border bg-background px-3 py-1.5 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n ) : (\n entry.value\n )}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n {isEditing ? (\n <>\n <button\n type=\"button\"\n disabled={upsert.isPending}\n onClick={() =>\n upsert.mutate({\n key: entry.key,\n locale: entry.locale,\n value: editValue,\n })\n }\n className=\"rounded-md bg-primary px-3 py-1 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Save\n </button>\n <button\n type=\"button\"\n onClick={() => setEditingId(null)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Cancel\n </button>\n </>\n ) : (\n <>\n <button\n type=\"button\"\n onClick={() => startEdit(entry)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Edit\n </button>\n <button\n type=\"button\"\n disabled={remove.isPending}\n onClick={() => remove.mutate({ key: entry.key, locale: entry.locale })}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Delete\n </button>\n </>\n )}\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n );\n }\n\n return (\n <section aria-label=\"Catalog editor\" className={cn('flex flex-col gap-4', className)}>\n {addForm}\n {filterInput}\n {body}\n </section>\n );\n}\n","import { cn } from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\n\nexport interface MissingEntry {\n key: string;\n locale: string;\n type?: string;\n}\n\ninterface MissingResponse {\n missing?: MissingEntry[];\n}\n\nexport interface MissingTranslationsPanelProps {\n basePath?: string;\n className?: string;\n}\n\nfunction normalize(data: MissingResponse | MissingEntry[] | undefined): MissingEntry[] {\n if (Array.isArray(data)) return data;\n return data?.missing ?? [];\n}\n\n/**\n * Reports translation keys that have no value for one or more locales. An empty\n * result is the healthy state (\"No missing translations\").\n */\nexport function MissingTranslationsPanel({\n basePath = '/api',\n className,\n}: MissingTranslationsPanelProps) {\n const { data, isLoading, isError, refetch } = useApiQuery<MissingResponse | MissingEntry[]>(\n ['i18n-missing'],\n (client) => client.get(`${basePath}/i18n/catalog/missing`),\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading missing translations\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading missing translations</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load missing translations</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const rows = normalize(data);\n\n if (rows.length === 0) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No missing translations\n </div>\n );\n }\n\n return (\n <section aria-label=\"Missing translations\" className={cn('flex flex-col gap-3', className)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Key\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Locale\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Type\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row, i) => (\n <tr key={`${row.key}:${row.locale}:${i}`} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 font-mono text-foreground\">{row.key}</td>\n <td className=\"px-4 py-3 text-foreground\">{row.locale}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.type ?? '—'}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </section>\n );\n}\n","import { cn } from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\n\nexport interface FallbackEntry {\n key: string;\n requestedLocale: string;\n resolvedLocale: string;\n steps?: string[];\n}\n\ninterface FallbackResponse {\n entries?: FallbackEntry[];\n}\n\nexport interface FallbackReportPanelProps {\n basePath?: string;\n className?: string;\n}\n\nfunction normalize(data: FallbackResponse | FallbackEntry[] | undefined): FallbackEntry[] {\n if (Array.isArray(data)) return data;\n return data?.entries ?? [];\n}\n\n/**\n * Shows translation keys that resolved through locale fallback, including the\n * requested vs. resolved locale and the resolution chain when available.\n */\nexport function FallbackReportPanel({ basePath = '/api', className }: FallbackReportPanelProps) {\n const { data, isLoading, isError, refetch } = useApiQuery<FallbackResponse | FallbackEntry[]>(\n ['i18n-fallback-report'],\n (client) => client.get(`${basePath}/i18n/catalog/fallback-report`),\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading fallback report\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading fallback report</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load fallback report</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const rows = normalize(data);\n\n if (rows.length === 0) {\n return (\n <div className={cn('p-6 text-center text-sm text-muted-foreground', className)}>\n No fallbacks reported\n </div>\n );\n }\n\n return (\n <section aria-label=\"Fallback report\" className={cn('flex flex-col gap-3', className)}>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Key\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Requested\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Resolved\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Chain\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row, i) => (\n <tr key={`${row.key}:${row.requestedLocale}:${i}`} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 font-mono text-foreground\">{row.key}</td>\n <td className=\"px-4 py-3 text-foreground\">{row.requestedLocale}</td>\n <td className=\"px-4 py-3 text-foreground\">{row.resolvedLocale}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {row.steps && row.steps.length > 0 ? (\n <ol className=\"flex flex-wrap items-center gap-1\">\n {row.steps.map((step, si) => (\n <li key={`${step}:${si}`} className=\"flex items-center gap-1\">\n <span className=\"rounded bg-muted px-1.5 py-0.5 text-xs text-foreground\">\n {step}\n </span>\n {si < (row.steps?.length ?? 0) - 1 && (\n <span aria-hidden=\"true\" className=\"text-muted-foreground\">\n →\n </span>\n )}\n </li>\n ))}\n </ol>\n ) : (\n '—'\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </section>\n );\n}\n","import { useState } from 'react';\nimport { cn, formatDateTime, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface RecipientSummary {\n userId: string;\n email: string | null;\n emailVerified: boolean;\n phone: string | null;\n phoneVerified: boolean;\n locale: string | null;\n timezone: string | null;\n consentEmail: boolean;\n consentPush: boolean;\n consentSms: boolean;\n createdAt: string;\n}\n\nexport interface RecipientPage {\n items: RecipientSummary[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface RecipientAdminPanelProps {\n basePath?: string;\n className?: string;\n}\n\nconst LIMIT = 20;\n\n/**\n * Recipient search with GDPR actions. Paginated, searchable recipient table\n * with per-row data export and erase (confirmed). All mutations surface\n * ApiError-aware toasts; erase refetches the list.\n */\nexport function RecipientAdminPanel({ basePath = '/api', className }: RecipientAdminPanelProps) {\n const toast = useToast();\n const [page, setPage] = useState(1);\n const [search, setSearch] = useState('');\n const [query, setQuery] = useState('');\n\n const { data, isLoading, isError, refetch } = useApiQuery<RecipientPage>(\n ['recipients', page, query],\n (client) =>\n client.get(\n `${basePath}/v1/admin/recipients?page=${page}&limit=${LIMIT}&search=${encodeURIComponent(query)}`,\n ),\n );\n\n const onMutationError = (error: {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n }) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n\n const exportData = useApiMutation<void, string>(\n (client, userId) => client.post(`${basePath}/v1/admin/recipients/${userId}/export`, {}),\n {\n onSuccess: () => toast.success('Export ready'),\n onError: onMutationError,\n },\n );\n\n const erase = useApiMutation<void, string>(\n (client, userId) => client.delete(`${basePath}/v1/admin/recipients/${userId}/erase`),\n {\n invalidates: [['recipients']],\n onSuccess: () => {\n toast.success('Recipient erased');\n void refetch();\n },\n onError: onMutationError,\n },\n );\n\n const onSearch = (event: React.FormEvent) => {\n event.preventDefault();\n setPage(1);\n setQuery(search.trim());\n };\n\n const onErase = (userId: string) => {\n if (window.confirm('Erase all data for this recipient? This cannot be undone.')) {\n erase.mutate(userId);\n }\n };\n\n const consents = (row: RecipientSummary): string => {\n const active: string[] = [];\n if (row.consentEmail) active.push('email');\n if (row.consentPush) active.push('push');\n if (row.consentSms) active.push('sms');\n return active.length > 0 ? active.join(', ') : 'none';\n };\n\n const searchForm = (\n <form onSubmit={onSearch} className=\"flex flex-wrap items-end gap-3\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"recipient-search\" className=\"text-sm font-medium text-foreground\">\n Search recipients\n </label>\n <input\n id=\"recipient-search\"\n type=\"text\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <button\n type=\"submit\"\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Search\n </button>\n </form>\n );\n\n let body: React.ReactNode;\n\n if (isLoading) {\n body = (\n <div role=\"status\" aria-label=\"Loading recipients\" className=\"flex flex-col gap-2 p-4\">\n <span className=\"sr-only\">Loading recipients</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n } else if (isError) {\n body = (\n <div className=\"flex flex-col items-start gap-3 p-4\">\n <p className=\"text-sm text-foreground\">Failed to load recipients</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n } else {\n const rows = data?.items ?? [];\n const totalPages = data?.totalPages ?? 1;\n\n if (rows.length === 0) {\n body = <div className=\"p-6 text-center text-sm text-muted-foreground\">No recipients</div>;\n } else {\n body = (\n <>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n User\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Email\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Phone\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Consents\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n <span className=\"sr-only\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.userId} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 font-mono text-foreground\">{row.userId}</td>\n <td className=\"px-4 py-3 text-foreground\">{row.email ?? '—'}</td>\n <td className=\"px-4 py-3 text-foreground\">{row.phone ?? '—'}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{consents(row)}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {formatDateTime(row.createdAt)}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n disabled={exportData.isPending}\n onClick={() => exportData.mutate(row.userId)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Export\n </button>\n <button\n type=\"button\"\n disabled={erase.isPending}\n onClick={() => onErase(row.userId)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Erase\n </button>\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n <nav aria-label=\"Recipient pagination\" className=\"flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n disabled={page <= 1}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Previous\n </button>\n <span className=\"text-xs text-muted-foreground\">\n Page {page} of {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.min(totalPages, p + 1))}\n disabled={page >= totalPages}\n className=\"rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Next\n </button>\n </nav>\n </>\n );\n }\n }\n\n return (\n <section aria-label=\"Recipient administration\" className={cn('flex flex-col gap-4', className)}>\n {searchForm}\n {body}\n </section>\n );\n}\n","import { Fragment, useState } from 'react';\nimport { cn, formatDateTime, useToast, StatusBadge } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface WebhookEndpoint {\n id: string;\n url: string;\n events: string[];\n active: boolean;\n createdAt: string;\n}\n\ninterface WebhookListResponse {\n items?: WebhookEndpoint[];\n}\n\nexport interface WebhookDelivery {\n id: string;\n status: string;\n createdAt: string;\n}\n\ninterface WebhookDeliveryResponse {\n items?: WebhookDelivery[];\n}\n\nexport interface WebhookEndpointManagerProps {\n basePath?: string;\n className?: string;\n}\n\ninterface CreatePayload {\n url: string;\n events: string[];\n active: boolean;\n}\n\ninterface TogglePayload {\n id: string;\n active: boolean;\n}\n\nconst EVENT_TYPES = [\n 'notification.sent',\n 'notification.delivered',\n 'notification.failed',\n 'notification.bounced',\n] as const;\n\nfunction normalizeEndpoints(\n data: WebhookListResponse | WebhookEndpoint[] | undefined,\n): WebhookEndpoint[] {\n if (Array.isArray(data)) return data;\n return data?.items ?? [];\n}\n\nfunction normalizeDeliveries(\n data: WebhookDeliveryResponse | WebhookDelivery[] | undefined,\n): WebhookDelivery[] {\n if (Array.isArray(data)) return data;\n return data?.items ?? [];\n}\n\ntype ToastError = {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n};\n\nfunction toastError(toast: ReturnType<typeof useToast>, error: ToastError) {\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n}\n\n/** Lazily fetches and renders recent delivery attempts for a single endpoint. */\nfunction WebhookDeliveries({ endpointId, basePath }: { endpointId: string; basePath: string }) {\n const { data, isLoading, isError, refetch } = useApiQuery<\n WebhookDeliveryResponse | WebhookDelivery[]\n >(['webhook-deliveries', endpointId], (client) =>\n client.get(`${basePath}/webhook-endpoints/${endpointId}/deliveries`),\n );\n\n if (isLoading) {\n return (\n <div role=\"status\" aria-label=\"Loading deliveries\" className=\"flex flex-col gap-2 p-3\">\n <span className=\"sr-only\">Loading deliveries</span>\n {[0, 1].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-8 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className=\"flex flex-col items-start gap-2 p-3\">\n <p className=\"text-sm text-foreground\">Failed to load deliveries</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const rows = normalizeDeliveries(data);\n\n if (rows.length === 0) {\n return <div className=\"p-3 text-center text-sm text-muted-foreground\">No deliveries</div>;\n }\n\n return (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Delivery\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border\">\n <td className=\"py-2 pe-4 font-mono text-foreground\">{row.id}</td>\n <td className=\"px-4 py-2 text-muted-foreground\">{row.status}</td>\n <td className=\"px-4 py-2 text-muted-foreground\">{formatDateTime(row.createdAt)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n\n/**\n * Manage webhook endpoints. Lists endpoints with create form, per-row active\n * toggle, delete (confirmed), and a lazy deliveries expander. All mutations\n * refetch and surface ApiError-aware toasts.\n */\nexport function WebhookEndpointManager({\n basePath = '/api',\n className,\n}: WebhookEndpointManagerProps) {\n const toast = useToast();\n const [url, setUrl] = useState('');\n const [events, setEvents] = useState<string[]>([]);\n const [active, setActive] = useState(true);\n const [urlError, setUrlError] = useState<string | undefined>();\n const [expandedId, setExpandedId] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useApiQuery<\n WebhookListResponse | WebhookEndpoint[]\n >(['webhook-endpoints'], (client) => client.get(`${basePath}/webhook-endpoints`));\n\n const create = useApiMutation<void, CreatePayload>(\n (client, payload) => client.post(`${basePath}/webhook-endpoints`, payload),\n {\n invalidates: [['webhook-endpoints']],\n onSuccess: () => {\n toast.success('Endpoint created');\n setUrl('');\n setEvents([]);\n setActive(true);\n void refetch();\n },\n onError: (error) => toastError(toast, error),\n },\n );\n\n const toggle = useApiMutation<void, TogglePayload>(\n (client, payload) =>\n client.patch(`${basePath}/webhook-endpoints/${payload.id}`, { active: payload.active }),\n {\n invalidates: [['webhook-endpoints']],\n onSuccess: () => {\n toast.success('Endpoint updated');\n void refetch();\n },\n onError: (error) => toastError(toast, error),\n },\n );\n\n const remove = useApiMutation<void, string>(\n (client, id) => client.delete(`${basePath}/webhook-endpoints/${id}`),\n {\n invalidates: [['webhook-endpoints']],\n onSuccess: () => {\n toast.success('Endpoint deleted');\n void refetch();\n },\n onError: (error) => toastError(toast, error),\n },\n );\n\n const toggleEvent = (event: string) => {\n setEvents((prev) =>\n prev.includes(event) ? prev.filter((e) => e !== event) : [...prev, event],\n );\n };\n\n const onCreate = (event: React.FormEvent) => {\n event.preventDefault();\n const trimmed = url.trim();\n if (!trimmed) {\n setUrlError('URL is required');\n return;\n }\n if (!trimmed.startsWith('http')) {\n setUrlError('URL must start with http');\n return;\n }\n setUrlError(undefined);\n create.mutate({ url: trimmed, events, active });\n };\n\n const onDelete = (id: string) => {\n if (window.confirm('Delete this webhook endpoint?')) {\n remove.mutate(id);\n }\n };\n\n const createForm = (\n <form onSubmit={onCreate} className=\"flex flex-col gap-3\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"webhook-url\" className=\"text-sm font-medium text-foreground\">\n Endpoint URL\n </label>\n <input\n id=\"webhook-url\"\n type=\"text\"\n value={url}\n aria-invalid={urlError ? 'true' : undefined}\n aria-describedby={urlError ? 'webhook-url-error' : undefined}\n onChange={(e) => setUrl(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n {urlError && (\n <p id=\"webhook-url-error\" className=\"text-xs text-destructive\">\n {urlError}\n </p>\n )}\n </div>\n <fieldset className=\"flex flex-col gap-2\">\n <legend className=\"text-sm font-medium text-foreground\">Events</legend>\n <div className=\"flex flex-wrap gap-3\">\n {EVENT_TYPES.map((evt) => {\n const id = `webhook-event-${evt}`;\n return (\n <label\n key={evt}\n htmlFor={id}\n className=\"flex items-center gap-2 text-sm text-foreground\"\n >\n <input\n id={id}\n type=\"checkbox\"\n checked={events.includes(evt)}\n onChange={() => toggleEvent(evt)}\n className=\"focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n {evt}\n </label>\n );\n })}\n </div>\n </fieldset>\n <label htmlFor=\"webhook-active\" className=\"flex items-center gap-2 text-sm text-foreground\">\n <input\n id=\"webhook-active\"\n type=\"checkbox\"\n checked={active}\n onChange={(e) => setActive(e.target.checked)}\n className=\"focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n Active\n </label>\n <div>\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {create.isPending ? 'Creating…' : 'Create endpoint'}\n </button>\n </div>\n </form>\n );\n\n let body: React.ReactNode;\n\n if (isLoading) {\n body = (\n <div role=\"status\" aria-label=\"Loading webhook endpoints\" className=\"flex flex-col gap-2 p-4\">\n <span className=\"sr-only\">Loading webhook endpoints</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n } else if (isError) {\n body = (\n <div className=\"flex flex-col items-start gap-3 p-4\">\n <p className=\"text-sm text-foreground\">Failed to load webhook endpoints</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n } else {\n const rows = normalizeEndpoints(data);\n\n if (rows.length === 0) {\n body = (\n <div className=\"p-6 text-center text-sm text-muted-foreground\">No webhook endpoints</div>\n );\n } else {\n body = (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n URL\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Events\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Active\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Created\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n <span className=\"sr-only\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => {\n const isExpanded = expandedId === row.id;\n return (\n <Fragment key={row.id}>\n <tr className=\"border-b border-border\">\n <td className=\"py-3 pe-4 font-mono text-foreground\">{row.url}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {row.events.length > 0 ? row.events.join(', ') : '—'}\n </td>\n <td className=\"px-4 py-3\">\n <StatusBadge variant={row.active ? 'success' : 'neutral'} appearance=\"dot\">\n {row.active ? 'active' : 'inactive'}\n </StatusBadge>\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {formatDateTime(row.createdAt)}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n disabled={toggle.isPending}\n onClick={() => toggle.mutate({ id: row.id, active: !row.active })}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {row.active ? 'Disable' : 'Enable'}\n </button>\n <button\n type=\"button\"\n onClick={() => setExpandedId(isExpanded ? null : row.id)}\n aria-expanded={isExpanded}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Deliveries\n </button>\n <button\n type=\"button\"\n disabled={remove.isPending}\n onClick={() => onDelete(row.id)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Delete\n </button>\n </div>\n </td>\n </tr>\n {isExpanded && (\n <tr className=\"border-b border-border\">\n <td colSpan={5} className=\"bg-muted px-4 py-3\">\n <WebhookDeliveries endpointId={row.id} basePath={basePath} />\n </td>\n </tr>\n )}\n </Fragment>\n );\n })}\n </tbody>\n </table>\n );\n }\n }\n\n return (\n <section aria-label=\"Webhook endpoints\" className={cn('flex flex-col gap-4', className)}>\n {createForm}\n {body}\n </section>\n );\n}\n","import {\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n EmptyState,\n Skeleton,\n StatCard,\n StatusBadge,\n cn,\n formatDateTime,\n} from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\n\nexport interface OperationsChannelStat {\n channel: string;\n sends: number;\n delivered: number;\n failed: number;\n}\n\nexport interface OperationsOverviewResponse {\n windowHours: number;\n channels: OperationsChannelStat[];\n totalSends: number;\n totalDelivered: number;\n totalFailed: number;\n dlqPending: number;\n broadcastsInFlight: number;\n queueHealthy: boolean;\n generatedAt: string;\n}\n\nexport interface OperationsOverviewProps {\n basePath?: string;\n className?: string;\n}\n\n/**\n * Operations overview dashboard. Renders summary stat cards (sends / delivered\n * / failed over the reporting window), a per-channel breakdown table, and\n * health indicators (DLQ pending, broadcasts in flight, queue health).\n */\nexport function OperationsOverview({ basePath = '/api', className }: OperationsOverviewProps) {\n const { data, isLoading, isError, refetch } = useApiQuery<OperationsOverviewResponse>(\n ['operations-overview'],\n (client) => client.get(`${basePath}/v1/admin/overview`),\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading operations overview\"\n className={cn('flex flex-col gap-4', className)}\n >\n <span className=\"sr-only\">Loading operations overview</span>\n <div aria-hidden=\"true\" className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n {[0, 1, 2].map((i) => (\n <Card key={i}>\n <CardContent className=\"space-y-3 p-5\">\n <Skeleton className=\"h-3 w-24\" />\n <Skeleton className=\"h-7 w-28\" />\n </CardContent>\n </Card>\n ))}\n </div>\n <Card aria-hidden=\"true\">\n <CardContent className=\"space-y-2 p-5\">\n {[0, 1, 2, 3].map((i) => (\n <Skeleton key={i} className=\"h-10 w-full\" />\n ))}\n </CardContent>\n </Card>\n </div>\n );\n }\n\n if (isError) {\n return (\n <Card className={className}>\n <CardContent className=\"flex flex-col items-center gap-3 p-8 text-center\">\n <p className=\"text-sm text-foreground\">Failed to load operations overview</p>\n <Button type=\"button\" onClick={() => void refetch()}>\n Try again\n </Button>\n </CardContent>\n </Card>\n );\n }\n\n if (!data) {\n return <EmptyState className={className} title=\"No overview data\" />;\n }\n\n const windowHours = data.windowHours;\n const channels = data.channels ?? [];\n const dlqPending = data.dlqPending;\n\n const cards: Array<{ label: string; value: number }> = [\n { label: `Sends (${windowHours}h)`, value: data.totalSends },\n { label: `Delivered (${windowHours}h)`, value: data.totalDelivered },\n { label: `Failed (${windowHours}h)`, value: data.totalFailed },\n ];\n\n return (\n <section aria-label=\"Operations overview\" className={cn('flex flex-col gap-5', className)}>\n <div className=\"flex flex-wrap items-baseline justify-between gap-2\">\n <div>\n <h2 className=\"text-base font-semibold tracking-tight text-foreground\">\n Operations overview\n </h2>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">Last {windowHours}h</p>\n </div>\n <p className=\"text-xs text-muted-foreground\">\n Generated {formatDateTime(data.generatedAt)}\n </p>\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n {cards.map((card) => (\n <StatCard key={card.label} label={card.label} value={card.value} />\n ))}\n </div>\n\n <Card>\n <CardContent className=\"flex flex-wrap items-center gap-x-8 gap-y-3 p-5\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">DLQ pending</span>\n <StatusBadge variant={dlqPending > 0 ? 'destructive' : 'success'} appearance=\"solid\">\n {dlqPending}\n </StatusBadge>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">Broadcasts in flight</span>\n <span className=\"text-sm font-semibold tabular-nums text-foreground\">\n {data.broadcastsInFlight}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">Queue</span>\n <StatusBadge variant={data.queueHealthy ? 'success' : 'destructive'} appearance=\"solid\">\n {data.queueHealthy ? 'Healthy' : 'Unhealthy'}\n </StatusBadge>\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Channel breakdown</CardTitle>\n </CardHeader>\n <CardContent className=\"p-0\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-xs uppercase tracking-wide text-muted-foreground\">\n <th scope=\"col\" className=\"px-5 py-2.5 font-medium\">\n Channel\n </th>\n <th scope=\"col\" className=\"px-4 py-2.5 text-end font-medium\">\n Sends\n </th>\n <th scope=\"col\" className=\"px-4 py-2.5 text-end font-medium\">\n Delivered\n </th>\n <th scope=\"col\" className=\"px-4 py-2.5 text-end font-medium\">\n Failed\n </th>\n </tr>\n </thead>\n <tbody>\n {channels.length === 0 ? (\n <tr>\n <td colSpan={4} className=\"px-5 py-8 text-center text-muted-foreground\">\n No channel activity\n </td>\n </tr>\n ) : (\n channels.map((row) => (\n <tr\n key={row.channel}\n className=\"border-b border-border last:border-0 hover:bg-muted/40\"\n >\n <td className=\"px-5 py-3 font-medium text-foreground\">{row.channel}</td>\n <td className=\"px-4 py-3 text-end tabular-nums text-muted-foreground\">\n {row.sends}\n </td>\n <td className=\"px-4 py-3 text-end tabular-nums text-muted-foreground\">\n {row.delivered}\n </td>\n <td className=\"px-4 py-3 text-end tabular-nums text-muted-foreground\">\n {row.failed}\n </td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </CardContent>\n </Card>\n </section>\n );\n}\n","import { useState } from 'react';\nimport { Button, Card, EmptyState, StatusBadge, cn, formatDateTime, type StatusBadgeVariant } from '@quanticjs/react-ui';\nimport { useApiQuery } from '@quanticjs/react-query';\nimport { ErrorPanel, FIELD_CLASS, Pager, PanelHeader, SkeletonRows } from './admin-panel';\n\nexport interface DeliveryLogExplorerRow {\n id: string;\n channel: string;\n userId: string;\n recipient: string | null;\n status: string;\n provider: string | null;\n attempts: number;\n sentAt: string | null;\n createdAt: string;\n}\n\nexport interface DeliveryLogExplorerPage {\n items: DeliveryLogExplorerRow[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface DeliveryLogExplorerProps {\n basePath?: string;\n className?: string;\n}\n\ninterface Filters {\n channel: string;\n status: string;\n recipient: string;\n userId: string;\n from: string;\n to: string;\n}\n\nconst LIMIT = 20;\n\nconst EMPTY_FILTERS: Filters = {\n channel: '',\n status: '',\n recipient: '',\n userId: '',\n from: '',\n to: '',\n};\n\nfunction channelVariant(channel: string): StatusBadgeVariant {\n switch (channel) {\n case 'email':\n return 'neutral';\n case 'sms':\n return 'warning';\n default:\n return 'neutral';\n }\n}\n\n/**\n * Cross-channel delivery log explorer. Filterable by channel, status,\n * recipient, user, and date range; paginated. Recipients are masked\n * server-side. Changing any filter resets to page 1.\n */\nexport function DeliveryLogExplorer({ basePath = '/api', className }: DeliveryLogExplorerProps) {\n const [page, setPage] = useState(1);\n const [draft, setDraft] = useState<Filters>(EMPTY_FILTERS);\n const [applied, setApplied] = useState<Filters>(EMPTY_FILTERS);\n\n const queryString = (() => {\n const params = new URLSearchParams();\n params.set('page', String(page));\n params.set('limit', String(LIMIT));\n if (applied.channel) params.set('channel', applied.channel);\n if (applied.status) params.set('status', applied.status);\n if (applied.userId) params.set('userId', applied.userId);\n if (applied.recipient) params.set('recipient', applied.recipient);\n if (applied.from) params.set('from', applied.from);\n if (applied.to) params.set('to', applied.to);\n return params.toString();\n })();\n\n const { data, isLoading, isError, refetch } = useApiQuery<DeliveryLogExplorerPage>(\n ['delivery-logs', page, applied],\n (client) => client.get(`${basePath}/v1/admin/delivery-logs?${queryString}`),\n );\n\n const onApply = (event: React.FormEvent) => {\n event.preventDefault();\n setPage(1);\n setApplied({\n channel: draft.channel,\n status: draft.status.trim(),\n recipient: draft.recipient.trim(),\n userId: draft.userId.trim(),\n from: draft.from,\n to: draft.to,\n });\n };\n\n const setField = (key: keyof Filters, value: string) =>\n setDraft((prev) => ({ ...prev, [key]: value }));\n\n const rows = data?.items ?? [];\n const totalPages = data?.totalPages ?? 1;\n\n return (\n <section aria-label=\"Delivery log explorer\" className={cn('flex flex-col gap-4', className)}>\n <Card>\n <form onSubmit={onApply} className=\"flex flex-wrap items-end gap-3 p-4\" noValidate>\n <label htmlFor=\"dle-channel\" className=\"flex flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">Channel</span>\n <select\n id=\"dle-channel\"\n value={draft.channel}\n onChange={(e) => setField('channel', e.target.value)}\n className={FIELD_CLASS}\n >\n <option value=\"\">All</option>\n <option value=\"email\">Email</option>\n <option value=\"sms\">SMS</option>\n </select>\n </label>\n <label htmlFor=\"dle-status\" className=\"flex flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">Status</span>\n <input id=\"dle-status\" type=\"text\" value={draft.status} onChange={(e) => setField('status', e.target.value)} className={FIELD_CLASS} />\n </label>\n <label htmlFor=\"dle-recipient\" className=\"flex flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">Recipient</span>\n <input id=\"dle-recipient\" type=\"text\" value={draft.recipient} onChange={(e) => setField('recipient', e.target.value)} className={FIELD_CLASS} />\n </label>\n <label htmlFor=\"dle-user\" className=\"flex flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">User ID</span>\n <input id=\"dle-user\" type=\"text\" value={draft.userId} onChange={(e) => setField('userId', e.target.value)} className={FIELD_CLASS} />\n </label>\n <label htmlFor=\"dle-from\" className=\"flex flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">From</span>\n <input id=\"dle-from\" type=\"date\" value={draft.from} onChange={(e) => setField('from', e.target.value)} className={FIELD_CLASS} />\n </label>\n <label htmlFor=\"dle-to\" className=\"flex flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">To</span>\n <input id=\"dle-to\" type=\"date\" value={draft.to} onChange={(e) => setField('to', e.target.value)} className={FIELD_CLASS} />\n </label>\n <Button type=\"submit\" className=\"ms-auto\">\n Apply\n </Button>\n </form>\n </Card>\n\n <Card>\n <PanelHeader title=\"Attempts\" subtitle={!isLoading && !isError ? `${data?.total ?? rows.length} matching entries` : undefined} />\n {isLoading ? (\n <SkeletonRows label=\"Loading delivery logs\" />\n ) : isError ? (\n <ErrorPanel message=\"Failed to load delivery logs\" onRetry={() => void refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState icon={<InboxIcon />} title=\"No delivery logs\" description=\"No attempts match the current filters.\" />\n ) : (\n <>\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Channel</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Recipient</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">User</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Status</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Provider</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Attempts</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Created</th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border last:border-0 hover:bg-muted/40\">\n <td className=\"px-4 py-3\">\n <StatusBadge variant={channelVariant(row.channel)} appearance=\"dot\">\n {row.channel}\n </StatusBadge>\n </td>\n <td className=\"px-4 py-3 text-foreground\">{row.recipient ?? '—'}</td>\n <td className=\"px-4 py-3 font-mono text-foreground\">{row.userId}</td>\n <td className=\"px-4 py-3 text-foreground\">{row.status}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{row.provider ?? '—'}</td>\n <td className=\"px-4 py-3 tabular-nums text-muted-foreground\">{row.attempts}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{formatDateTime(row.createdAt)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n <Pager\n label=\"Delivery log pagination\"\n page={page}\n totalPages={totalPages}\n onPrev={() => setPage((p) => Math.max(1, p - 1))}\n onNext={() => setPage((p) => Math.min(totalPages, p + 1))}\n />\n </>\n )}\n </Card>\n </section>\n );\n}\n\n/* Decorative inline icon — `lucide-react` is not a dependency of this package. */\n\nfunction InboxIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 12h-6l-2 3h-4l-2-3H2\" />\n <path d=\"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11Z\" />\n </svg>\n );\n}\n","import { useEffect, useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface QuietHours {\n enabled: boolean;\n start: string;\n end: string;\n timezone: string;\n}\n\nexport interface QuietHoursFormProps {\n basePath?: string;\n className?: string;\n}\n\nconst DEFAULTS: QuietHours = {\n enabled: false,\n start: '22:00',\n end: '08:00',\n timezone: 'UTC',\n};\n\n/** Normalizes a loosely-typed quiet-hours payload into the strict shape. */\nfunction normalize(raw: unknown): QuietHours {\n const obj = (raw ?? {}) as Record<string, unknown>;\n return {\n enabled: typeof obj.enabled === 'boolean' ? obj.enabled : DEFAULTS.enabled,\n start:\n typeof obj.start === 'string'\n ? obj.start\n : typeof obj.startHour === 'string'\n ? obj.startHour\n : DEFAULTS.start,\n end:\n typeof obj.end === 'string'\n ? obj.end\n : typeof obj.endHour === 'string'\n ? obj.endHour\n : DEFAULTS.end,\n timezone: typeof obj.timezone === 'string' ? obj.timezone : DEFAULTS.timezone,\n };\n}\n\n/**\n * Quiet-hours configuration form. Loads the current window via GET and saves\n * via PUT. Tolerates absent/legacy fields (startHour/endHour) and falls back\n * to sensible defaults. ApiError-aware toasts on save.\n */\nexport function QuietHoursForm({ basePath = '/api', className }: QuietHoursFormProps) {\n const toast = useToast();\n const url = `${basePath}/notifications/config/quiet-hours`;\n\n const { data, isLoading, isError, refetch } = useApiQuery<unknown>(['quiet-hours'], (client) =>\n client.get(url),\n );\n\n const [form, setForm] = useState<QuietHours>(DEFAULTS);\n\n useEffect(() => {\n if (data !== undefined) {\n setForm(normalize(data));\n }\n }, [data]);\n\n const save = useApiMutation<unknown, QuietHours>((client, payload) => client.put(url, payload), {\n invalidates: [['quiet-hours']],\n onSuccess: () => toast.success('Quiet hours saved'),\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n });\n\n const onSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n save.mutate(form);\n };\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading quiet hours\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading quiet hours</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load quiet hours</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n return (\n <form onSubmit={onSubmit} className={cn('flex flex-col gap-4', className)} noValidate>\n <h2 className=\"text-sm font-semibold text-foreground\">Quiet hours</h2>\n\n <label className=\"flex items-center gap-2 text-sm text-foreground\">\n <input\n type=\"checkbox\"\n checked={form.enabled}\n onChange={(e) => setForm((prev) => ({ ...prev, enabled: e.target.checked }))}\n className=\"focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n Enable quiet hours\n </label>\n\n <div className=\"flex flex-wrap gap-4\">\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"qh-start\" className=\"text-sm font-medium text-foreground\">\n Start\n </label>\n <input\n id=\"qh-start\"\n type=\"time\"\n value={form.start}\n onChange={(e) => setForm((prev) => ({ ...prev, start: e.target.value }))}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"qh-end\" className=\"text-sm font-medium text-foreground\">\n End\n </label>\n <input\n id=\"qh-end\"\n type=\"time\"\n value={form.end}\n onChange={(e) => setForm((prev) => ({ ...prev, end: e.target.value }))}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"qh-tz\" className=\"text-sm font-medium text-foreground\">\n Timezone\n </label>\n <input\n id=\"qh-tz\"\n type=\"text\"\n value={form.timezone}\n onChange={(e) => setForm((prev) => ({ ...prev, timezone: e.target.value }))}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n </div>\n\n <div>\n <button\n type=\"submit\"\n disabled={save.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {save.isPending ? 'Saving…' : 'Save'}\n </button>\n </div>\n </form>\n );\n}\n","import { useEffect, useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface Cap {\n type: string;\n maxPerDay: number;\n}\n\nexport interface FrequencyCapTableProps {\n basePath?: string;\n className?: string;\n}\n\n/** Normalizes an array | { caps } payload (with limit/maxPerDay/perDay) into Cap[]. */\nfunction normalize(raw: unknown): Cap[] {\n const list = Array.isArray(raw)\n ? raw\n : Array.isArray((raw as Record<string, unknown>)?.caps)\n ? ((raw as Record<string, unknown>).caps as unknown[])\n : [];\n return list.map((entry) => {\n const obj = (entry ?? {}) as Record<string, unknown>;\n const max =\n typeof obj.maxPerDay === 'number'\n ? obj.maxPerDay\n : typeof obj.limit === 'number'\n ? obj.limit\n : typeof obj.perDay === 'number'\n ? obj.perDay\n : 0;\n return { type: typeof obj.type === 'string' ? obj.type : '', maxPerDay: max };\n });\n}\n\n/**\n * Frequency-cap editor. Loads the current per-type caps via GET, renders an\n * editable table with add/remove rows, and saves the full list via PUT.\n * Tolerates array | { caps } shapes and limit/maxPerDay/perDay field names.\n */\nexport function FrequencyCapTable({ basePath = '/api', className }: FrequencyCapTableProps) {\n const toast = useToast();\n const url = `${basePath}/notifications/config/frequency-cap`;\n\n const { data, isLoading, isError, refetch } = useApiQuery<unknown>(['frequency-cap'], (client) =>\n client.get(url),\n );\n\n const [caps, setCaps] = useState<Cap[]>([]);\n const [newType, setNewType] = useState('');\n const [newMax, setNewMax] = useState(0);\n\n useEffect(() => {\n if (data !== undefined) {\n setCaps(normalize(data));\n }\n }, [data]);\n\n const save = useApiMutation<unknown, { caps: Cap[] }>(\n (client, payload) => client.put(url, payload),\n {\n invalidates: [['frequency-cap']],\n onSuccess: () => toast.success('Frequency caps saved'),\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n const updateRow = (index: number, value: number) =>\n setCaps((prev) => prev.map((cap, i) => (i === index ? { ...cap, maxPerDay: value } : cap)));\n\n const removeRow = (index: number) => setCaps((prev) => prev.filter((_, i) => i !== index));\n\n const addRow = (event: React.FormEvent) => {\n event.preventDefault();\n const type = newType.trim();\n if (!type) return;\n setCaps((prev) => [...prev, { type, maxPerDay: newMax }]);\n setNewType('');\n setNewMax(0);\n };\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading frequency caps\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading frequency caps</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load frequency caps</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n return (\n <section aria-label=\"Frequency caps\" className={cn('flex flex-col gap-4', className)}>\n <h2 className=\"text-sm font-semibold text-foreground\">Frequency caps</h2>\n\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"py-2 pe-4 font-medium\">\n Type\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n Max per day\n </th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">\n <span className=\"sr-only\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {caps.map((cap, index) => {\n const inputId = `cap-${index}`;\n return (\n <tr key={`${cap.type}-${index}`} className=\"border-b border-border\">\n <td className=\"py-3 pe-4 text-foreground\">{cap.type}</td>\n <td className=\"px-4 py-3\">\n <label htmlFor={inputId} className=\"sr-only\">\n Max per day for {cap.type}\n </label>\n <input\n id={inputId}\n type=\"number\"\n min={0}\n value={cap.maxPerDay}\n onChange={(e) => updateRow(index, Number(e.target.value))}\n className=\"w-24 rounded-md border border-border bg-background px-3 py-1.5 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </td>\n <td className=\"px-4 py-3\">\n <button\n type=\"button\"\n onClick={() => removeRow(index)}\n className=\"rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Remove\n </button>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n\n <form onSubmit={addRow} className=\"flex flex-wrap items-end gap-3\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"cap-new-type\" className=\"text-sm font-medium text-foreground\">\n New type\n </label>\n <input\n id=\"cap-new-type\"\n type=\"text\"\n value={newType}\n onChange={(e) => setNewType(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"cap-new-max\" className=\"text-sm font-medium text-foreground\">\n Max per day\n </label>\n <input\n id=\"cap-new-max\"\n type=\"number\"\n min={0}\n value={newMax}\n onChange={(e) => setNewMax(Number(e.target.value))}\n className=\"w-24 rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <button\n type=\"submit\"\n className=\"rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Add\n </button>\n </form>\n\n <div>\n <button\n type=\"button\"\n disabled={save.isPending}\n onClick={() => save.mutate({ caps })}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {save.isPending ? 'Saving…' : 'Save'}\n </button>\n </div>\n </section>\n );\n}\n","import { useEffect, useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface TenantConfig {\n notificationTypes: string[];\n immediateEmailTypes: string[];\n}\n\nexport interface TenantConfigFormProps {\n basePath?: string;\n className?: string;\n}\n\n/** Normalizes the tenant-config payload, defaulting both lists to []. */\nfunction normalize(raw: unknown): TenantConfig {\n const obj = (raw ?? {}) as Record<string, unknown>;\n const toList = (value: unknown): string[] =>\n Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string') : [];\n return {\n notificationTypes: toList(obj.notificationTypes),\n immediateEmailTypes: toList(obj.immediateEmailTypes),\n };\n}\n\ninterface TagEditorProps {\n id: string;\n label: string;\n values: string[];\n onAdd: (value: string) => void;\n onRemove: (value: string) => void;\n}\n\nfunction TagEditor({ id, label, values, onAdd, onRemove }: TagEditorProps) {\n const [draft, setDraft] = useState('');\n\n const add = (event: React.FormEvent) => {\n event.preventDefault();\n const value = draft.trim();\n if (!value) return;\n onAdd(value);\n setDraft('');\n };\n\n return (\n <div className=\"flex flex-col gap-2\">\n <span className=\"text-sm font-medium text-foreground\">{label}</span>\n <ul className=\"flex flex-wrap gap-2\">\n {values.length === 0 ? (\n <li className=\"text-sm text-muted-foreground\">None</li>\n ) : (\n values.map((value) => (\n <li\n key={value}\n className=\"flex items-center gap-1 rounded-md border border-border bg-card px-2 py-1 text-sm text-foreground\"\n >\n {value}\n <button\n type=\"button\"\n aria-label={`Remove ${value}`}\n onClick={() => onRemove(value)}\n className=\"rounded text-muted-foreground hover:text-destructive focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n ×\n </button>\n </li>\n ))\n )}\n </ul>\n <form onSubmit={add} className=\"flex items-end gap-2\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor={id} className=\"sr-only\">\n Add to {label}\n </label>\n <input\n id={id}\n type=\"text\"\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n className=\"rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n </div>\n <button\n type=\"submit\"\n className=\"rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Add\n </button>\n </form>\n </div>\n );\n}\n\n/**\n * Tenant notification-config form. Edits the set of notification types and the\n * subset enabled for immediate email. Enforces (matching the backend rule)\n * that immediateEmailTypes is a subset of notificationTypes.\n */\nexport function TenantConfigForm({ basePath = '/api', className }: TenantConfigFormProps) {\n const toast = useToast();\n const url = `${basePath}/admin/notification-config`;\n\n const { data, isLoading, isError, refetch } = useApiQuery<unknown>(['tenant-config'], (client) =>\n client.get(url),\n );\n\n const [config, setConfig] = useState<TenantConfig>({\n notificationTypes: [],\n immediateEmailTypes: [],\n });\n const [subsetError, setSubsetError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (data !== undefined) {\n setConfig(normalize(data));\n }\n }, [data]);\n\n const save = useApiMutation<unknown, TenantConfig>(\n (client, payload) => client.put(url, payload),\n {\n invalidates: [['tenant-config']],\n onSuccess: () => toast.success('Configuration saved'),\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n const addType = (value: string) =>\n setConfig((prev) =>\n prev.notificationTypes.includes(value)\n ? prev\n : { ...prev, notificationTypes: [...prev.notificationTypes, value] },\n );\n\n const removeType = (value: string) =>\n setConfig((prev) => ({\n ...prev,\n notificationTypes: prev.notificationTypes.filter((t) => t !== value),\n }));\n\n const addImmediate = (value: string) =>\n setConfig((prev) =>\n prev.immediateEmailTypes.includes(value)\n ? prev\n : { ...prev, immediateEmailTypes: [...prev.immediateEmailTypes, value] },\n );\n\n const removeImmediate = (value: string) =>\n setConfig((prev) => ({\n ...prev,\n immediateEmailTypes: prev.immediateEmailTypes.filter((t) => t !== value),\n }));\n\n const onSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n const invalid = config.immediateEmailTypes.filter((t) => !config.notificationTypes.includes(t));\n if (invalid.length > 0) {\n setSubsetError(\n `Immediate email types must be a subset of notification types. Not allowed: ${invalid.join(', ')}`,\n );\n return;\n }\n setSubsetError(undefined);\n save.mutate(config);\n };\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading tenant configuration\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading tenant configuration</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load tenant configuration</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const errorId = 'tenant-config-subset-error';\n\n return (\n <form\n onSubmit={onSubmit}\n className={cn('flex flex-col gap-5', className)}\n noValidate\n aria-invalid={subsetError ? 'true' : undefined}\n aria-describedby={subsetError ? errorId : undefined}\n >\n <h2 className=\"text-sm font-semibold text-foreground\">Notification configuration</h2>\n\n <TagEditor\n id=\"tc-notification-types\"\n label=\"Notification types\"\n values={config.notificationTypes}\n onAdd={addType}\n onRemove={removeType}\n />\n\n <TagEditor\n id=\"tc-immediate-email-types\"\n label=\"Immediate email types\"\n values={config.immediateEmailTypes}\n onAdd={addImmediate}\n onRemove={removeImmediate}\n />\n\n {subsetError && (\n <p id={errorId} className=\"text-xs text-destructive\">\n {subsetError}\n </p>\n )}\n\n <div>\n <button\n type=\"submit\"\n disabled={save.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {save.isPending ? 'Saving…' : 'Save'}\n </button>\n </div>\n </form>\n );\n}\n","import { useEffect, useState } from 'react';\nimport { cn, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface TrackingConfig {\n openTrackingEnabled: boolean;\n clickTrackingEnabled: boolean;\n}\n\nexport interface TrackingConfigFormProps {\n basePath?: string;\n className?: string;\n}\n\n/** Normalizes the tracking-config payload, tolerating opensEnabled/clicksEnabled. */\nfunction normalize(raw: unknown): TrackingConfig {\n const obj = (raw ?? {}) as Record<string, unknown>;\n const bool = (...keys: string[]): boolean => {\n for (const key of keys) {\n if (typeof obj[key] === 'boolean') return obj[key] as boolean;\n }\n return false;\n };\n return {\n openTrackingEnabled: bool('openTrackingEnabled', 'opensEnabled'),\n clickTrackingEnabled: bool('clickTrackingEnabled', 'clicksEnabled'),\n };\n}\n\n/**\n * Email tracking-config form. Loads open/click tracking flags via GET and\n * persists them via POST. Tolerates absent or legacy field names and defaults\n * both flags to off. ApiError-aware toasts on save.\n */\nexport function TrackingConfigForm({ basePath = '/api', className }: TrackingConfigFormProps) {\n const toast = useToast();\n const url = `${basePath}/analytics/notifications/tracking-config`;\n\n const { data, isLoading, isError, refetch } = useApiQuery<unknown>(\n ['tracking-config'],\n (client) => client.get(url),\n );\n\n const [form, setForm] = useState<TrackingConfig>({\n openTrackingEnabled: false,\n clickTrackingEnabled: false,\n });\n\n useEffect(() => {\n if (data !== undefined) {\n setForm(normalize(data));\n }\n }, [data]);\n\n const save = useApiMutation<unknown, TrackingConfig>(\n (client, payload) => client.post(url, payload),\n {\n invalidates: [['tracking-config']],\n onSuccess: () => toast.success('Tracking configuration saved'),\n onError: (error) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n }),\n },\n );\n\n const onSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n save.mutate(form);\n };\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading tracking configuration\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading tracking configuration</span>\n {[0, 1].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load tracking configuration</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n return (\n <form onSubmit={onSubmit} className={cn('flex flex-col gap-4', className)} noValidate>\n <h2 className=\"text-sm font-semibold text-foreground\">Tracking configuration</h2>\n\n <label className=\"flex items-center gap-2 text-sm text-foreground\">\n <input\n type=\"checkbox\"\n checked={form.openTrackingEnabled}\n onChange={(e) => setForm((prev) => ({ ...prev, openTrackingEnabled: e.target.checked }))}\n className=\"focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n Open tracking\n </label>\n\n <label className=\"flex items-center gap-2 text-sm text-foreground\">\n <input\n type=\"checkbox\"\n checked={form.clickTrackingEnabled}\n onChange={(e) => setForm((prev) => ({ ...prev, clickTrackingEnabled: e.target.checked }))}\n className=\"focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n />\n Click tracking\n </label>\n\n <div>\n <button\n type=\"submit\"\n disabled={save.isPending}\n className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {save.isPending ? 'Saving…' : 'Save'}\n </button>\n </div>\n </form>\n );\n}\n","/**\n * NOTE: The backend does NOT yet expose the `/v1/admin/api-keys` endpoint.\n * This component targets that contract so it is ready when the endpoint lands.\n * Until then the list query will 404 and the component renders its error state\n * (\"Failed to load API keys\" + Try again) gracefully.\n */\nimport { useState } from 'react';\nimport { Button, Card, EmptyState, StatusBadge, cn, formatDateTime, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\nimport { ErrorPanel, FIELD_CLASS, PanelHeader, SkeletonRows } from './admin-panel';\n\nexport interface ApiKey {\n id: string;\n name: string;\n prefix?: string;\n /** Bound application slug (SPEC-application-scoping); null/absent = unscoped. */\n applicationKey?: string | null;\n createdAt: string;\n lastUsedAt?: string | null;\n revoked?: boolean;\n}\n\nexport interface ApiKeyCreateResponse {\n id?: string;\n name?: string;\n key?: string;\n secret?: string;\n}\n\nexport interface ApiKeyManagerProps {\n basePath?: string;\n className?: string;\n}\n\n/** Normalizes an array | { items } payload into ApiKey[]. */\nfunction normalize(raw: unknown): ApiKey[] {\n const list = Array.isArray(raw)\n ? raw\n : Array.isArray((raw as Record<string, unknown>)?.items)\n ? ((raw as Record<string, unknown>).items as unknown[])\n : [];\n return list as ApiKey[];\n}\n\n/**\n * API key manager. Lists keys, creates new keys (surfacing the one-time secret\n * in a toast), and revokes keys (confirmed). All mutations surface\n * ApiError-aware toasts. See file-level note re: backend availability.\n */\nexport function ApiKeyManager({ basePath = '/api', className }: ApiKeyManagerProps) {\n const toast = useToast();\n const url = `${basePath}/v1/admin/api-keys`;\n\n const { data, isLoading, isError, refetch } = useApiQuery<unknown>(['api-keys'], (client) =>\n client.get(url),\n );\n\n const [name, setName] = useState('');\n const [applicationKey, setApplicationKey] = useState('');\n\n const onMutationError = (error: {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n }) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n\n const create = useApiMutation<ApiKeyCreateResponse, { name: string; applicationKey?: string }>(\n (client, vars) =>\n client.post(url, {\n name: vars.name,\n ...(vars.applicationKey ? { applicationKey: vars.applicationKey } : {}),\n }),\n {\n invalidates: [['api-keys']],\n onSuccess: (result) => {\n const secret = result?.key ?? result?.secret;\n if (secret) {\n toast.success('API key created — copy it now', {\n description: `This secret is shown only once: ${secret}`,\n });\n } else {\n toast.success('API key created');\n }\n setName('');\n setApplicationKey('');\n },\n onError: onMutationError,\n },\n );\n\n const revoke = useApiMutation<void, string>((client, id) => client.delete(`${url}/${id}`), {\n invalidates: [['api-keys']],\n onSuccess: () => {\n toast.success('API key revoked');\n void refetch();\n },\n onError: onMutationError,\n });\n\n const onCreate = (event: React.FormEvent) => {\n event.preventDefault();\n const trimmed = name.trim();\n if (!trimmed) return;\n create.mutate({ name: trimmed, applicationKey: applicationKey.trim() || undefined });\n };\n\n const onRevoke = (id: string) => {\n if (window.confirm('Revoke this API key? Applications using it will lose access.')) {\n revoke.mutate(id);\n }\n };\n\n const rows = normalize(data);\n\n return (\n <section aria-label=\"API key management\" className={cn('flex flex-col gap-4', className)}>\n <Card>\n <form onSubmit={onCreate} className=\"flex flex-wrap items-end gap-3 p-4\" noValidate>\n <label className=\"flex flex-1 flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">New key name</span>\n <input type=\"text\" value={name} onChange={(e) => setName(e.target.value)} className={FIELD_CLASS} />\n </label>\n <label className=\"flex flex-1 flex-col gap-1 text-sm\">\n <span className=\"font-medium text-foreground\">Application (optional)</span>\n <input\n type=\"text\"\n value={applicationKey}\n onChange={(e) => setApplicationKey(e.target.value)}\n placeholder=\"delivery-hub\"\n className={FIELD_CLASS}\n />\n </label>\n <Button type=\"submit\" disabled={create.isPending}>\n {create.isPending ? 'Creating…' : 'Create key'}\n </Button>\n </form>\n </Card>\n\n <Card>\n <PanelHeader title=\"Keys\" subtitle={!isLoading && !isError ? `${rows.length} keys` : undefined} />\n {isLoading ? (\n <SkeletonRows label=\"Loading API keys\" />\n ) : isError ? (\n <ErrorPanel message=\"Failed to load API keys\" onRetry={() => void refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState icon={<KeyIcon />} title=\"No API keys\" description=\"Create a key to get started.\" />\n ) : (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Name</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Prefix</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Application</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Status</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Created</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\">Last used</th>\n <th scope=\"col\" className=\"px-4 py-2 font-medium\"><span className=\"sr-only\">Actions</span></th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} className=\"border-b border-border last:border-0 hover:bg-muted/40\">\n <td className=\"px-4 py-3 text-foreground\">{row.name}</td>\n <td className=\"px-4 py-3 font-mono text-muted-foreground\">{row.prefix ?? '—'}</td>\n <td className=\"px-4 py-3 font-mono text-muted-foreground\">{row.applicationKey ?? '—'}</td>\n <td className=\"px-4 py-3\">\n <StatusBadge variant={row.revoked ? 'destructive' : 'success'}>\n {row.revoked ? 'Revoked' : 'Active'}\n </StatusBadge>\n </td>\n <td className=\"px-4 py-3 text-muted-foreground\">{formatDateTime(row.createdAt)}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {row.lastUsedAt ? formatDateTime(row.lastUsedAt) : '—'}\n </td>\n <td className=\"px-4 py-3 text-end\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-destructive\"\n disabled={revoke.isPending || row.revoked}\n onClick={() => onRevoke(row.id)}\n >\n Revoke\n </Button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </Card>\n </section>\n );\n}\n\n/* Decorative inline icon — `lucide-react` is not a dependency of this package. */\n\nfunction KeyIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4\" />\n <path d=\"m21 2-9.6 9.6\" />\n <circle cx=\"7.5\" cy=\"15.5\" r=\"5.5\" />\n </svg>\n );\n}\n","import { useState } from 'react';\nimport { cn, formatDateTime, StatusBadge, useToast } from '@quanticjs/react-ui';\nimport { useApiMutation, useApiQuery } from '@quanticjs/react-query';\n\nexport interface Application {\n id: string;\n key: string;\n displayName: string;\n description: string | null;\n status: 'active' | 'disabled';\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface ApplicationRegistryPanelProps {\n /** API path prefix (BFF). Endpoints are mounted at `${basePath}/admin/applications`. */\n basePath?: string;\n className?: string;\n}\n\ninterface MutationError {\n isServerError: boolean;\n title: string;\n detail?: string;\n correlationId?: string;\n}\n\n/** Normalizes an array | { items } payload into Application[]. */\nfunction normalize(raw: unknown): Application[] {\n const list = Array.isArray(raw)\n ? raw\n : Array.isArray((raw as Record<string, unknown>)?.items)\n ? ((raw as Record<string, unknown>).items as unknown[])\n : [];\n return list as Application[];\n}\n\n/**\n * Global application registry manager (SPEC-application-scoping-and-registry).\n * Lists registered applications, registers new ones, and enables/disables them.\n * Platform-admin only (the backend gates `notification:platform-admin`). All\n * mutations surface ApiError-aware toasts.\n */\nexport function ApplicationRegistryPanel({\n basePath = '/api',\n className,\n}: ApplicationRegistryPanelProps) {\n const toast = useToast();\n const url = `${basePath}/admin/applications`;\n\n const { data, isLoading, isError, refetch } = useApiQuery<unknown>(['applications'], (client) =>\n client.get(url),\n );\n\n const [key, setKey] = useState('');\n const [displayName, setDisplayName] = useState('');\n const [description, setDescription] = useState('');\n\n const onMutationError = (error: MutationError) =>\n toast.error(error.isServerError ? 'Something went wrong' : error.title, {\n description: error.isServerError\n ? `Please try again. (ref: ${error.correlationId ?? 'unknown'})`\n : `${error.detail ?? ''} (ref: ${error.correlationId ?? 'unknown'})`,\n });\n\n const register = useApiMutation<\n Application,\n { key: string; displayName: string; description?: string }\n >((client, body) => client.post(url, body), {\n invalidates: [['applications']],\n onSuccess: () => {\n toast.success('Application registered');\n setKey('');\n setDisplayName('');\n setDescription('');\n },\n onError: onMutationError,\n });\n\n const setStatus = useApiMutation<\n Application,\n { key: string; status: 'active' | 'disabled' }\n >((client, body) => client.patch(`${url}/${body.key}`, { status: body.status }), {\n invalidates: [['applications']],\n onSuccess: () => {\n toast.success('Application updated');\n void refetch();\n },\n onError: onMutationError,\n });\n\n const onRegister = (event: React.FormEvent) => {\n event.preventDefault();\n const k = key.trim();\n const name = displayName.trim();\n if (!k || !name) return;\n register.mutate({ key: k, displayName: name, description: description.trim() || undefined });\n };\n\n const registerForm = (\n <form onSubmit={onRegister} className=\"flex flex-wrap items-end gap-3\" noValidate>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"application-key\" className=\"text-sm font-medium text-foreground\">\n Key (slug)\n </label>\n <input\n id=\"application-key\"\n type=\"text\"\n value={key}\n onChange={(e) => setKey(e.target.value)}\n placeholder=\"delivery-hub\"\n className=\"rounded border border-border bg-background px-3 py-1.5 text-sm text-foreground\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"application-name\" className=\"text-sm font-medium text-foreground\">\n Display name\n </label>\n <input\n id=\"application-name\"\n type=\"text\"\n value={displayName}\n onChange={(e) => setDisplayName(e.target.value)}\n placeholder=\"DeliveryHub\"\n className=\"rounded border border-border bg-background px-3 py-1.5 text-sm text-foreground\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor=\"application-description\" className=\"text-sm font-medium text-foreground\">\n Description (optional)\n </label>\n <input\n id=\"application-description\"\n type=\"text\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n className=\"rounded border border-border bg-background px-3 py-1.5 text-sm text-foreground\"\n />\n </div>\n <button\n type=\"submit\"\n disabled={register.isPending}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n Register\n </button>\n </form>\n );\n\n if (isLoading) {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading applications\"\n className={cn('flex flex-col gap-2 p-4', className)}\n >\n <span className=\"sr-only\">Loading applications</span>\n {[0, 1, 2].map((i) => (\n <div key={i} aria-hidden=\"true\" className=\"h-10 animate-pulse rounded bg-muted\" />\n ))}\n </div>\n );\n }\n\n if (isError) {\n return (\n <div className={cn('flex flex-col items-start gap-3 p-4', className)}>\n <p className=\"text-sm text-foreground\">Failed to load applications</p>\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n >\n Try again\n </button>\n </div>\n );\n }\n\n const apps = normalize(data);\n\n return (\n <section aria-label=\"Applications\" className={cn('flex flex-col gap-4 p-4', className)}>\n {registerForm}\n\n {apps.length === 0 ? (\n <p className=\"p-6 text-center text-sm text-muted-foreground\">No applications registered</p>\n ) : (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border text-start text-muted-foreground\">\n <th className=\"py-2 font-medium\">Key</th>\n <th className=\"py-2 font-medium\">Name</th>\n <th className=\"py-2 font-medium\">Status</th>\n <th className=\"py-2 font-medium\">Created</th>\n <th className=\"py-2 font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {apps.map((app) => (\n <tr key={app.id} className=\"border-b border-border\">\n <td className=\"py-2 font-mono text-foreground\">{app.key}</td>\n <td className=\"py-2 text-foreground\">{app.displayName}</td>\n <td className=\"py-2\">\n <StatusBadge variant={app.status === 'active' ? 'success' : 'neutral'}>\n {app.status}\n </StatusBadge>\n </td>\n <td className=\"py-2 text-muted-foreground\">{formatDateTime(app.createdAt)}</td>\n <td className=\"py-2\">\n <button\n type=\"button\"\n disabled={setStatus.isPending}\n onClick={() =>\n setStatus.mutate({\n key: app.key,\n status: app.status === 'active' ? 'disabled' : 'active',\n })\n }\n className=\"text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50\"\n >\n {app.status === 'active' ? 'Disable' : 'Enable'}\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </section>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,gBAAmE;;;ACAnE,mBAAuF;AACvF,yBAA+B;AAC/B,oBAAgC;AAkH5B;AAzGJ,IAAM,sBAAkB,4BAAoC,EAAE,QAAQ,MAAM,QAAQ,WAAW,CAAC;AA0BzF,SAAS,6BAA6B;AAAA,EAC3C,YAAY;AAAA,EACZ,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAAsC;AACpC,QAAM,kBAAc,mCAAe;AACnC,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAwB,IAAI;AACxD,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAyB,WAAW,aAAa,cAAc;AAC3F,QAAM,uBAAmB,qBAAmD,oBAAI,IAAI,CAAC;AAErF,8BAAU,MAAM;AACd,QAAI,UAAU;AACZ,gBAAU,UAAU;AACpB;AAAA,IACF;AAEA,UAAM,qBAAqB,CAAC,QAA4B;AACtD,YAAM,WAAW,KAAK,UAAU,GAAG;AACnC,UAAI,iBAAiB,QAAQ,IAAI,QAAQ,EAAG;AAC5C,WAAK,YAAY,kBAAkB,EAAE,UAAU,IAAiB,CAAC;AACjE,YAAM,QAAQ,WAAW,MAAM,iBAAiB,QAAQ,OAAO,QAAQ,GAAG,GAAG;AAC7E,uBAAiB,QAAQ,IAAI,UAAU,KAAK;AAAA,IAC9C;AAEA,UAAM,QAAI,kBAAG,GAAG,SAAS,aAAa;AAAA,MACpC,iBAAiB;AAAA,MACjB,YAAY,CAAC,WAAW;AAAA,MACxB,mBAAmB;AAAA,MACnB,sBAAsB;AAAA,MACtB,qBAAqB;AAAA,IACvB,CAAC;AACD,cAAU,CAAC;AAEX,MAAE,GAAG,WAAW,MAAM;AACpB,gBAAU,WAAW;AAErB,WAAK,YAAY,kBAAkB,EAAE,UAAU,CAAC,eAAe,EAAE,CAAC;AAAA,IACpE,CAAC;AAED,MAAE,GAAG,oBAAoB,CAAC,YAAwC;AAGhE,YAAM,aAAa,SAAS,SAAS;AACrC,UAAI,SAAS,cAAc,eAAe,MAAO;AACjD,yBAAmB,CAAC,eAAe,CAAC;AACpC,yBAAmB,CAAC,iBAAiB,cAAc,CAAC;AAAA,IACtD,CAAC;AAED,MAAE,GAAG,wBAAwB,MAAM;AACjC,yBAAmB,CAAC,iBAAiB,cAAc,CAAC;AAAA,IACtD,CAAC;AAED,MAAE,GAAG,GAAG,qBAAqB,MAAM,UAAU,cAAc,CAAC;AAE5D,MAAE,GAAG,cAAc,CAAC,WAAmB;AAErC,UAAI,WAAW,wBAAwB;AACrC,UAAE,GAAG,KAAK,eAAe;AACzB,kBAAU,UAAU;AACpB;AAAA,MACF;AACA,gBAAU,cAAc;AAAA,IAC1B,CAAC;AAED,MAAE,GAAG,iBAAiB,MAAM,UAAU,cAAc,CAAC;AAErD,UAAM,SAAS,iBAAiB;AAChC,WAAO,MAAM;AACX,iBAAW,KAAK,OAAO,OAAO,EAAG,cAAa,CAAC;AAC/C,aAAO,MAAM;AACb,QAAE,WAAW;AACb,gBAAU,IAAI;AACd,gBAAU,cAAc;AAAA,IAC1B;AAAA,EAEF,GAAG,CAAC,UAAU,WAAW,KAAK,CAAC;AAE/B,SACE,4CAAC,gBAAgB,UAAhB,EAAyB,OAAO,EAAE,QAAQ,OAAO,GAAI,UAAS;AAEnE;AAEO,SAAS,qBAA2C;AACzD,aAAO,yBAAW,eAAe;AACnC;;;ADrCM,IAAAC,sBAAA;AA3DN,IAAM,iBAAqC;AAAA,EACzC,OAAO;AAAA,EACP,UAAU;AAAA,EACV,gBAAgB;AAClB;AAEA,IAAM,gCAA4B,6BAAkC,cAAc;AAO3E,SAAS,wBAA4C;AAC1D,aAAO,0BAAW,yBAAyB;AAC7C;AA6BO,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AACF,GAA8B;AAC5B,QAAM,aAAS;AAAA,IACb,OAAO,EAAE,OAAO,UAAU,eAAe;AAAA,IACzC,CAAC,OAAO,UAAU,cAAc;AAAA,EAClC;AAEA,SACE,6CAAC,0BAA0B,UAA1B,EAAmC,OAAO,QACzC,uDAAC,gCAA6B,OAAc,WAAsB,UAC/D,UACH,GACF;AAEJ;;;AE1FA,IAAAC,gBAA6C;AAC7C,IAAAC,sBAA4C;AAC5C,sBAA6B;AA8GnB,IAAAC,sBAAA;AAnFV,SAAS,YAAY,MAAsB;AACzC,QAAM,WAAW,KAAK,QAAQ,SAAS,EAAE,EAAE,QAAQ,MAAM,GAAG;AAC5D,SAAO,SAAS,OAAO,CAAC,EAAE,YAAY,IAAI,SAAS,MAAM,CAAC;AAC5D;AAEA,SAAS,OAAO,OAAgD;AAC9D,QAAM,SAAS,oBAAI,IAAsB;AACzC,aAAW,QAAQ,OAAO;AACxB,UAAM,MAAM,OAAO,IAAI,KAAK,IAAI,KAAK;AAAA,MACnC,MAAM,KAAK;AAAA,MACX,cAAc;AAAA,MACd,cAAc;AAAA,MACd,QAAQ;AAAA,IACV;AACA,QAAI,KAAK,YAAY,SAAS;AAC5B,UAAI,eAAe,KAAK;AAAA,IAC1B,OAAO;AACL,UAAI,eAAe,KAAK;AACxB,UAAI,SAAS,KAAK;AAAA,IACpB;AACA,WAAO,IAAI,KAAK,MAAM,GAAG;AAAA,EAC3B;AACA,SAAO,CAAC,GAAG,OAAO,OAAO,CAAC;AAC5B;AAEA,SAAS,UAAU,MAKhB;AACD,SAAO,KAAK,QAAQ,CAAC,QAAQ;AAAA,IAC3B,EAAE,SAAS,SAAkB,MAAM,IAAI,MAAM,SAAS,IAAI,aAAa;AAAA,IACvE,EAAE,SAAS,SAAkB,MAAM,IAAI,MAAM,SAAS,IAAI,cAAc,QAAQ,IAAI,OAAO;AAAA,EAC7F,CAAC;AACH;AAQO,SAAS,wBAAwB;AAAA,EACtC,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAAiC;AAC/B,QAAM,YAAQ,0BAAS;AACvB,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,iBAAiB,aAAa;AAAA,IAC/B,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,cAAc;AAAA,EAClD;AAEA,QAAM,iBAAa,uBAAQ,MAAO,OAAO,OAAO,IAAI,IAAI,CAAC,GAAI,CAAC,IAAI,CAAC;AACnE,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAqB,UAAU;AACvD,+BAAU,MAAM,QAAQ,UAAU,GAAG,CAAC,UAAU,CAAC;AAEjD,QAAM,eAAW,oCAGf,CAAC,QAAQ,YAAY,OAAO,IAAI,GAAG,QAAQ,gBAAgB,EAAE,QAAQ,CAAC,GAAG;AAAA,IACzE,aAAa,CAAC,CAAC,iBAAiB,aAAa,CAAC;AAAA,IAC9C,WAAW,MAAM;AACf,YAAM,QAAQ,gCAAgC;AAAA,IAChD;AAAA,IACA,SAAS,CAAC,UAAU;AAClB,YAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,QACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,MACrE,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,QAAM,SAAS,CAAC,MAAc,UAA6B;AACzD,YAAQ,CAAC,SAAS,KAAK,IAAI,CAAC,QAAS,IAAI,SAAS,OAAO,EAAE,GAAG,KAAK,GAAG,MAAM,IAAI,GAAI,CAAC;AAAA,EACvF;AAEA,MAAI,WAAW;AACb,WACE,6CAAC,SAAI,MAAK,UAAS,cAAW,oCAAmC,eAAW,oBAAG,aAAa,SAAS,GAClG,WAAC,GAAG,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACjB,6CAAC,SAAY,WAAU,4CAAb,CAAsD,CACjE,GACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,8CAAC,SAAI,eAAW,oBAAG,mDAAmD,SAAS,GAC7E;AAAA,mDAAC,OAAE,WAAU,iCAAgC,sDAAwC;AAAA,MACrF;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,QAAQ;AAAA,UACvB,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,KAAK,WAAW,GAAG;AACrB,WACE,6CAAC,SAAI,eAAW,oBAAG,mDAAmD,SAAS,GAC7E,uDAAC,OAAE,WAAU,iCAAgC,oDAAsC,GACrF;AAAA,EAEJ;AAEA,SACE,8CAAC,SAAI,eAAW,oBAAG,aAAa,SAAS,GACvC;AAAA,kDAAC,WAAM,WAAU,kBACf;AAAA,mDAAC,WACC,wDAAC,QAAG,WAAU,2DACZ;AAAA,qDAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,0BAElD;AAAA,QACA,6CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAElD;AAAA,QACA,6CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,mBAElD;AAAA,QACA,6CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,0BAElD;AAAA,SACF,GACF;AAAA,MACA,6CAAC,WACE,eAAK,IAAI,CAAC,QAAQ;AACjB,cAAM,QAAQ,aAAa,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI;AAC5D,eACE,8CAAC,QAAkB,WAAU,0BAC3B;AAAA,uDAAC,QAAG,WAAU,aAAa,iBAAM;AAAA,UACjC,6CAAC,QAAG,WAAU,aACZ;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAY,GAAG,KAAK;AAAA,cACpB,SAAS,IAAI;AAAA,cACb,UAAU,CAAC,MAAM,OAAO,IAAI,MAAM,EAAE,cAAc,EAAE,OAAO,QAAQ,CAAC;AAAA;AAAA,UACtE,GACF;AAAA,UACA,6CAAC,QAAG,WAAU,aACZ;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAY,GAAG,KAAK;AAAA,cACpB,SAAS,IAAI;AAAA,cACb,UAAU,CAAC,MAAM,OAAO,IAAI,MAAM,EAAE,cAAc,EAAE,OAAO,QAAQ,CAAC;AAAA;AAAA,UACtE,GACF;AAAA,UACA,6CAAC,QAAG,WAAU,aACZ;AAAA,YAAC;AAAA;AAAA,cACC,cAAY,GAAG,KAAK;AAAA,cACpB,OAAO,IAAI;AAAA,cACX,UAAU,CAAC,IAAI;AAAA,cACf,UAAU,CAAC,MAAM,OAAO,IAAI,MAAM,EAAE,QAAQ,EAAE,OAAO,MAAsB,CAAC;AAAA,cAC5E,WAAU;AAAA,cAEV;AAAA,6DAAC,YAAO,OAAM,QAAO,yBAAW;AAAA,gBAChC,6CAAC,YAAO,OAAM,UAAS,2BAAa;AAAA,gBACpC,6CAAC,YAAO,OAAM,SAAQ,0BAAY;AAAA;AAAA;AAAA,UACpC,GACF;AAAA,aA9BO,IAAI,IA+Bb;AAAA,MAEJ,CAAC,GACH;AAAA,OACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,SAAS,OAAO,UAAU,IAAI,CAAC;AAAA,QAC9C,UAAU,SAAS;AAAA,QACnB,WAAU;AAAA,QAET,mBAAS,YAAY,iBAAY;AAAA;AAAA,IACpC;AAAA,KACF;AAEJ;;;AClNA,IAAAC,sBAA4B;AAoBrB,SAAS,eAAe,UAAiC,CAAC,GAAG;AAClE,QAAM,SAAS,sBAAsB;AACrC,QAAM,WAAW,QAAQ,YAAY,OAAO;AAC5C,QAAM,iBAAiB,QAAQ,kBAAkB,OAAO;AACxD,QAAM,QAAQ,QAAQ,SAAS,OAAO;AACtC,QAAM,EAAE,OAAO,IAAI,mBAAmB;AACtC,QAAM,WAAW,WAAW;AAC5B,QAAM,MAAM,QACR,CAAC,iBAAiB,gBAAgB,KAAK,IACvC,CAAC,iBAAiB,cAAc;AACpC,QAAM,MAAM,QACR,GAAG,QAAQ,uBAAuB,mBAAmB,KAAK,CAAC,KAC3D,GAAG,QAAQ;AAEf,aAAO,iCAA+B,KAAK,CAAC,WAAW,OAAO,IAAI,GAAG,GAAG;AAAA,IACtE,iBAAiB,WAAW,QAAQ;AAAA,IACpC,WAAW,WAAW,WAAW,iBAAiB;AAAA,EACpD,CAAC;AACH;;;ACtCA,IAAAC,gBAA0B;AAC1B,IAAAC,sBAA4C;AAC5C,IAAAC,mBAAyB;AA0ClB,SAAS,oBAAoB,UAAsC,CAAC,GAAG;AAC5E,QAAM,SAAS,sBAAsB;AACrC,QAAM,WAAW,QAAQ,YAAY,OAAO;AAC5C,QAAM,iBAAiB,QAAQ,kBAAkB,OAAO;AACxD,QAAM,QAAQ,QAAQ,SAAS,OAAO;AACtC,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,EAAE,QAAQ,OAAO,IAAI,mBAAmB;AAC9C,QAAM,WAAW,WAAW;AAC5B,QAAM,YAAQ,2BAAS;AACvB,QAAM,WAAW,QAAQ,UAAU,mBAAmB,KAAK,CAAC,KAAK;AACjE,QAAM,cAAc,QAAQ,GAAG,QAAQ,mBAAmB,mBAAmB,KAAK,CAAC,KAAK,GAAG,QAAQ;AAInG,QAAM,YAAQ;AAAA,IACZ,CAAC,iBAAiB,EAAE,OAAO,MAAM,CAAC;AAAA,IAClC,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,oBAAoB,KAAK,GAAG,QAAQ,EAAE;AAAA,IACxE;AAAA,MACE,iBAAiB,WAAW,QAAQ;AAAA,MACpC,WAAW,WAAW,WAAW,iBAAiB;AAAA,IACpD;AAAA,EACF;AAIA,+BAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,YAAY,MAAM;AACtB,YAAM,SAAS,MAAM,MAAM,QAAQ,CAAC,GAAG,cAAa,oBAAI,KAAK,CAAC,GAAE,YAAY;AAC5E,aAAO,KAAK,oBAAoB,EAAE,OAAO,OAAO,CAAC;AAAA,IACnD;AACA,WAAO,GAAG,WAAW,SAAS;AAC9B,WAAO,MAAM;AACX,aAAO,IAAI,WAAW,SAAS;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,QAAQ,MAAM,IAAI,CAAC;AAEvB,QAAM,eAAW;AAAA,IACf,CAAC,QAAQ,OAAO,OAAO,KAAK,GAAG,QAAQ,IAAI,EAAE,SAAS,CAAC,CAAC;AAAA,IACxD;AAAA,MACE,aAAa,CAAC,CAAC,eAAe,GAAG,CAAC,iBAAiB,cAAc,CAAC;AAAA,MAClE,SAAS,CAAC,UACR,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,QACtE,aAAa,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,MAC9E,CAAC;AAAA,IACL;AAAA,EACF;AAEA,QAAM,kBAAc;AAAA,IAClB,CAAC,WAAW,OAAO,KAAK,aAAa,CAAC,CAAC;AAAA,IACvC;AAAA,MACE,aAAa,CAAC,CAAC,eAAe,GAAG,CAAC,iBAAiB,cAAc,CAAC;AAAA,MAClE,SAAS,CAAC,UACR,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,QACtE,aAAa,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,MAC9E,CAAC;AAAA,IACL;AAAA,EACF;AAEA,SAAO,EAAE,GAAG,OAAO,UAAU,YAAY;AAC3C;;;ACxGA,IAAAC,mBAAmB;AA+Bf,IAAAC,sBAAA;AAbG,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AAExB,QAAM,EAAE,KAAK,IAAI,eAAe,EAAE,UAAU,gBAAgB,MAAM,CAAC;AACnE,QAAM,QAAQ,MAAM,SAAS;AAC7B,QAAM,QAAQ,UAAU,IAAI,4BAA4B,GAAG,KAAK;AAEhE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,cAAW;AAAA,MACX,eAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,eAAY;AAAA,YACZ,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,QAAO;AAAA,YACP,aAAY;AAAA,YACZ,WAAU;AAAA,YAEV;AAAA,cAAC;AAAA;AAAA,gBACC,eAAc;AAAA,gBACd,gBAAe;AAAA,gBACf,GAAE;AAAA;AAAA,YACJ;AAAA;AAAA,QACF;AAAA,QACA,6CAAC,UAAK,MAAK,UAAS,cAAY,OAAO,WAAU,WAC9C,iBACH;AAAA,QACC,QAAQ,KACP;AAAA,UAAC;AAAA;AAAA,YACC,eAAY;AAAA,YACZ,WAAU;AAAA,YAET,kBAAQ,KAAK,QAAQ;AAAA;AAAA,QACxB;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AClEA,IAAAC,mBAAuD;AAiC/C,IAAAC,sBAAA;AAhBD,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AAEzB,QAAM,EAAE,MAAM,WAAW,SAAS,SAAS,UAAU,YAAY,IAAI,oBAAoB;AAAA,IACvF;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,MAAI,WAAW;AACb,WACE,8CAAC,SAAI,MAAK,UAAS,cAAW,yBAAwB,eAAW,qBAAG,SAAS,GAC3E;AAAA,mDAAC,UAAK,WAAU,WAAU,mCAAqB;AAAA,MAC/C,8CAAC,yBAAK,eAAY,QAChB;AAAA,qDAAC,eAAY;AAAA,QACb,6CAAC,QAAG,WAAU,0BACX,WAAC,GAAG,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACjB,8CAAC,QAAW,WAAU,sCACpB;AAAA,uDAAC,6BAAS,WAAU,6BAA4B;AAAA,UAChD,8CAAC,SAAI,WAAU,sCACb;AAAA,yDAAC,6BAAS,WAAU,eAAc;AAAA,YAClC,6CAAC,6BAAS,WAAU,aAAY;AAAA,aAClC;AAAA,aALO,CAMT,CACD,GACH;AAAA,SACF;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,8CAAC,yBAAK,WACJ;AAAA,mDAAC,eAAY;AAAA,MACb,8CAAC,SAAI,WAAU,2DACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,eAAY;AAAA,YACZ,WAAU;AAAA,YAEV,uDAAC,aAAU;AAAA;AAAA,QACb;AAAA,QACA,8CAAC,SAAI,WAAU,uBACb;AAAA,uDAAC,OAAE,WAAU,uCAAsC,0CAA4B;AAAA,UAC/E,6CAAC,OAAE,WAAU,iCAAgC,4DAE7C;AAAA,WACF;AAAA,QACA,6CAAC,2BAAO,MAAK,UAAS,SAAS,MAAM,KAAK,QAAQ,GAAG,uBAErD;AAAA,SACF;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,QAAQ,MAAM,SAAS,CAAC;AAE9B,MAAI,MAAM,WAAW,GAAG;AACtB,WACE,8CAAC,yBAAK,WACJ;AAAA,mDAAC,eAAY;AAAA,MACb;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,6CAAC,eAAY;AAAA,UACnB,OAAM;AAAA,UACN,aAAY;AAAA;AAAA,MACd;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,8CAAC,yBAAK,MAAK,UAAS,cAAW,iBAAgB,WAC7C;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,QACE;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,MAAM,YAAY,OAAO;AAAA,YAClC,UAAU,YAAY;AAAA,YACvB;AAAA;AAAA,QAED;AAAA;AAAA,IAEJ;AAAA,IACA,6CAAC,QAAG,WAAU,0BACX,gBAAM,IAAI,CAAC,SACV,6CAAC,YAAuB,MAAY,YAAY,MAAM,SAAS,OAAO,KAAK,EAAE,KAA9D,KAAK,EAA4D,CACjF,GACH;AAAA,KACF;AAEJ;AAGA,SAAS,YAAY,EAAE,OAAO,GAA2B;AACvD,SACE,8CAAC,SAAI,WAAU,4EACb;AAAA,iDAAC,QAAG,WAAU,yCAAwC,2BAAa;AAAA,IAClE;AAAA,KACH;AAEJ;AAEA,SAAS,SAAS;AAAA,EAChB;AAAA,EACA;AACF,GAGG;AACD,SACE,6CAAC,QACC;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS;AAAA,MACT,cAAY,GAAG,KAAK,KAAK,GAAG,KAAK,SAAS,KAAK,WAAW;AAAA,MAC1D,WAAU;AAAA,MAEV;AAAA,qDAAC,UAAK,eAAY,QAAO,WAAU,2DAChC,WAAC,KAAK,UAAU,6CAAC,UAAK,WAAU,gCAA+B,GAClE;AAAA,QACA,8CAAC,UAAK,WAAU,wCACd;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,eAAW;AAAA,gBACT;AAAA,gBACA,KAAK,SAAS,sCAAsC;AAAA,cACtD;AAAA,cAEC,eAAK;AAAA;AAAA,UACR;AAAA,UACC,KAAK,QACJ,6CAAC,UAAK,WAAU,0CAA0C,eAAK,MAAK;AAAA,WAExE;AAAA;AAAA;AAAA,EACF,GACF;AAEJ;AAIA,SAAS,YAAY;AACnB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MAEf;AAAA,qDAAC,UAAK,GAAE,4FAA2F;AAAA,QACnG,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA,QACrC,6CAAC,UAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,MAAK,IAAG,MAAK;AAAA;AAAA;AAAA,EAC3C;AAEJ;AAEA,SAAS,cAAc;AACrB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MAEf;AAAA,qDAAC,UAAK,GAAE,8CAA6C;AAAA,QACrD,6CAAC,UAAK,GAAE,2CAA0C;AAAA,QAClD,6CAAC,UAAK,GAAE,kCAAiC;AAAA,QACzC,6CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA;AAAA;AAAA,EACtC;AAEJ;;;ACtMA,IAAAC,gBAAyD;AACzD,IAAAC,mBAAmD;AAoB/C,IAAAC,sBAAA;AAFJ,SAAS,WAAW;AAClB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW;AAAA,MACX,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,WAAU;AAAA,MAEV;AAAA,qDAAC,UAAK,GAAE,+CAA8C;AAAA,QACtD,6CAAC,UAAK,GAAE,8BAA6B;AAAA;AAAA;AAAA,EACvC;AAEJ;AAeO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAS,KAAK;AACtC,QAAM,mBAAe,sBAAuB,IAAI;AAChD,QAAM,eAAW,sBAAuB,IAAI;AAC5C,QAAM,EAAE,KAAK,IAAI,eAAe,EAAE,OAAO,UAAU,eAAe,CAAC;AAEnE,QAAM,cAAc,MAAM,SAAS;AACnC,QAAM,QAAQ,cAAc,KAAK,QAAQ,OAAO,WAAW;AAC3D,QAAM,QACJ,gBAAgB,IAAI,4BAA4B,GAAG,WAAW;AAEhE,QAAM,YAAQ,2BAAY,MAAM,QAAQ,KAAK,GAAG,CAAC,CAAC;AAElD,+BAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,UAAM,QAAQ,CAAC,MAAqB;AAClC,UAAI,EAAE,QAAQ,SAAU,OAAM;AAAA,IAChC;AACA,UAAM,YAAY,CAAC,MAAkB;AACnC,YAAM,IAAI,aAAa;AACvB,UAAI,KAAK,EAAE,kBAAkB,QAAQ,CAAC,EAAE,SAAS,EAAE,MAAM,EAAG,OAAM;AAAA,IACpE;AACA,aAAS,iBAAiB,WAAW,KAAK;AAC1C,aAAS,iBAAiB,aAAa,SAAS;AAChD,WAAO,MAAM;AACX,eAAS,oBAAoB,WAAW,KAAK;AAC7C,eAAS,oBAAoB,aAAa,SAAS;AAAA,IACrD;AAAA,EACF,GAAG,CAAC,MAAM,KAAK,CAAC;AAEhB,qCAAa,UAAU,IAAI;AAC3B,QAAM,gBAAY,mCAAiB,IAAI;AAEvC,SACE,8CAAC,SAAI,KAAK,cAAc,eAAW,qBAAG,yBAAyB,SAAS,GACtE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,iBAAc;AAAA,QACd,iBAAe;AAAA,QACf,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;AAAA,QAChC,WAAU;AAAA,QAEV;AAAA,uDAAC,YAAS;AAAA,UACV,6CAAC,UAAK,MAAK,UAAS,WAAU,WAC3B,iBACH;AAAA,UACC,cAAc,KACb;AAAA,YAAC;AAAA;AAAA,cACC,eAAW;AAAA,cACX,WAAU;AAAA,cAET;AAAA;AAAA,UACH;AAAA;AAAA;AAAA,IAEJ;AAAA,IAEC,UAAU,WACT;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL,cAAW;AAAA,QACX,UAAU;AAAA,QACV,cAAY,UAAU;AAAA,QACtB,gBAAgB,UAAU;AAAA,QAC1B,eAAW;AAAA,UACT;AAAA,UACA,UAAU,UAAU,SAChB,mBACA;AAAA,UACJ;AAAA,QACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA,WAAU;AAAA;AAAA,QACZ;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;;;AC3IA,IAAAC,gBAAyB;AACzB,IAAAC,mBAAmB;;;ACDnB,IAAAC,sBAA4B;AA4B5B,SAAS,QAAQ,SAA2C;AAC1D,QAAM,SAAS,IAAI,gBAAgB;AACnC,SAAO,IAAI,QAAQ,QAAQ,IAAI;AAC/B,SAAO,IAAI,MAAM,QAAQ,EAAE;AAC3B,MAAI,QAAQ,QAAS,QAAO,IAAI,WAAW,QAAQ,OAAO;AAC1D,MAAI,QAAQ,KAAM,QAAO,IAAI,QAAQ,QAAQ,IAAI;AACjD,MAAI,QAAQ,eAAgB,QAAO,IAAI,kBAAkB,QAAQ,cAAc;AAC/E,SAAO,OAAO,SAAS;AACzB;AAGO,SAAS,qBAAqB;AAAA,EACnC,WAAW;AAAA,EACX,GAAG;AACL,GAAgC;AAC9B,aAAO;AAAA,IACL,CAAC,sBAAsB,WAAW,OAAO;AAAA,IACzC,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,YAAY,QAAQ,OAAO,CAAC,EAAE;AAAA,EAClE;AACF;;;AC/CA,IAAAC,sBAA4B;AAqBrB,SAAS,eAAe;AAAA,EAC7B,WAAW;AAAA,EACX,GAAG;AACL,GAA0B;AACxB,aAAO;AAAA,IACL,CAAC,sBAAsB,UAAU,OAAO;AAAA,IACxC,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,WAAW,QAA4B,OAAO,CAAC,EAAE;AAAA,EACrF;AACF;;;AC7BA,IAAAC,sBAA4B;AAqBrB,SAAS,iBAAiB;AAAA,EAC/B,WAAW;AAAA,EACX,GAAG;AACL,GAA4B;AAC1B,QAAM,SAAS,IAAI,gBAAgB;AACnC,SAAO,IAAI,QAAQ,QAAQ,IAAI;AAC/B,SAAO,IAAI,MAAM,QAAQ,EAAE;AAC3B,MAAI,QAAQ,eAAgB,QAAO,IAAI,kBAAkB,QAAQ,cAAc;AAE/E,aAAO;AAAA,IACL,CAAC,sBAAsB,SAAS,OAAO;AAAA,IACvC,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,UAAU,OAAO,SAAS,CAAC,EAAE;AAAA,EACjE;AACF;;;AClCA,IAAAC,mBAAmB;AA0BX,IAAAC,sBAAA;AAlBR,IAAM,MAAM,CAAC,MAAc,IAAI,IAAI,KAAK,QAAQ,CAAC,CAAC;AAG3C,SAAS,YAAY,EAAE,QAAQ,UAAU,GAAqB;AACnE,QAAM,QAAiD;AAAA,IACrD,EAAE,OAAO,SAAS,OAAO,OAAO,OAAO,KAAK,EAAE;AAAA,IAC9C,EAAE,OAAO,aAAa,OAAO,OAAO,OAAO,SAAS,EAAE;AAAA,IACtD,EAAE,OAAO,UAAU,OAAO,OAAO,OAAO,MAAM,EAAE;AAAA,IAChD,EAAE,OAAO,WAAW,OAAO,OAAO,OAAO,OAAO,EAAE;AAAA,IAClD,EAAE,OAAO,aAAa,OAAO,IAAI,OAAO,QAAQ,EAAE;AAAA,IAClD,EAAE,OAAO,cAAc,OAAO,IAAI,OAAO,SAAS,EAAE;AAAA,IACpD,EAAE,OAAO,eAAe,OAAO,IAAI,OAAO,UAAU,EAAE;AAAA,IACtD,EAAE,OAAO,iBAAiB,OAAO,IAAI,OAAO,YAAY,EAAE;AAAA,EAC5D;AAEA,SACE,6CAAC,QAAG,eAAW,qBAAG,yCAAyC,SAAS,GAAG,cAAW,mBAC/E,gBAAM,IAAI,CAAC,MACV;AAAA,IAAC;AAAA;AAAA,MAEC,WAAU;AAAA,MAEV;AAAA,qDAAC,UAAK,WAAU,6CAA6C,YAAE,OAAM;AAAA,QACrE,6CAAC,UAAK,WAAU,0CAA0C,YAAE,OAAM;AAAA;AAAA;AAAA,IAJ7D,EAAE;AAAA,EAKT,CACD,GACH;AAEJ;;;ACpCA,IAAAC,mBAAmB;AACnB,sBAQO;AAgBC,IAAAC,sBAAA;AAJD,SAAS,WAAW,EAAE,MAAM,UAAU,GAAoB;AAC/D,SACE,6CAAC,SAAI,eAAW,qBAAG,eAAe,SAAS,GAAG,MAAK,OAAM,cAAW,4BAClE,uDAAC,uCAAoB,OAAM,QAAO,QAAO,QACvC,wDAAC,6BAAU,MAAY,QAAQ,EAAE,KAAK,GAAG,OAAO,IAAI,QAAQ,GAAG,MAAM,EAAE,GACrE;AAAA,iDAAC,iCAAc,iBAAgB,OAAM,QAAO,iBAAgB;AAAA,IAC5D,6CAAC,yBAAM,SAAQ,OAAM,QAAO,2BAA0B,UAAU,IAAI;AAAA,IACpE,6CAAC,yBAAM,QAAO,2BAA0B,UAAU,IAAI,eAAe,OAAO;AAAA,IAC5E,6CAAC,2BAAQ;AAAA,IACT,6CAAC,wBAAK,MAAK,YAAW,SAAQ,SAAQ,QAAO,kBAAiB,KAAK,OAAO;AAAA,IAC1E,6CAAC,wBAAK,MAAK,YAAW,SAAQ,aAAY,QAAO,kCAAiC,KAAK,OAAO;AAAA,IAC9F,6CAAC,wBAAK,MAAK,YAAW,SAAQ,UAAS,QAAO,kCAAiC,KAAK,OAAO;AAAA,IAC3F,6CAAC,wBAAK,MAAK,YAAW,SAAQ,WAAU,QAAO,kCAAiC,KAAK,OAAO;AAAA,KAC9F,GACF,GACF;AAEJ;;;ACtCA,IAAAC,mBAAmB;AAcb,IAAAC,sBAAA;AANN,IAAMC,OAAM,CAAC,MAAc,IAAI,IAAI,KAAK,QAAQ,CAAC,CAAC;AAG3C,SAAS,UAAU,EAAE,MAAM,UAAU,GAAmB;AAC7D,SACE,8CAAC,WAAM,eAAW,qBAAG,kCAAkC,SAAS,GAC9D;AAAA,iDAAC,aAAQ,WAAU,WAAU,qDAAuC;AAAA,IACpE,6CAAC,WACC,wDAAC,QAAG,WAAU,2DACZ;AAAA,mDAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,kBAAI;AAAA,MACtD,6CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,mBAAK;AAAA,MACvD,6CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,uBAAS;AAAA,MAC3D,6CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,uBAAS;AAAA,MAC3D,6CAAC,QAAG,OAAM,OAAM,WAAU,oBAAmB,wBAAU;AAAA,OACzD,GACF;AAAA,IACA,6CAAC,WACE,eAAK,IAAI,CAAC,MACT,8CAAC,QAAgB,WAAU,6BACzB;AAAA,mDAAC,QAAG,WAAU,yCAAyC,YAAE,MAAK;AAAA,MAC9D,6CAAC,QAAG,WAAU,6BAA6B,YAAE,OAAM;AAAA,MACnD,6CAAC,QAAG,WAAU,6BAA6B,YAAE,WAAU;AAAA,MACvD,6CAAC,QAAG,WAAU,6BAA6B,UAAAA,KAAI,EAAE,QAAQ,GAAE;AAAA,MAC3D,6CAAC,QAAG,WAAU,wBAAwB,UAAAA,KAAI,EAAE,SAAS,GAAE;AAAA,SALhD,EAAE,IAMX,CACD,GACH;AAAA,KACF;AAEJ;;;ANOM,IAAAC,uBAAA;AA7BN,IAAM,eAAe;AACrB,IAAM,aAAa;AAEnB,IAAM,WAAW,CAAC,IAAI,SAAS,SAAS,QAAQ,KAAK;AAO9C,SAAS,sBAAsB;AAAA,EACpC,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAA+B;AAC7B,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAiB,EAAE;AACjD,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAiB,YAAY;AACrD,QAAM,CAAC,IAAI,KAAK,QAAI,wBAAiB,UAAU;AAE/C,QAAM,UAAU,EAAE,MAAM,IAAI,SAAS,WAAW,QAAW,gBAAgB,SAAS;AACpF,QAAM,UAAU,qBAAqB,OAAO;AAC5C,QAAM,SAAS,eAAe,OAAO;AACrC,QAAM,QAAQ,iBAAiB,EAAE,MAAM,IAAI,gBAAgB,SAAS,CAAC;AAErE,QAAM,YAAY,QAAQ,aAAa,OAAO,aAAa,MAAM;AACjE,QAAM,UAAU,QAAQ,WAAW,OAAO,WAAW,MAAM;AAE3D,SACE,+CAAC,UAAK,eAAW,qBAAG,kCAAkC,SAAS,GAC7D;AAAA,mDAAC,YAAO,WAAU,uBAChB;AAAA,oDAAC,QAAG,WAAU,yCAAwC,gCAAkB;AAAA,MACxE,8CAAC,OAAE,WAAU,iCAAgC,8DAE7C;AAAA,OACF;AAAA,IAEA,+CAAC,SAAI,WAAU,kCACb;AAAA,qDAAC,WAAM,WAAU,+BACf;AAAA,sDAAC,UAAK,WAAU,+BAA8B,qBAAO;AAAA,QACrD;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,WAAW,EAAE,OAAO,KAAK;AAAA,YAC1C,WAAU;AAAA,YAET,mBAAS,IAAI,CAAC,MACb,8CAAC,YAAwB,OAAO,GAC7B,gBAAM,KAAK,iBAAiB,KADlB,KAAK,KAElB,CACD;AAAA;AAAA,QACH;AAAA,SACF;AAAA,MACA,+CAAC,WAAM,WAAU,+BACf;AAAA,sDAAC,UAAK,WAAU,+BAA8B,kBAAI;AAAA,QAClD;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,YACvC,WAAU;AAAA;AAAA,QACZ;AAAA,SACF;AAAA,MACA,+CAAC,WAAM,WAAU,+BACf;AAAA,sDAAC,UAAK,WAAU,+BAA8B,gBAAE;AAAA,QAChD;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,MAAM,EAAE,OAAO,KAAK;AAAA,YACrC,WAAU;AAAA;AAAA,QACZ;AAAA,SACF;AAAA,OACF;AAAA,IAEC,YACC,+CAAC,SAAI,MAAK,UAAS,cAAW,8BAA6B,WAAU,uBACnE;AAAA,oDAAC,UAAK,WAAU,WAAU,wCAA0B;AAAA,MACpD,8CAAC,SAAI,eAAY,QAAO,WAAU,uCAAsC;AAAA,MACxE,8CAAC,SAAI,eAAY,QAAO,WAAU,uCAAsC;AAAA,OAC1E,IACE,UACF,+CAAC,SAAI,WAAU,mCACb;AAAA,oDAAC,OAAE,WAAU,2BAA0B,+CAAiC;AAAA,MACxE;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM;AACb,iBAAK,QAAQ,QAAQ;AACrB,iBAAK,OAAO,QAAQ;AACpB,iBAAK,MAAM,QAAQ;AAAA,UACrB;AAAA,UACA,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF,KACG,QAAQ,MAAM,UAAU,OAAO,IAClC,8CAAC,OAAE,WAAU,8EAA6E,qDAE1F,IAEA,+CAAC,SAAI,WAAU,uBACZ;AAAA,aAAO,OAAO,8CAAC,eAAY,QAAQ,OAAO,MAAM,IAAK;AAAA,MACtD,+CAAC,aAAQ,cAAW,kBAAiB,WAAU,uCAC7C;AAAA,sDAAC,QAAG,WAAU,8CAA6C,mBAAK;AAAA,QAChE,8CAAC,cAAW,MAAM,QAAQ,QAAQ,CAAC,GAAG;AAAA,SACxC;AAAA,MACA,+CAAC,aAAQ,cAAW,oBAAmB,WAAU,uCAC/C;AAAA,sDAAC,QAAG,WAAU,8CAA6C,qBAAO;AAAA,QAClE,8CAAC,aAAU,MAAM,MAAM,QAAQ,CAAC,GAAG;AAAA,SACrC;AAAA,OACF;AAAA,KAEJ;AAEJ;;;AO9HA,IAAAC,oBAAmB;AAuBf,IAAAC,uBAAA;AAnBJ,IAAM,gBAAwC;AAAA,EAC5C,OAAO;AAAA,EACP,WAAW;AAAA,EACX,UAAU;AACZ;AAMO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AACF,GAGG;AACD,QAAM,QAAQ,cAAc,MAAM,KAAK;AACvC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;;;AChCA,IAAAC,oBAAuD;AACvD,IAAAC,sBAA4B;AA8BpB,IAAAC,uBAAA;AATD,SAAS,aAAa,EAAE,WAAW,kBAAkB,UAAU,GAAsB;AAC1F,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,aAAa,QAAQ;AAAA,IACtB,CAAC,WAAW,OAAO,IAAI,QAAQ;AAAA,EACjC;AAEA,MAAI,WAAW;AACb,WACE,+CAAC,SAAI,MAAK,UAAS,cAAW,qBAAoB,eAAW,sBAAG,SAAS,GACvE;AAAA,oDAAC,UAAK,WAAU,WAAU,+BAAiB;AAAA,MAC3C,+CAAC,0BAAK,eAAY,QAChB;AAAA,sDAAC,cAAW;AAAA,QACZ,8CAAC,QAAG,WAAU,0BACX,WAAC,GAAG,GAAG,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACpB,+CAAC,QAAW,WAAU,mCACpB;AAAA,yDAAC,SAAI,WAAU,6BACb;AAAA,0DAAC,8BAAS,WAAU,cAAa;AAAA,YACjC,8CAAC,8BAAS,WAAU,yBAAwB;AAAA,aAC9C;AAAA,UACA,8CAAC,8BAAS,WAAU,YAAW;AAAA,aALxB,CAMT,CACD,GACH;AAAA,SACF;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,0BAAK,WACJ;AAAA,oDAAC,cAAW;AAAA,MACZ,+CAAC,SAAI,WAAU,2DACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,eAAY;AAAA,YACZ,WAAU;AAAA,YAEV,wDAACC,YAAA,EAAU;AAAA;AAAA,QACb;AAAA,QACA,+CAAC,SAAI,WAAU,uBACb;AAAA,wDAAC,OAAE,WAAU,uCAAsC,sCAAwB;AAAA,UAC3E,8CAAC,OAAE,WAAU,iCAAgC,gEAE7C;AAAA,WACF;AAAA,QACA,8CAAC,4BAAO,MAAK,UAAS,SAAS,MAAM,KAAK,QAAQ,GAAG,uBAErD;AAAA,SACF;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,QAAQ,QAAQ,CAAC;AAEvB,MAAI,MAAM,WAAW,GAAG;AACtB,WACE,+CAAC,0BAAK,WACJ;AAAA,oDAAC,cAAW;AAAA,MACZ;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,8CAAC,YAAS;AAAA,UAChB,OAAM;AAAA,UACN,aAAY;AAAA;AAAA,MACd;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,+CAAC,0BAAK,MAAK,UAAS,cAAW,aAAY,WACzC;AAAA,kDAAC,cAAW,OAAO,MAAM,QAAQ;AAAA,IACjC,8CAAC,QAAG,WAAU,0BACX,gBAAM,IAAI,CAAC,SACV,8CAAC,eAAkC,QAAjB,KAAK,UAAwB,CAChD,GACH;AAAA,KACF;AAEJ;AAGA,SAAS,WAAW,EAAE,MAAM,GAAuB;AACjD,SACE,+CAAC,SAAI,WAAU,4EACb;AAAA,mDAAC,SAAI,WAAU,iBACb;AAAA,oDAAC,QAAG,WAAU,yCAAwC,uBAAS;AAAA,MAC/D,8CAAC,OAAE,WAAU,iCAAgC,0DAA4C;AAAA,OAC3F;AAAA,IACC,SAAS,QAAQ,QAAQ,KACxB,+CAAC,UAAK,WAAU,qHACb;AAAA;AAAA,MAAM;AAAA,OACT;AAAA,KAEJ;AAEJ;AAEA,SAAS,YAAY,EAAE,KAAK,GAA+B;AACzD,SACE,+CAAC,QAAG,WAAU,qCACZ;AAAA,mDAAC,SAAI,WAAU,6BACb;AAAA,oDAAC,UAAK,WAAU,gDAAgD,eAAK,YAAW;AAAA,MAChF,8CAAC,uBAAoB,QAAQ,KAAK,cAAc;AAAA,OAClD;AAAA,IACA,+CAAC,SAAI,WAAU,6EACb;AAAA,qDAAC,UAAK,WAAU,gBAAgB;AAAA,aAAK;AAAA,QAAa;AAAA,SAAS;AAAA,MAC3D,8CAAC,UAAK,eAAY,QAAO,WAAU,eAAc,kBAEjD;AAAA,MACA,+CAAC,UAAK,WAAU,qCACd;AAAA,sDAAC,UAAK,sBAAQ;AAAA,QACb,KAAK,QAAQ,IAAI,CAAC,WACjB;AAAA,UAAC;AAAA;AAAA,YAEC,WAAU;AAAA,YAET;AAAA;AAAA,UAHI;AAAA,QAIP,CACD;AAAA,SACH;AAAA,OACF;AAAA,KACF;AAEJ;AAIA,SAASA,aAAY;AACnB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MAEf;AAAA,sDAAC,UAAK,GAAE,4FAA2F;AAAA,QACnG,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA,QACrC,8CAAC,UAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,MAAK,IAAG,MAAK;AAAA;AAAA;AAAA,EAC3C;AAEJ;AAEA,SAAS,WAAW;AAClB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MAEf;AAAA,sDAAC,UAAK,GAAE,8DAA6D;AAAA,QACrE,8CAAC,UAAK,GAAE,2BAA0B;AAAA,QAClC,8CAAC,UAAK,GAAE,WAAU;AAAA,QAClB,8CAAC,UAAK,GAAE,YAAW;AAAA,QACnB,8CAAC,UAAK,GAAE,YAAW;AAAA;AAAA;AAAA,EACrB;AAEJ;;;ACxLA,IAAAC,gBAAyB;AACzB,IAAAC,oBAA6B;AAC7B,IAAAC,sBAA+B;AA6HvB,IAAAC,uBAAA;AAlGR,IAAM,aAA4F;AAAA,EAChG,EAAE,KAAK,WAAW,OAAO,WAAW,WAAW,MAAM;AAAA,EACrD,EAAE,KAAK,WAAW,OAAO,WAAW,WAAW,MAAM;AAAA,EACrD,EAAE,KAAK,QAAQ,OAAO,QAAQ,WAAW,KAAK;AAAA,EAC9C,EAAE,KAAK,OAAO,OAAO,aAAa,WAAW,MAAM;AAAA,EACnD,EAAE,KAAK,QAAQ,OAAO,QAAQ,WAAW,KAAK;AAChD;AAGA,SAAS,eAAe,OAAwB;AAC9C,QAAM,QAAQ,MAAM,MAAM,OAAO,KAAK,CAAC,GAAG;AAC1C,QAAM,SAAS,MAAM,MAAM,OAAO,KAAK,CAAC,GAAG;AAC3C,SAAO,SAAS;AAClB;AAOO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX;AACF,GAAwB;AACtB,QAAM,YAAQ,4BAAS;AACvB,QAAM,CAAC,QAAQ,SAAS,QAAI,wBAA+B;AAAA,IACzD,SAAS,eAAe,WAAW;AAAA,IACnC,SAAS,eAAe,WAAW;AAAA,IACnC,MAAM,eAAe,QAAQ;AAAA,IAC7B,KAAK,eAAe,OAAO;AAAA,IAC3B,MAAM,eAAe,QAAQ;AAAA,EAC/B,CAAC;AACD,QAAM,CAAC,QAAQ,SAAS,QAAI,wBAA8D,CAAC,CAAC;AAC5F,QAAM,CAAC,QAAQ,SAAS,QAAI,wBAAyB,aAAa;AAClE,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,wBAA6B,SAAS;AAEpF,QAAM,WAAO;AAAA,IACX,CAAC,QAAQ,YAAY,OAAO,IAAI,GAAG,QAAQ,IAAI,UAAU,IAAI,OAAO;AAAA,IACpE;AAAA,MACE,aAAa,CAAC,CAAC,WAAW,CAAC;AAAA,MAC3B,WAAW,CAAC,WAAW;AACrB,kBAAU,OAAO,MAAM;AACvB,2BAAmB,OAAO,EAAE;AAC5B,cAAM,QAAQ,aAAa;AAAA,MAC7B;AAAA,MACA,SAAS,CAAC,UACR,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,QACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,MACrE,CAAC;AAAA,IACL;AAAA,EACF;AAEA,QAAM,cAAU;AAAA,IACd,CAAC,QAAQ,QAAQ,OAAO,KAAK,GAAG,QAAQ,IAAI,UAAU,aAAa,GAAG,YAAY,CAAC,CAAC;AAAA,IACpF;AAAA,MACE,aAAa,CAAC,CAAC,WAAW,CAAC;AAAA,MAC3B,WAAW,MAAM;AACf,kBAAU,WAAW;AACrB,cAAM,QAAQ,mBAAmB;AAAA,MACnC;AAAA,MACA,SAAS,CAAC,UACR,MAAM;AAAA,QACJ,MAAM,aACF,8BACA,MAAM,gBACJ,yBACA,MAAM;AAAA,QACZ,EAAE,aAAa,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS,IAAI;AAAA,MACpF;AAAA,IACJ;AAAA,EACF;AAEA,QAAM,WAAW,MAAe;AAC9B,UAAM,OAA4D,CAAC;AACnE,eAAW,EAAE,IAAI,KAAK,YAAY;AAChC,UAAI,CAAC,eAAe,OAAO,GAAG,CAAC,GAAG;AAChC,aAAK,GAAG,IAAI;AAAA,MACd;AAAA,IACF;AACA,cAAU,IAAI;AACd,WAAO,OAAO,KAAK,IAAI,EAAE,WAAW;AAAA,EACtC;AAEA,QAAM,WAAW,CAAC,UAA2B;AAC3C,UAAM,eAAe;AACrB,QAAI,CAAC,SAAS,EAAG;AACjB,SAAK,OAAO,MAAM;AAAA,EACpB;AAEA,SACE,+CAAC,UAAK,UAAoB,eAAW,sBAAG,uBAAuB,SAAS,GAAG,YAAU,MACnF;AAAA,mDAAC,YAAO,WAAU,qCAChB;AAAA,qDAAC,QAAG,WAAU,yCAAwC;AAAA;AAAA,QAAgB;AAAA,SAAW;AAAA,MACjF,8CAAC,uBAAoB,QAAgB;AAAA,OACvC;AAAA,IAEC,WAAW,IAAI,CAAC,EAAE,KAAK,OAAO,UAAU,MAAM;AAC7C,YAAM,UAAU,YAAY,GAAG;AAC/B,YAAM,UAAU,GAAG,OAAO;AAC1B,YAAM,QAAQ,OAAO,GAAG;AACxB,aACE,+CAAC,SAAc,WAAU,uBACvB;AAAA,sDAAC,WAAM,SAAS,SAAS,WAAU,uCAChC,iBACH;AAAA,QACC,YACC;AAAA,UAAC;AAAA;AAAA,YACC,IAAI;AAAA,YACJ,OAAO,OAAO,GAAG;AAAA,YACjB,MAAM;AAAA,YACN,gBAAc,QAAQ,SAAS;AAAA,YAC/B,oBAAkB,QAAQ,UAAU;AAAA,YACpC,UAAU,CAAC,MAAM,UAAU,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,GAAG,GAAG,EAAE,OAAO,MAAM,EAAE;AAAA,YACzE,WAAU;AAAA;AAAA,QACZ,IAEA;AAAA,UAAC;AAAA;AAAA,YACC,IAAI;AAAA,YACJ,MAAK;AAAA,YACL,OAAO,OAAO,GAAG;AAAA,YACjB,gBAAc,QAAQ,SAAS;AAAA,YAC/B,oBAAkB,QAAQ,UAAU;AAAA,YACpC,UAAU,CAAC,MAAM,UAAU,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,GAAG,GAAG,EAAE,OAAO,MAAM,EAAE;AAAA,YACzE,WAAU;AAAA;AAAA,QACZ;AAAA,QAED,SACC,8CAAC,OAAE,IAAI,SAAS,WAAU,4BACvB,iBACH;AAAA,WA5BM,GA8BV;AAAA,IAEJ,CAAC;AAAA,IAED,+CAAC,SAAI,WAAU,2BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,KAAK;AAAA,UACf,WAAU;AAAA,UAET,eAAK,YAAY,iBAAY;AAAA;AAAA,MAChC;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,CAAC,mBAAmB,QAAQ;AAAA,UACtC,SAAS,MAAM,mBAAmB,QAAQ,OAAO,eAAe;AAAA,UAChE,WAAU;AAAA,UAET,kBAAQ,YAAY,qBAAgB;AAAA;AAAA,MACvC;AAAA,OACF;AAAA,KACF;AAEJ;;;AC7LA,IAAAC,gBAA0B;AAC1B,IAAAC,oBAAmB;AACnB,IAAAC,uBAA+B;AAyCzB,IAAAC,uBAAA;AApBC,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA,OAAO,CAAC;AAAA,EACR,WAAW;AAAA,EACX;AACF,GAA6B;AAC3B,QAAM,cAAU;AAAA,IACd,CAAC,QAAQ,YAAY,OAAO,KAAK,GAAG,QAAQ,IAAI,UAAU,YAAY,OAAO;AAAA,EAC/E;AAEA,QAAM,EAAE,QAAQ,MAAM,WAAW,QAAQ,IAAI;AAE7C,+BAAU,MAAM;AACd,WAAO,EAAE,WAAW,KAAK,CAAC;AAAA,EAE5B,GAAG,CAAC,YAAY,SAAS,CAAC;AAE1B,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,6BAAe;AAAA,UACzC,8CAAC,SAAI,eAAY,QAAO,WAAU,4CAA2C;AAAA,UAC7E,8CAAC,SAAI,eAAY,QAAO,WAAU,uCAAsC;AAAA;AAAA;AAAA,IAC1E;AAAA,EAEJ;AAEA,MAAI,WAAW,CAAC,MAAM;AACpB,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,oCAAsB;AAAA,MAC7D;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,OAAO,EAAE,WAAW,KAAK,CAAC;AAAA,UACzC,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,+CAAC,aAAQ,cAAW,oBAAmB,eAAW,sBAAG,uBAAuB,SAAS,GACnF;AAAA,kDAAC,QAAG,WAAU,yCAAyC,eAAK,SAAQ;AAAA,IACpE;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,SAAQ;AAAA,QACR,QAAQ,KAAK;AAAA,QACb,WAAU;AAAA;AAAA,IACZ;AAAA,IACA,+CAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,QAAG,WAAU,6CAA4C,wBAAU;AAAA,MACpE,8CAAC,SAAI,WAAU,0GACZ,eAAK,MACR;AAAA,OACF;AAAA,KACF;AAEJ;;;ACvFA,IAAAC,oBAA6B;AAC7B,IAAAC,uBAA4C;AAyDtC,IAAAC,uBAAA;AAjCC,SAAS,uBAAuB;AAAA,EACrC;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA,cAAc;AAChB,GAAgC;AAC9B,QAAM,YAAQ,4BAAS;AACvB,QAAM,cAAc,CAAC,aAAa,YAAY,UAAU;AAExD,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C;AAAA,IACA,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,IAAI,UAAU,WAAW;AAAA,EAC7D;AAEA,QAAM,eAAW;AAAA,IACf,CAAC,QAAQ,OAAO,OAAO,KAAK,GAAG,QAAQ,IAAI,UAAU,aAAa,EAAE,aAAa,CAAC,CAAC;AAAA,IACnF;AAAA,MACE,aAAa,CAAC,CAAC,GAAG,WAAW,GAAG,CAAC,WAAW,CAAC;AAAA,MAC7C,WAAW,MAAM,MAAM,QAAQ,qBAAqB;AAAA,MACpD,SAAS,CAAC,UACR,MAAM;AAAA,QACJ,MAAM,aACF,kCACA,MAAM,gBACJ,yBACA,MAAM;AAAA,QACZ,EAAE,aAAa,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS,IAAI;AAAA,MACpF;AAAA,IACJ;AAAA,EACF;AAEA,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,8BAAgB;AAAA,UACzC,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,qCAAuB;AAAA,MAC9D;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,WAAW,QAAQ,CAAC;AAE1B,MAAI,SAAS,WAAW,GAAG;AACzB,WACE,8CAAC,SAAI,eAAW,sBAAG,iDAAiD,SAAS,GAAG,yBAEhF;AAAA,EAEJ;AAEA,SACE,8CAAC,aAAQ,cAAW,mBAAkB,eAAW,sBAAG,iBAAiB,SAAS,GAC5E,yDAAC,WAAM,WAAU,kBACf;AAAA,kDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,oDAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,qBAElD;AAAA,MACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAElD;AAAA,MACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAElD;AAAA,MACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,kBAElD;AAAA,MACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBACxB,wDAAC,UAAK,WAAU,WAAU,qBAAO,GACnC;AAAA,OACF,GACF;AAAA,IACA,8CAAC,WACE,mBAAS,IAAI,CAAC,YACb,+CAAC,QAAoB,WAAU,0BAC7B;AAAA,qDAAC,QAAG,WAAU,yCAAwC;AAAA;AAAA,QAAE,QAAQ;AAAA,SAAc;AAAA,MAC9E,8CAAC,QAAG,WAAU,aACZ,wDAAC,uBAAoB,QAAQ,QAAQ,QAAQ,GAC/C;AAAA,MACA,8CAAC,QAAG,WAAU,mCAAmC,kBAAQ,WAAU;AAAA,MACnE,8CAAC,QAAG,WAAU,mCAAmC,kBAAQ,WAAU;AAAA,MACnE,8CAAC,QAAG,WAAU,sBACX,yBAAe,QAAQ,WAAW,cACjC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,SAAS;AAAA,UACnB,SAAS,MAAM,SAAS,OAAO,QAAQ,EAAE;AAAA,UACzC,WAAU;AAAA,UACX;AAAA;AAAA,MAED,GAEJ;AAAA,SAlBO,QAAQ,EAmBjB,CACD,GACH;AAAA,KACF,GACF;AAEJ;;;ACjJA,IAAAC,gBAAyB;AACzB,IAAAC,oBAAmB;AACnB,IAAAC,uBAA4B;AA8CtB,IAAAC,uBAAA;AApBN,IAAM,QAAQ;AAMP,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA,WAAW;AAAA,EACX;AACF,GAA2B;AACzB,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAS,CAAC;AAElC,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,aAAa,YAAY,iBAAiB,IAAI;AAAA,IAC/C,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,IAAI,UAAU,uBAAuB,IAAI,UAAU,KAAK,EAAE;AAAA,EAC9F;AAEA,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,mCAAqB;AAAA,UAC9C,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,0CAA4B;AAAA,MACnE;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,OAAO,MAAM,SAAS,CAAC;AAC7B,QAAM,aAAa,MAAM,cAAc;AAEvC,MAAI,KAAK,WAAW,GAAG;AACrB,WACE,8CAAC,SAAI,eAAW,sBAAG,iDAAiD,SAAS,GAAG,8BAEhF;AAAA,EAEJ;AAEA,SACE,+CAAC,aAAQ,cAAW,iBAAgB,eAAW,sBAAG,uBAAuB,SAAS,GAChF;AAAA,mDAAC,WAAM,WAAU,kBACf;AAAA,oDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,sDAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,uBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,sBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,wBAElD;AAAA,SACF,GACF;AAAA,MACA,8CAAC,WACE,eAAK,IAAI,CAAC,QACT,+CAAC,QAAgB,WAAU,0BACzB;AAAA,sDAAC,QAAG,WAAU,6BAA6B,cAAI,gBAAe;AAAA,QAC9D,8CAAC,QAAG,WAAU,aACZ,wDAAC,uBAAoB,QAAQ,IAAI,QAAQ,GAC3C;AAAA,QACA,8CAAC,QAAG,WAAU,mCAAmC,cAAI,UAAS;AAAA,QAC9D,8CAAC,QAAG,WAAU,mCAAmC,cAAI,aAAa,UAAI;AAAA,WAN/D,IAAI,EAOb,CACD,GACH;AAAA,OACF;AAAA,IACA,+CAAC,SAAI,cAAW,2BAA0B,WAAU,qCAClD;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AAAA,UAChD,UAAU,QAAQ;AAAA,UAClB,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,MACA,+CAAC,UAAK,WAAU,iCAAgC;AAAA;AAAA,QACxC;AAAA,QAAK;AAAA,QAAK;AAAA,SAClB;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,QAAQ,CAAC,MAAM,KAAK,IAAI,YAAY,IAAI,CAAC,CAAC;AAAA,UACzD,UAAU,QAAQ;AAAA,UAClB,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,KACF;AAEJ;;;AC9IA,IAAAC,uBAA4B;AAgC5B,IAAMC,SAAQ;AAGP,SAAS,cAAc,EAAE,OAAO,GAAG,QAAQ,WAAW,OAAO,IAA0B,CAAC,GAAG;AAChG,QAAM,cAAc,SAAS,WAAW,mBAAmB,MAAM,CAAC,KAAK;AACvE,aAAO;AAAA,IAA+B,CAAC,cAAc,EAAE,MAAM,OAAO,CAAC;AAAA,IAAG,CAAC,WACvE,OAAO,IAAI,GAAG,QAAQ,uBAAuB,IAAI,UAAUA,MAAK,GAAG,WAAW,EAAE;AAAA,EAClF;AACF;;;ACxCA,IAAAC,iBAAyB;AACzB,IAAAC,oBAAyE;AA6CnE,IAAAC,uBAAA;AAnCN,SAAS,cAAc,QAAoC;AACzD,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAOO,SAAS,cAAc;AAAA,EAC5B,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AACF,GAAuB;AACrB,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAS,CAAC;AAClC,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,IAAI,cAAc,EAAE,MAAM,QAAQ,SAAS,CAAC;AAEtF,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,gCAAkB;AAAA,UAC3C,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,uCAAyB;AAAA,MAChE;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,OAAO,MAAM,SAAS,CAAC;AAC7B,QAAM,aAAa,MAAM,cAAc;AAEvC,MAAI,KAAK,WAAW,GAAG;AACrB,WACE,8CAAC,SAAI,eAAW,sBAAG,iDAAiD,SAAS,GAAG,2BAEhF;AAAA,EAEJ;AAEA,QAAM,qBAAqB,CAAC,QAC1B,WACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS,MAAM,SAAS,IAAI,EAAE;AAAA,MAC9B,WAAU;AAAA,MAET,cAAI;AAAA;AAAA,EACP,IAEA,8CAAC,UAAK,WAAU,mBAAmB,cAAI,YAAW;AAGtD,SACE,+CAAC,aAAQ,cAAW,cAAa,eAAW,sBAAG,uBAAuB,SAAS,GAC7E;AAAA,mDAAC,WAAM,WAAU,kBACf;AAAA,oDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,sDAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,sBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,sBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,qCAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,wBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,qBAElD;AAAA,SACF,GACF;AAAA,MACA,8CAAC,WACE,eAAK,IAAI,CAAC,QACT,+CAAC,QAAgB,WAAU,0BACzB;AAAA,sDAAC,QAAG,WAAU,aAAa,6BAAmB,GAAG,GAAE;AAAA,QACnD,8CAAC,QAAG,WAAU,aACZ,wDAAC,iCAAY,SAAS,cAAc,IAAI,MAAM,GAAI,cAAI,QAAO,GAC/D;AAAA,QACA,8CAAC,QAAG,WAAU,mCACX,cAAI,SAAS,SAAS,IAAI,IAAI,SAAS,KAAK,IAAI,IAAI,UACvD;AAAA,QACA,+CAAC,QAAG,WAAU,mCACX;AAAA,cAAI;AAAA,UAAU;AAAA,UAAI,IAAI;AAAA,UAAY;AAAA,UAAI,IAAI;AAAA,WAC7C;AAAA,QACA,8CAAC,QAAG,WAAU,mCAAmC,cAAI,WAAU;AAAA,QAC/D,8CAAC,QAAG,WAAU,mCAAmC,gDAAe,IAAI,SAAS,GAAE;AAAA,WAZxE,IAAI,EAab,CACD,GACH;AAAA,OACF;AAAA,IACA,+CAAC,SAAI,cAAW,wBAAuB,WAAU,qCAC/C;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AAAA,UAChD,UAAU,QAAQ;AAAA,UAClB,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,MACA,+CAAC,UAAK,WAAU,iCAAgC;AAAA;AAAA,QACxC;AAAA,QAAK;AAAA,QAAK;AAAA,SAClB;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,QAAQ,CAAC,MAAM,KAAK,IAAI,YAAY,IAAI,CAAC,CAAC;AAAA,UACzD,UAAU,QAAQ;AAAA,UAClB,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,KACF;AAEJ;;;ACrKA,IAAAC,oBAAmE;AACnE,IAAAC,uBAA4C;AAoFtC,IAAAC,uBAAA;AA7DN,IAAM,oBAAoB,CAAC,aAAa,yBAAyB,UAAU,WAAW;AAEtF,SAAS,iBAAiB,QAAqC;AAC7D,SAAO,WAAW,UAAa,kBAAkB,SAAS,MAAM;AAClE;AAEA,SAASC,eAAc,QAAoC;AACzD,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAOO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,YAAQ,4BAAS;AAEvB,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,cAAc,WAAW;AAAA,IAC1B,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,kBAAkB,WAAW,EAAE;AAAA,IACjE;AAAA,MACE,iBAAiB,CAAC,UAAW,iBAAiB,MAAM,MAAM,MAAM,MAAM,IAAI,QAAQ;AAAA,IACpF;AAAA,EACF;AAEA,QAAM,aAAS;AAAA,IACb,CAAC,WAAW,OAAO,OAAO,GAAG,QAAQ,kBAAkB,WAAW,EAAE;AAAA,IACpE;AAAA,MACE,aAAa,CAAC,CAAC,YAAY,CAAC;AAAA,MAC5B,WAAW,MAAM;AACf,cAAM,QAAQ,qBAAqB;AACnC,sBAAc;AAAA,MAChB;AAAA,MACA,SAAS,CAAC,UACR,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,QACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,MACrE,CAAC;AAAA,IACL;AAAA,EACF;AAEA,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,+BAAiB;AAAA,UAC1C,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,MACX,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,sCAAwB;AAAA,MAC/D;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,CAAC,MAAM;AACT,WACE,8CAAC,SAAI,eAAW,sBAAG,iDAAiD,SAAS,GAAG,0BAEhF;AAAA,EAEJ;AAEA,QAAM,QAAQ,KAAK;AACnB,QAAM,YAAY,KAAK,YAAY,KAAK,cAAc,KAAK;AAC3D,QAAMC,OAAM,QAAQ,IAAI,KAAK,IAAI,KAAK,KAAK,MAAO,YAAY,QAAS,GAAG,CAAC,IAAI;AAC/E,QAAM,WAAW,iBAAiB,KAAK,MAAM;AAE7C,SACE,+CAAC,aAAQ,cAAW,sBAAqB,eAAW,sBAAG,2BAA2B,SAAS,GACzF;AAAA,mDAAC,YAAO,WAAU,qCAChB;AAAA,qDAAC,QAAG,WAAU,yCAAwC;AAAA;AAAA,QAAW,KAAK;AAAA,SAAW;AAAA,MACjF,8CAAC,iCAAY,SAASD,eAAc,KAAK,MAAM,GAAG,YAAW,SAC1D,eAAK,QACR;AAAA,OACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,iBAAeC;AAAA,QACf,iBAAe;AAAA,QACf,iBAAe;AAAA,QACf,cAAW;AAAA,QACX,WAAU;AAAA,QAEV,wDAAC,SAAI,WAAU,kCAAiC,OAAO,EAAE,OAAO,GAAGA,IAAG,IAAI,GAAG;AAAA;AAAA,IAC/E;AAAA,IACA,+CAAC,OAAE,WAAU,iCACV;AAAA;AAAA,MAAU;AAAA,MAAK;AAAA,MAAM;AAAA,MAAaA;AAAA,MAAI;AAAA,OACzC;AAAA,IAEA,+CAAC,QAAG,WAAU,iDACZ;AAAA,qDAAC,SAAI,WAAU,6DACb;AAAA,sDAAC,QAAG,WAAU,iCAAgC,kBAAI;AAAA,QAClD,8CAAC,QAAG,WAAU,mBAAmB,eAAK,WAAU;AAAA,SAClD;AAAA,MACA,+CAAC,SAAI,WAAU,6DACb;AAAA,sDAAC,QAAG,WAAU,iCAAgC,oBAAM;AAAA,QACpD,8CAAC,QAAG,WAAU,mBAAmB,eAAK,aAAY;AAAA,SACpD;AAAA,MACA,+CAAC,SAAI,WAAU,6DACb;AAAA,sDAAC,QAAG,WAAU,iCAAgC,qBAAO;AAAA,QACrD,8CAAC,QAAG,WAAU,mBAAmB,eAAK,cAAa;AAAA,SACrD;AAAA,MACA,+CAAC,SAAI,WAAU,6DACb;AAAA,sDAAC,QAAG,WAAU,iCAAgC,mBAAK;AAAA,QACnD,8CAAC,QAAG,WAAU,mBAAmB,iBAAM;AAAA,SACzC;AAAA,OACF;AAAA,IAEA,8CAAC,SACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAU,YAAY,OAAO;AAAA,QAC7B,SAAS,MAAM,OAAO,OAAO;AAAA,QAC7B,WAAU;AAAA,QAET,iBAAO,YAAY,qBAAgB;AAAA;AAAA,IACtC,GACF;AAAA,KACF;AAEJ;;;ACpLA,IAAAC,iBAAyB;AACzB,IAAAC,oBAA6B;AAC7B,IAAAC,uBAA4C;AAgHtC,IAAAC,uBAAA;AA3EN,IAAMC,YAAW,CAAC,SAAS,SAAS,QAAQ,OAAO,WAAW,SAAS,OAAO;AAS9E,SAAS,cAAiB,MAA8C;AACtE,MAAI,CAAC,KAAM,QAAO,CAAC;AACnB,MAAI,MAAM,QAAQ,IAAI,EAAG,QAAO;AAChC,SAAO,KAAK,SAAS,CAAC;AACxB;AAEA,SAAS,gBAAgB,KAAuB;AAC9C,SAAO,IACJ,MAAM,OAAO,EACb,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAC/B;AAOO,SAAS,kBAAkB;AAAA,EAChC,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,YAAQ,4BAAS;AACvB,QAAM,CAAC,cAAc,QAAI,yBAAS,MAAM,OAAO,WAAW,CAAC;AAE3D,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAS,EAAE;AAC/C,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAmB,CAAC,CAAC;AACrD,QAAM,CAAC,cAAc,eAAe,QAAI,yBAAuB,SAAS;AACxE,QAAM,CAAC,WAAW,YAAY,QAAI,yBAAS,EAAE;AAC7C,QAAM,CAAC,eAAe,gBAAgB,QAAI,yBAAS,EAAE;AACrD,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAS,EAAE;AACnC,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAyB,CAAC,CAAC;AAEvD,QAAM,qBAAiB;AAAA,IACrB,CAAC,WAAW;AAAA,IACZ,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,YAAY;AAAA,EAChD;AAEA,QAAM,oBAAgB;AAAA,IACpB,CAAC,UAAU;AAAA,IACX,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,cAAc;AAAA,EAClD;AAEA,QAAM,aAAS;AAAA,IACb,CAAC,QAAQ,YAAY,OAAO,KAAK,GAAG,QAAQ,kBAAkB,OAAO;AAAA,IACrE;AAAA,MACE,aAAa,CAAC,CAAC,YAAY,CAAC;AAAA,MAC5B,WAAW,CAAC,WAAW;AACrB,cAAM,QAAQ,mBAAmB;AACjC,oBAAY,OAAO,EAAE;AAAA,MACvB;AAAA,MACA,SAAS,CAAC,UACR,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,QACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,MACrE,CAAC;AAAA,IACL;AAAA,EACF;AAEA,QAAM,YAAY,eAAe,aAAa,cAAc;AAC5D,QAAM,UAAU,eAAe,WAAW,cAAc;AAExD,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,wCAA0B;AAAA,UACnD,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,+CAAiC;AAAA,MACxE;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM;AACb,iBAAK,eAAe,QAAQ;AAC5B,iBAAK,cAAc,QAAQ;AAAA,UAC7B;AAAA,UACA,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,YAAY,cAAc,eAAe,IAAI;AACnD,QAAM,WAAW,cAAc,cAAc,IAAI;AAEjD,QAAM,gBAAgB,CAAC,YAAoB;AACzC;AAAA,MAAY,CAAC,SACX,KAAK,SAAS,OAAO,IAAI,KAAK,OAAO,CAAC,MAAM,MAAM,OAAO,IAAI,CAAC,GAAG,MAAM,OAAO;AAAA,IAChF;AAAA,EACF;AAEA,QAAM,WAAW,CAAC,iBAAoC;AACpD,UAAM,OAAuB,CAAC;AAC9B,QAAI,CAAC,WAAY,MAAK,aAAa;AACnC,QAAI,SAAS,WAAW,EAAG,MAAK,WAAW;AAC3C,QAAI,iBAAiB,aAAa,CAAC,WAAW;AAC5C,WAAK,WAAW;AAAA,IAClB;AACA,QAAI,iBAAiB,gBAAgB,aAAa,WAAW,GAAG;AAC9D,WAAK,WAAW;AAAA,IAClB;AACA,cAAU,IAAI;AACd,WAAO,OAAO,KAAK,IAAI,EAAE,WAAW;AAAA,EACtC;AAEA,QAAM,WAAW,CAAC,UAA2B;AAC3C,UAAM,eAAe;AACrB,UAAM,eAAe,gBAAgB,aAAa;AAClD,QAAI,CAAC,SAAS,YAAY,EAAG;AAC7B,WAAO,OAAO;AAAA,MACZ;AAAA,MACA;AAAA,MACA,MAAM,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI;AAAA,MAClC,WAAW,iBAAiB,YAAY,YAAY;AAAA,MACpD,cAAc,iBAAiB,eAAe,eAAe;AAAA,MAC7D;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SACE,+CAAC,UAAK,UAAoB,eAAW,sBAAG,2BAA2B,SAAS,GAAG,YAAU,MACvF;AAAA,kDAAC,QAAG,WAAU,yCAAwC,2BAAa;AAAA,IAEnE,+CAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,qBAAoB,WAAU,uCAAsC,sBAEnF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,OAAO;AAAA,UACP,gBAAc,OAAO,aAAa,SAAS;AAAA,UAC3C,oBAAkB,OAAO,aAAa,4BAA4B;AAAA,UAClE,UAAU,CAAC,MAAM,cAAc,EAAE,OAAO,KAAK;AAAA,UAC7C,WAAU;AAAA,UAEV;AAAA,0DAAC,YAAO,OAAM,IAAG,qCAAkB;AAAA,YAClC,UAAU,IAAI,CAAC,MACd,8CAAC,YAAkB,OAAO,EAAE,IACzB,YAAE,QAAQ,EAAE,MADF,EAAE,EAEf,CACD;AAAA;AAAA;AAAA,MACH;AAAA,MACC,OAAO,cACN,8CAAC,OAAE,IAAG,2BAA0B,WAAU,4BACvC,iBAAO,YACV;AAAA,OAEJ;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,gBAAc,OAAO,WAAW,SAAS;AAAA,QACzC,oBAAkB,OAAO,WAAW,4BAA4B;AAAA,QAEhE;AAAA,wDAAC,YAAO,WAAU,uCAAsC,sBAAQ;AAAA,UAChE,8CAAC,SAAI,WAAU,wBACZ,UAAAA,UAAS,IAAI,CAAC,YAAY;AACzB,kBAAM,aAAa,oBAAoB,OAAO;AAC9C,mBACE;AAAA,cAAC;AAAA;AAAA,gBAEC,SAAS;AAAA,gBACT,WAAU;AAAA,gBAEV;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,IAAI;AAAA,sBACJ,MAAK;AAAA,sBACL,SAAS,SAAS,SAAS,OAAO;AAAA,sBAClC,UAAU,MAAM,cAAc,OAAO;AAAA,sBACrC,WAAU;AAAA;AAAA,kBACZ;AAAA,kBACC;AAAA;AAAA;AAAA,cAXI;AAAA,YAYP;AAAA,UAEJ,CAAC,GACH;AAAA,UACC,OAAO,YACN,8CAAC,OAAE,IAAG,2BAA0B,WAAU,4BACvC,iBAAO,UACV;AAAA;AAAA;AAAA,IAEJ;AAAA,IAEA,+CAAC,cAAS,WAAU,uBAClB;AAAA,oDAAC,YAAO,WAAU,uCAAsC,sBAAQ;AAAA,MAChE,+CAAC,SAAI,WAAU,cACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,WAAU;AAAA,YAEV;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,IAAG;AAAA,kBACH,MAAK;AAAA,kBACL,MAAK;AAAA,kBACL,SAAS,iBAAiB;AAAA,kBAC1B,UAAU,MAAM,gBAAgB,SAAS;AAAA,kBACzC,WAAU;AAAA;AAAA,cACZ;AAAA,cAAE;AAAA;AAAA;AAAA,QAEJ;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,WAAU;AAAA,YAEV;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,IAAG;AAAA,kBACH,MAAK;AAAA,kBACL,MAAK;AAAA,kBACL,SAAS,iBAAiB;AAAA,kBAC1B,UAAU,MAAM,gBAAgB,YAAY;AAAA,kBAC5C,WAAU;AAAA;AAAA,cACZ;AAAA,cAAE;AAAA;AAAA;AAAA,QAEJ;AAAA,SACF;AAAA,MAEC,iBAAiB,YAChB;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,cAAW;AAAA,UACX,OAAO;AAAA,UACP,gBAAc,OAAO,WAAW,SAAS;AAAA,UACzC,oBAAkB,OAAO,WAAW,4BAA4B;AAAA,UAChE,UAAU,CAAC,MAAM,aAAa,EAAE,OAAO,KAAK;AAAA,UAC5C,WAAU;AAAA,UAEV;AAAA,0DAAC,YAAO,OAAM,IAAG,oCAAiB;AAAA,YACjC,SAAS,IAAI,CAAC,MACb,8CAAC,YAAkB,OAAO,EAAE,IACzB,YAAE,QADQ,EAAE,EAEf,CACD;AAAA;AAAA;AAAA,MACH,IAEA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,cAAW;AAAA,UACX,OAAO;AAAA,UACP,MAAM;AAAA,UACN,aAAY;AAAA,UACZ,gBAAc,OAAO,WAAW,SAAS;AAAA,UACzC,oBAAkB,OAAO,WAAW,4BAA4B;AAAA,UAChE,UAAU,CAAC,MAAM,iBAAiB,EAAE,OAAO,KAAK;AAAA,UAChD,WAAU;AAAA;AAAA,MACZ;AAAA,MAED,OAAO,YACN,8CAAC,OAAE,IAAG,2BAA0B,WAAU,4BACvC,iBAAO,UACV;AAAA,OAEJ;AAAA,IAEA,+CAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,iBAAgB,WAAU,uCAAsC,6BAE/E;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,UACvC,WAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,IAEA,8CAAC,SACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAU,OAAO;AAAA,QACjB,WAAU;AAAA,QAET,iBAAO,YAAY,mBAAc;AAAA;AAAA,IACpC,GACF;AAAA,KACF;AAEJ;;;ACpVA,IAAAC,oBAAyE;AACzE,IAAAC,uBAA4B;AAsDtB,IAAAC,uBAAA;AAlCN,SAAS,UAAU,MAAgE;AACjF,MAAI,MAAM,QAAQ,IAAI,EAAG,QAAO;AAChC,SAAO,MAAM,SAAS,CAAC;AACzB;AAEA,SAAS,YAAY,MAAkC;AACrD,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAOO,SAAS,YAAY;AAAA,EAC1B,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,UAAU;AAAA,IACX,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,cAAc;AAAA,EAClD;AAEA,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,8BAAgB;AAAA,UACzC,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,qCAAuB;AAAA,MAC9D;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,OAAO,UAAU,IAAI;AAE3B,QAAM,SAAS,WACb,8CAAC,YAAO,WAAU,iCAChB;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS,MAAM,SAAS;AAAA,MACxB,WAAU;AAAA,MACX;AAAA;AAAA,EAED,GACF,IACE;AAEJ,MAAI,KAAK,WAAW,GAAG;AACrB,WACE,+CAAC,aAAQ,cAAW,YAAW,eAAW,sBAAG,uBAAuB,SAAS,GAC1E;AAAA;AAAA,MACD,8CAAC,SAAI,WAAU,iDAAgD,yBAAW;AAAA,OAC5E;AAAA,EAEJ;AAEA,QAAM,iBAAiB,CAAC,QACtB,WACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS,MAAM,SAAS,IAAI,EAAE;AAAA,MAC9B,WAAU;AAAA,MAET,cAAI;AAAA;AAAA,EACP,IAEA,8CAAC,UAAK,WAAU,mBAAmB,cAAI,MAAK;AAGhD,SACE,+CAAC,aAAQ,cAAW,YAAW,eAAW,sBAAG,uBAAuB,SAAS,GAC1E;AAAA;AAAA,IACD,+CAAC,WAAM,WAAU,kBACf;AAAA,oDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,sDAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,kBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,kBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,yBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,wBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,qBAElD;AAAA,SACF,GACF;AAAA,MACA,8CAAC,WACE,eAAK,IAAI,CAAC,QACT,+CAAC,QAAgB,WAAU,0BACzB;AAAA,sDAAC,QAAG,WAAU,aAAa,yBAAe,GAAG,GAAE;AAAA,QAC/C,8CAAC,QAAG,WAAU,aACZ,wDAAC,iCAAY,SAAS,YAAY,IAAI,IAAI,GAAG,YAAW,OACrD,cAAI,MACP,GACF;AAAA,QACA,8CAAC,QAAG,WAAU,mCAAmC,cAAI,eAAe,UAAI;AAAA,QACxE,8CAAC,QAAG,WAAU,mCAAmC,cAAI,cAAc,UAAU,UAAI;AAAA,QACjF,8CAAC,QAAG,WAAU,mCAAmC,gDAAe,IAAI,SAAS,GAAE;AAAA,WATxE,IAAI,EAUb,CACD,GACH;AAAA,OACF;AAAA,KACF;AAEJ;;;AChKA,IAAAC,iBAAyB;AACzB,IAAAC,oBAA6B;AAC7B,IAAAC,uBAA+B;AAkIvB,IAAAC,uBAAA;AAhGR,SAAS,kBAAkB,OAAyB;AAClD,SAAO,MACJ,MAAM,OAAO,EACb,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,EACrB,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;AACjC;AAOO,SAAS,eAAe;AAAA,EAC7B,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwB;AACtB,QAAM,YAAQ,4BAAS;AACvB,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAS,SAAS,QAAQ,EAAE;AACpD,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAsB,SAAS,QAAQ,QAAQ;AACvE,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,SAAS,eAAe,EAAE;AACzE,QAAM,CAAC,eAAe,gBAAgB,QAAI,0BAAU,SAAS,gBAAgB,CAAC,GAAG,KAAK,IAAI,CAAC;AAC3F,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAA6B,CAAC,CAAC;AAE3D,QAAM,SAAS,QAAQ,SAAS;AAEhC,QAAM,kBAAkB,CAAC,UAMvB,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,IACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,EACrE,CAAC;AAEH,QAAM,WAAO;AAAA,IACX,CAAC,QAAQ,YACP,YACI,OAAO,MAAM,GAAG,QAAQ,gBAAgB,SAAS,IAAI,OAAO,IAC5D,OAAO,KAAK,GAAG,QAAQ,gBAAgB,OAAO;AAAA,IACpD;AAAA,MACE,aAAa,CAAC,CAAC,UAAU,CAAC;AAAA,MAC1B,WAAW,CAAC,WAAW;AACrB,cAAM,QAAQ,SAAS,oBAAoB,iBAAiB;AAC5D,kBAAU,OAAO,EAAE;AAAA,MACrB;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,aAAS;AAAA,IACb,CAAC,WAAW,OAAO,OAAO,GAAG,QAAQ,gBAAgB,SAAS,EAAE;AAAA,IAChE;AAAA,MACE,aAAa,CAAC,CAAC,UAAU,CAAC;AAAA,MAC1B,WAAW,MAAM;AACf,cAAM,QAAQ,iBAAiB;AAC/B,oBAAY;AAAA,MACd;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,WAAW,CAAC,iBAAoC;AACpD,UAAM,OAA2B,CAAC;AAClC,QAAI,KAAK,KAAK,EAAE,WAAW,GAAG;AAC5B,WAAK,OAAO;AAAA,IACd;AACA,QAAI,SAAS,YAAY,aAAa,WAAW,GAAG;AAClD,WAAK,eAAe;AAAA,IACtB;AACA,cAAU,IAAI;AACd,WAAO,OAAO,KAAK,IAAI,EAAE,WAAW;AAAA,EACtC;AAEA,QAAM,WAAW,CAAC,UAA2B;AAC3C,UAAM,eAAe;AACrB,UAAM,eAAe,kBAAkB,aAAa;AACpD,QAAI,CAAC,SAAS,YAAY,EAAG;AAC7B,SAAK,OAAO,EAAE,MAAM,KAAK,KAAK,GAAG,MAAM,aAAa,YAAY,KAAK,GAAG,aAAa,CAAC;AAAA,EACxF;AAEA,QAAM,WAAW,MAAM;AACrB,QAAI,CAAC,UAAW;AAChB,QAAI,CAAC,OAAO,QAAQ,6CAA6C,EAAG;AACpE,WAAO,OAAO;AAAA,EAChB;AAEA,SACE,+CAAC,UAAK,UAAoB,eAAW,sBAAG,uBAAuB,SAAS,GAAG,YAAU,MACnF;AAAA,kDAAC,YAAO,WAAU,qCAChB,wDAAC,QAAG,WAAU,yCACX,mBAAS,iBAAiB,SAAS,KAAK,eAC3C,GACF;AAAA,IAEA,+CAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,gBAAe,WAAU,uCAAsC,kBAE9E;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,OAAO;AAAA,UACP,gBAAc,OAAO,OAAO,SAAS;AAAA,UACrC,oBAAkB,OAAO,OAAO,uBAAuB;AAAA,UACvD,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,UACvC,WAAU;AAAA;AAAA,MACZ;AAAA,MACC,OAAO,QACN,8CAAC,OAAE,IAAG,sBAAqB,WAAU,4BAClC,iBAAO,MACV;AAAA,OAEJ;AAAA,IAEA,+CAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,gBAAe,WAAU,uCAAsC,kBAE9E;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAoB;AAAA,UACtD,WAAU;AAAA,UAEV;AAAA,0DAAC,YAAO,OAAM,UAAS,oBAAM;AAAA,YAC7B,8CAAC,YAAO,OAAM,WAAU,qBAAO;AAAA;AAAA;AAAA,MACjC;AAAA,OACF;AAAA,IAEA,+CAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,uBAAsB,WAAU,uCAAsC,yBAErF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,OAAO;AAAA,UACP,MAAM;AAAA,UACN,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA,UAC9C,WAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,IAEC,SAAS,YACR,+CAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,sBAAqB,WAAU,uCAAsC,2BAEpF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,OAAO;AAAA,UACP,MAAM;AAAA,UACN,aAAY;AAAA,UACZ,gBAAc,OAAO,eAAe,SAAS;AAAA,UAC7C,oBAAkB,OAAO,eAAe,6BAA6B;AAAA,UACrE,UAAU,CAAC,MAAM,iBAAiB,EAAE,OAAO,KAAK;AAAA,UAChD,WAAU;AAAA;AAAA,MACZ;AAAA,MACC,OAAO,gBACN,8CAAC,OAAE,IAAG,4BAA2B,WAAU,4BACxC,iBAAO,cACV;AAAA,OAEJ;AAAA,IAGF,+CAAC,SAAI,WAAU,2BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,KAAK;AAAA,UACf,WAAU;AAAA,UAET,eAAK,YAAY,iBAAY,SAAS,iBAAiB;AAAA;AAAA,MAC1D;AAAA,MACC,UACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,OAAO;AAAA,UACjB,SAAS;AAAA,UACT,WAAU;AAAA,UAET,iBAAO,YAAY,mBAAc;AAAA;AAAA,MACpC;AAAA,OAEJ;AAAA,KACF;AAEJ;;;ACrOA,IAAAC,iBAAyB;AACzB,IAAAC,oBAAuE;AACvE,IAAAC,uBAA4C;;;ACF5C,IAAAC,oBAAiC;AAY3B,IAAAC,uBAAA;AAHC,SAAS,YAAY,EAAE,OAAO,SAAS,GAAyC;AACrF,SACE,8CAAC,SAAI,WAAU,4EACb,yDAAC,SAAI,WAAU,iBACb;AAAA,kDAAC,QAAG,WAAU,yCAAyC,iBAAM;AAAA,IAC5D,YAAY,8CAAC,OAAE,WAAU,8CAA8C,oBAAS;AAAA,KACnF,GACF;AAEJ;AAGO,SAAS,aAAa,EAAE,OAAO,OAAO,EAAE,GAAqC;AAClF,SACE,+CAAC,SAAI,MAAK,UAAS,cAAY,OAAO,WAAU,2BAC9C;AAAA,kDAAC,UAAK,WAAU,WAAW,iBAAM;AAAA,IAChC,MAAM,KAAK,EAAE,QAAQ,KAAK,CAAC,EAAE,IAAI,CAAC,GAAG,MACpC,8CAAC,8BAAiB,WAAU,iBAAb,CAA2B,CAC3C;AAAA,KACH;AAEJ;AAGO,SAAS,WAAW,EAAE,SAAS,QAAQ,GAA6C;AACzF,SACE,+CAAC,SAAI,WAAU,2DACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,eAAY;AAAA,QACZ,WAAU;AAAA,QAEV,wDAACC,YAAA,EAAU;AAAA;AAAA,IACb;AAAA,IACA,8CAAC,OAAE,WAAU,uCAAuC,mBAAQ;AAAA,IAC5D,8CAAC,4BAAO,MAAK,UAAS,SAAS,SAAS,uBAExC;AAAA,KACF;AAEJ;AAGO,SAAS,MAAM;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,cAAY;AAAA,MACZ,WAAU;AAAA,MAEV;AAAA,sDAAC,4BAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAAK,SAAS,QAAQ,UAAU,QAAQ,GAAG,sBAExF;AAAA,QACA,+CAAC,UAAK,WAAU,8CAA6C;AAAA;AAAA,UACrD;AAAA,UAAK;AAAA,UAAK;AAAA,WAClB;AAAA,QACA,8CAAC,4BAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAAK,SAAS,QAAQ,UAAU,QAAQ,YAAY,kBAEjG;AAAA;AAAA;AAAA,EACF;AAEJ;AAGO,IAAM,cACX;AAIK,SAASA,aAAY;AAC1B,SACE,+CAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAC9G;AAAA,kDAAC,UAAK,GAAE,4FAA2F;AAAA,IACnG,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA,IACrC,8CAAC,UAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,MAAK,IAAG,MAAK;AAAA,KAC3C;AAEJ;;;ADQU,IAAAC,uBAAA;AAtEV,IAAMC,SAAQ;AACd,IAAMC,YAAiC,CAAC,SAAS,SAAS,QAAQ,KAAK;AAOhE,SAAS,mBAAmB,EAAE,WAAW,QAAQ,UAAU,GAA4B;AAC5F,QAAM,YAAQ,4BAAS;AACvB,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAS,CAAC;AAClC,QAAM,CAAC,SAAS,UAAU,QAAI,yBAA6B,OAAO;AAClE,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,EAAE;AACzC,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAS,EAAE;AAEvC,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,eAAe,IAAI;AAAA,IACpB,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,8BAA8B,IAAI,UAAUD,MAAK,EAAE;AAAA,EACvF;AAEA,QAAM,kBAAkB,CAAC,UAMvB,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,IACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,EACrE,CAAC;AAEH,QAAM,UAAM;AAAA,IACV,CAAC,QAAQ,YAAY,OAAO,KAAK,GAAG,QAAQ,yBAAyB,OAAO;AAAA,IAC5E;AAAA,MACE,aAAa,CAAC,CAAC,aAAa,CAAC;AAAA,MAC7B,WAAW,MAAM;AACf,cAAM,QAAQ,mBAAmB;AACjC,mBAAW,EAAE;AACb,kBAAU,EAAE;AACZ,aAAK,QAAQ;AAAA,MACf;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,aAAS;AAAA,IACb,CAAC,QAAQ,OAAO,OAAO,OAAO,GAAG,QAAQ,yBAAyB,EAAE,EAAE;AAAA,IACtE;AAAA,MACE,aAAa,CAAC,CAAC,aAAa,CAAC;AAAA,MAC7B,WAAW,MAAM;AACf,cAAM,QAAQ,qBAAqB;AACnC,aAAK,QAAQ;AAAA,MACf;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,QAAQ,CAAC,UAA2B;AACxC,UAAM,eAAe;AACrB,QAAI,OAAO,EAAE,SAAS,SAAS,QAAQ,KAAK,GAAG,QAAQ,OAAO,KAAK,EAAE,CAAC;AAAA,EACxE;AAEA,QAAM,OAAO,MAAM,SAAS,CAAC;AAC7B,QAAM,aAAa,MAAM,cAAc;AAEvC,SACE,+CAAC,aAAQ,cAAW,oBAAmB,eAAW,sBAAG,uBAAuB,SAAS,GACnF;AAAA,kDAAC,0BACC,yDAAC,UAAK,UAAU,OAAO,WAAU,sCAAqC,YAAU,MAC9E;AAAA,qDAAC,WAAM,WAAU,+BACf;AAAA,sDAAC,UAAK,WAAU,+BAA8B,qBAAO;AAAA,QACrD;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,WAAW,EAAE,OAAO,KAA2B;AAAA,YAChE,WAAW;AAAA,YAEV,UAAAC,UAAS,IAAI,CAAC,MACb,8CAAC,YAAe,OAAO,GACpB,eADU,CAEb,CACD;AAAA;AAAA,QACH;AAAA,SACF;AAAA,MACA,+CAAC,WAAM,WAAU,sCACf;AAAA,sDAAC,UAAK,WAAU,+BAA8B,qBAAO;AAAA,QACrD,8CAAC,WAAM,MAAK,QAAO,OAAO,SAAS,UAAU,CAAC,MAAM,WAAW,EAAE,OAAO,KAAK,GAAG,WAAW,aAAa;AAAA,SAC1G;AAAA,MACA,+CAAC,WAAM,WAAU,sCACf;AAAA,sDAAC,UAAK,WAAU,+BAA8B,oBAAM;AAAA,QACpD,8CAAC,WAAM,MAAK,QAAO,OAAO,QAAQ,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK,GAAG,WAAW,aAAa;AAAA,SACxG;AAAA,MACA,8CAAC,4BAAO,MAAK,UAAS,UAAU,IAAI,WACjC,cAAI,YAAY,iBAAY,mBAC/B;AAAA,OACF,GACF;AAAA,IAEA,+CAAC,0BACC;AAAA,oDAAC,eAAY,OAAM,gBAAe,UAAU,GAAG,MAAM,SAAS,KAAK,MAAM,YAAY;AAAA,MACpF,YACC,8CAAC,gBAAa,OAAM,wBAAuB,IACzC,UACF,8CAAC,cAAW,SAAQ,+BAA8B,SAAS,MAAM,KAAK,QAAQ,GAAG,IAC/E,KAAK,WAAW,IAClB,8CAAC,gCAAW,MAAM,8CAAC,WAAQ,GAAI,OAAM,mBAAkB,aAAY,gCAA+B,IAElG,gFACE;AAAA,uDAAC,WAAM,WAAU,kBACf;AAAA,wDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,0DAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,qBAAO;AAAA,YACzD,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,qBAAO;AAAA,YACzD,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAAM;AAAA,YACxD,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,qBAAO;AAAA,YACzD,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,wDAAC,UAAK,WAAU,WAAU,qBAAO,GAAO;AAAA,aAC5F,GACF;AAAA,UACA,8CAAC,WACE,eAAK,IAAI,CAAC,QACT,+CAAC,QAAgB,WAAU,0DACzB;AAAA,0DAAC,QAAG,WAAU,aACZ,wDAAC,UAAK,WAAU,iIACb,cAAI,SACP,GACF;AAAA,YACA,8CAAC,QAAG,WAAU,6BAA6B,cAAI,SAAQ;AAAA,YACvD,8CAAC,QAAG,WAAU,mCAAmC,cAAI,QAAO;AAAA,YAC5D,8CAAC,QAAG,WAAU,mCAAmC,gDAAe,IAAI,SAAS,GAAE;AAAA,YAC/E,8CAAC,QAAG,WAAU,sBACZ;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,UAAU,OAAO;AAAA,gBACjB,SAAS,MAAM,OAAO,OAAO,IAAI,EAAE;AAAA,gBACpC;AAAA;AAAA,YAED,GACF;AAAA,eApBO,IAAI,EAqBb,CACD,GACH;AAAA,WACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA,QAAQ,MAAM,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AAAA,YAC/C,QAAQ,MAAM,QAAQ,CAAC,MAAM,KAAK,IAAI,YAAY,IAAI,CAAC,CAAC;AAAA;AAAA,QAC1D;AAAA,SACF;AAAA,OAEJ;AAAA,KACF;AAEJ;AAIA,SAAS,UAAU;AACjB,SACE,+CAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAC9G;AAAA,kDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,IAC/B,8CAAC,UAAK,GAAE,sBAAqB;AAAA,KAC/B;AAEJ;;;AE1MA,IAAAC,iBAAmC;AACnC,IAAAC,oBASO;AACP,IAAAC,uBAA4C;AA6EtC,IAAAC,uBAAA;AAtCN,IAAMC,SAAQ;AACd,IAAM,iBAAoC,CAAC,UAAU,YAAY,WAAW;AAS5E,SAAS,sBAAsB,OAAmC;AAChE,SAAO,MAAM,gBACT,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AACrE;AAEA,SAASC,eAAc,QAAoC;AACzD,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAGA,SAAS,oBAAoB,EAAE,IAAI,SAAS,GAAqC;AAC/E,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,OAAO,UAAU,EAAE;AAAA,IACpB,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,cAAc,EAAE,EAAE;AAAA,EACtD;AAEA,MAAI,WAAW;AACb,WACE,+CAAC,SAAI,MAAK,UAAS,cAAW,0BAAyB,WAAU,OAC/D;AAAA,oDAAC,UAAK,WAAU,WAAU,oCAAsB;AAAA,MAChD,8CAAC,SAAI,eAAY,QAAO,WAAU,kEAAiE;AAAA,OACrG;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,WAAU,uCACb;AAAA,oDAAC,OAAE,WAAU,2BAA0B,2CAA6B;AAAA,MACpE,8CAAC,4BAAO,MAAK,UAAS,MAAK,MAAK,SAAS,MAAM,KAAK,QAAQ,GAAG,uBAE/D;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,+CAAC,SAAI,WAAU,yCACb;AAAA,mDAAC,SACC;AAAA,oDAAC,SAAI,WAAU,+EAA8E,mBAAK;AAAA,MAClG,8CAAC,SAAI,WAAU,sCAAsC,gBAAM,gBAAgB,UAAI;AAAA,OACjF;AAAA,IACA,+CAAC,SACC;AAAA,oDAAC,SAAI,WAAU,+EAA8E,qBAAO;AAAA,MACpG,8CAAC,SAAI,WAAU,wHACZ,eAAK,UAAU,MAAM,WAAW,CAAC,GAAG,MAAM,CAAC,GAC9C;AAAA,OACF;AAAA,KACF;AAEJ;AAOO,SAAS,WAAW,EAAE,WAAW,QAAQ,UAAU,GAAoB;AAC5E,QAAM,YAAQ,4BAAS;AACvB,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAS,CAAC;AAClC,QAAM,CAAC,cAAc,eAAe,QAAI,yBAA+B,EAAE;AACzE,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAwB,IAAI;AAEhE,QAAM,cAAc,eAAe,WAAW,YAAY,KAAK;AAC/D,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,OAAO,MAAM,YAAY;AAAA,IAC1B,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,mBAAmB,IAAI,UAAUD,MAAK,GAAG,WAAW,EAAE;AAAA,EAC1F;AAEA,QAAM,aAAS;AAAA,IACb,CAAC,QAAQ,OAAO,OAAO,KAAK,GAAG,QAAQ,cAAc,EAAE,WAAW,CAAC,CAAC;AAAA,IACpE;AAAA,MACE,aAAa,CAAC,CAAC,KAAK,CAAC;AAAA,MACrB,WAAW,MAAM;AACf,cAAM,QAAQ,2BAA2B;AACzC,aAAK,QAAQ;AAAA,MACf;AAAA,MACA,SAAS,CAAC,UAAU;AAClB,YAAI,MAAM,YAAY;AACpB,gBAAM,MAAM,4BAA4B;AAAA,YACtC,aAAa,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,UAC9E,CAAC;AACD,eAAK,QAAQ;AACb;AAAA,QACF;AACA,cAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,UACtE,aAAa,sBAAsB,KAAK;AAAA,QAC1C,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,QAAM,cAAU;AAAA,IACd,CAAC,QAAQ,OAAO,OAAO,OAAO,GAAG,QAAQ,cAAc,EAAE,EAAE;AAAA,IAC3D;AAAA,MACE,aAAa,CAAC,CAAC,KAAK,CAAC;AAAA,MACrB,WAAW,MAAM;AACf,cAAM,QAAQ,mBAAmB;AACjC,aAAK,QAAQ;AAAA,MACf;AAAA,MACA,SAAS,CAAC,UACR,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,QACtE,aAAa,sBAAsB,KAAK;AAAA,MAC1C,CAAC;AAAA,IACL;AAAA,EACF;AAEA,QAAM,OAAO,MAAM,SAAS,CAAC;AAC7B,QAAM,aAAa,MAAM,cAAc;AAEvC,SACE,+CAAC,aAAQ,cAAW,qBAAoB,eAAW,sBAAG,uBAAuB,SAAS,GACpF;AAAA,mDAAC,SAAI,WAAU,uCACb;AAAA,oDAAC,WAAM,SAAQ,cAAa,WAAU,uCAAsC,oBAE5E;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,OAAO;AAAA,UACP,UAAU,CAAC,MAAM;AACf,4BAAgB,EAAE,OAAO,KAA6B;AACtD,oBAAQ,CAAC;AAAA,UACX;AAAA,UACA,WAAW;AAAA,UAEX;AAAA,0DAAC,YAAO,OAAM,IAAG,iBAAG;AAAA,YACnB,eAAe,IAAI,CAAC,MACnB,8CAAC,YAAe,OAAO,GACpB,eADU,CAEb,CACD;AAAA;AAAA;AAAA,MACH;AAAA,OACF;AAAA,IAEA,+CAAC,0BACC;AAAA,oDAAC,eAAY,OAAM,YAAW,UAAU,CAAC,aAAa,CAAC,UAAU,GAAG,MAAM,SAAS,KAAK,MAAM,cAAc,QAAW;AAAA,MACtH,YACC,8CAAC,gBAAa,OAAM,gCAA+B,IACjD,UACF,8CAAC,cAAW,SAAQ,uCAAsC,SAAS,MAAM,KAAK,QAAQ,GAAG,IACvF,KAAK,WAAW,IAClB,8CAAC,gCAAW,MAAM,8CAAC,aAAU,GAAI,OAAM,2BAA0B,aAAY,8CAA6C,IAE1H,gFACE;AAAA,sDAAC,QAAG,WAAU,0BACX,eAAK,IAAI,CAAC,QAAQ;AACjB,gBAAM,aAAa,eAAe,IAAI;AACtC,iBACE,+CAAC,2BACC;AAAA,2DAAC,QAAG,WAAU,sCACZ;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,iBAAe;AAAA,kBACf,cAAY,aAAa,aAAa;AAAA,kBACtC,SAAS,MAAM,cAAc,aAAa,OAAO,IAAI,EAAE;AAAA,kBACvD,WAAU;AAAA,kBAEV,wDAAC,eAAY,MAAM,YAAY;AAAA;AAAA,cACjC;AAAA,cACA,+CAAC,SAAI,WAAU,kBACb;AAAA,+DAAC,SAAI,WAAU,qCACb;AAAA,gEAAC,UAAK,WAAU,2CAA2C,cAAI,aAAa,IAAI,IAAG;AAAA,kBACnF,8CAAC,iCAAY,SAASC,eAAc,IAAI,MAAM,GAAG,YAAW,OACzD,cAAI,QACP;AAAA,mBACF;AAAA,gBACA,8CAAC,SAAI,WAAU,qDAAqD,cAAI,eAAc;AAAA,gBACtF,+CAAC,SAAI,WAAU,0EACb;AAAA,iEAAC,UAAK,WAAU,gBAAgB;AAAA,wBAAI;AAAA,oBAAa;AAAA,qBAAS;AAAA,kBAC1D,8CAAC,UAAK,eAAY,QAAO,WAAU,eAAc,kBAAC;AAAA,kBAClD,+CAAC,UAAK,WAAU,gBAAe;AAAA;AAAA,wBAAY,kCAAe,IAAI,WAAW;AAAA,qBAAE;AAAA,mBAC7E;AAAA,iBACF;AAAA,cACA,+CAAC,SAAI,WAAU,sCACb;AAAA,8DAAC,4BAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAAK,UAAU,OAAO,WAAW,SAAS,MAAM,OAAO,OAAO,IAAI,EAAE,GAAG,oBAEpH;AAAA,gBACA,8CAAC,4BAAO,MAAK,UAAS,SAAQ,SAAQ,MAAK,MAAK,WAAU,oBAAmB,UAAU,QAAQ,WAAW,SAAS,MAAM,QAAQ,OAAO,IAAI,EAAE,GAAG,qBAEjJ;AAAA,iBACF;AAAA,eACF;AAAA,YACC,cACC,8CAAC,QAAG,WAAU,sCACZ,wDAAC,uBAAoB,IAAI,IAAI,IAAI,UAAoB,GACvD;AAAA,eArCW,IAAI,EAuCnB;AAAA,QAEJ,CAAC,GACH;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA,QAAQ,MAAM,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AAAA,YAC/C,QAAQ,MAAM,QAAQ,CAAC,MAAM,KAAK,IAAI,YAAY,IAAI,CAAC,CAAC;AAAA;AAAA,QAC1D;AAAA,SACF;AAAA,OAEJ;AAAA,KACF;AAEJ;AAIA,SAAS,YAAY,EAAE,KAAK,GAAsB;AAChD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAW,sBAAG,sDAAsD,QAAQ,WAAW;AAAA,MAEvF,wDAAC,UAAK,GAAE,iBAAgB;AAAA;AAAA,EAC1B;AAEJ;AAEA,SAAS,YAAY;AACnB,SACE,+CAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAC9G;AAAA,kDAAC,YAAO,IAAG,KAAI,IAAG,MAAK,GAAE,KAAI;AAAA,IAC7B,8CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,IAC9B,8CAAC,UAAK,GAAE,gBAAe;AAAA,IACvB,8CAAC,UAAK,GAAE,yBAAwB;AAAA,IAChC,8CAAC,UAAK,GAAE,+DAA8D;AAAA,KACxE;AAEJ;;;AC/SA,IAAAC,iBAAkC;AAClC,IAAAC,oBAA6B;AAC7B,IAAAC,uBAA4C;AAkJtC,IAAAC,uBAAA;AAtHN,SAASC,WACP,MACgB;AAChB,MAAI,CAAC,KAAM,QAAO,CAAC;AACnB,MAAI,MAAM,QAAQ,IAAI,EAAG,QAAO;AAChC,MAAI,aAAa,QAAQ,MAAM,QAAS,KAAyB,OAAO,GAAG;AACzE,WAAQ,KAAyB,WAAW,CAAC;AAAA,EAC/C;AACA,SAAO,OAAO,OAAO,IAAoC,EAAE;AAAA,IACzD,CAAC,UACC,OAAO,UAAU,YACjB,UAAU,QACV,SAAS,SACT,YAAY,SACZ,WAAW;AAAA,EACf;AACF;AAOO,SAAS,cAAc,EAAE,WAAW,QAAQ,UAAU,GAAuB;AAClF,QAAM,YAAQ,4BAAS;AACvB,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAS,EAAE;AACvC,QAAM,CAAC,WAAW,YAAY,QAAI,yBAAwB,IAAI;AAC9D,QAAM,CAAC,WAAW,YAAY,QAAI,yBAAS,EAAE;AAC7C,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAS,EAAE;AACvC,QAAM,CAAC,WAAW,YAAY,QAAI,yBAAS,EAAE;AAC7C,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,EAAE;AAE3C,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI,kCAE5C,CAAC,cAAc,GAAG,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,sBAAsB,CAAC;AAE7E,QAAM,kBAAkB,CAAC,UAMvB,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,IACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,EACrE,CAAC;AAEH,QAAM,aAAS;AAAA,IACb,CAAC,QAAQ,YACP,OAAO,IAAI,GAAG,QAAQ,yBAAyB,mBAAmB,QAAQ,GAAG,CAAC,IAAI;AAAA,MAChF,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,IACH;AAAA,MACE,aAAa,CAAC,CAAC,cAAc,CAAC;AAAA,MAC9B,WAAW,MAAM;AACf,cAAM,QAAQ,aAAa;AAC3B,qBAAa,IAAI;AACjB,aAAK,QAAQ;AAAA,MACf;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,UAAM;AAAA,IACV,CAAC,QAAQ,YACP,OAAO,IAAI,GAAG,QAAQ,yBAAyB,mBAAmB,QAAQ,GAAG,CAAC,IAAI;AAAA,MAChF,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,IACH;AAAA,MACE,aAAa,CAAC,CAAC,cAAc,CAAC;AAAA,MAC9B,WAAW,MAAM;AACf,cAAM,QAAQ,aAAa;AAC3B,kBAAU,EAAE;AACZ,qBAAa,EAAE;AACf,oBAAY,EAAE;AACd,aAAK,QAAQ;AAAA,MACf;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,aAAS;AAAA,IACb,CAAC,QAAQ,YACP,OAAO;AAAA,MACL,GAAG,QAAQ,yBAAyB,mBAAmB,QAAQ,GAAG,CAAC,WAAW,mBAAmB,QAAQ,MAAM,CAAC;AAAA,IAClH;AAAA,IACF;AAAA,MACE,aAAa,CAAC,CAAC,cAAc,CAAC;AAAA,MAC9B,WAAW,MAAM;AACf,cAAM,QAAQ,eAAe;AAC7B,aAAK,QAAQ;AAAA,MACf;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,cAAU,wBAAQ,MAAMA,WAAU,IAAI,GAAG,CAAC,IAAI,CAAC;AACrD,QAAM,eAAW,wBAAQ,MAAM;AAC7B,UAAM,IAAI,OAAO,KAAK,EAAE,YAAY;AACpC,QAAI,CAAC,EAAG,QAAO;AACf,WAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,IAAI,YAAY,EAAE,SAAS,CAAC,CAAC;AAAA,EAC9D,GAAG,CAAC,SAAS,MAAM,CAAC;AAEpB,QAAM,QAAQ,CAAC,UAA2B;AACxC,UAAM,eAAe;AACrB,QAAI,OAAO,EAAE,KAAK,OAAO,KAAK,GAAG,QAAQ,UAAU,KAAK,GAAG,OAAO,SAAS,CAAC;AAAA,EAC9E;AAEA,QAAM,YAAY,CAAC,UAAwB;AACzC,iBAAa,GAAG,MAAM,GAAG,IAAI,MAAM,MAAM,EAAE;AAC3C,iBAAa,MAAM,KAAK;AAAA,EAC1B;AAEA,QAAM,UACJ,+CAAC,UAAK,UAAU,OAAO,WAAU,kCAAiC,YAAU,MAC1E;AAAA,mDAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,mBAAkB,WAAU,uCAAsC,iBAEjF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK;AAAA,UACzC,WAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,IACA,+CAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,sBAAqB,WAAU,uCAAsC,oBAEpF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,aAAa,EAAE,OAAO,KAAK;AAAA,UAC5C,WAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,IACA,+CAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,qBAAoB,WAAU,uCAAsC,mBAEnF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK;AAAA,UAC3C,WAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAU,IAAI;AAAA,QACd,WAAU;AAAA,QAET,cAAI,YAAY,iBAAY;AAAA;AAAA,IAC/B;AAAA,KACF;AAGF,QAAM,cACJ,+CAAC,SAAI,WAAU,uBACb;AAAA,kDAAC,WAAM,SAAQ,kBAAiB,WAAU,uCAAsC,2BAEhF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,IAAG;AAAA,QACH,MAAK;AAAA,QACL,OAAO;AAAA,QACP,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK;AAAA,QACzC,WAAU;AAAA;AAAA,IACZ;AAAA,KACF;AAGF,MAAI;AAEJ,MAAI,WAAW;AACb,WACE,+CAAC,SAAI,MAAK,UAAS,cAAW,mBAAkB,WAAU,2BACxD;AAAA,oDAAC,UAAK,WAAU,WAAU,6BAAe;AAAA,MACxC,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA,OACH;AAAA,EAEJ,WAAW,SAAS;AAClB,WACE,+CAAC,SAAI,WAAU,uCACb;AAAA,oDAAC,OAAE,WAAU,2BAA0B,oCAAsB;AAAA,MAC7D;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ,WAAW,SAAS,WAAW,GAAG;AAChC,WACE,8CAAC,SAAI,WAAU,iDACZ,kBAAQ,WAAW,IAAI,uBAAuB,gCACjD;AAAA,EAEJ,OAAO;AACL,WACE,+CAAC,WAAM,WAAU,kBACf;AAAA,oDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,sDAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,iBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,mBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBACxB,wDAAC,UAAK,WAAU,WAAU,qBAAO,GACnC;AAAA,SACF,GACF;AAAA,MACA,8CAAC,WACE,mBAAS,IAAI,CAAC,UAAU;AACvB,cAAM,QAAQ,GAAG,MAAM,GAAG,IAAI,MAAM,MAAM;AAC1C,cAAM,YAAY,cAAc;AAChC,eACE,+CAAC,QAAe,WAAU,0BACxB;AAAA,wDAAC,QAAG,WAAU,uCAAuC,gBAAM,KAAI;AAAA,UAC/D,8CAAC,QAAG,WAAU,6BAA6B,gBAAM,QAAO;AAAA,UACxD,8CAAC,QAAG,WAAU,6BACX,sBACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAY,aAAa,MAAM,GAAG,KAAK,MAAM,MAAM;AAAA,cACnD,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,aAAa,EAAE,OAAO,KAAK;AAAA,cAC5C,WAAU;AAAA;AAAA,UACZ,IAEA,MAAM,OAEV;AAAA,UACA,8CAAC,QAAG,WAAU,aACZ,wDAAC,SAAI,WAAU,2BACZ,sBACC,gFACE;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,UAAU,OAAO;AAAA,gBACjB,SAAS,MACP,OAAO,OAAO;AAAA,kBACZ,KAAK,MAAM;AAAA,kBACX,QAAQ,MAAM;AAAA,kBACd,OAAO;AAAA,gBACT,CAAC;AAAA,gBAEH,WAAU;AAAA,gBACX;AAAA;AAAA,YAED;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,MAAM,aAAa,IAAI;AAAA,gBAChC,WAAU;AAAA,gBACX;AAAA;AAAA,YAED;AAAA,aACF,IAEA,gFACE;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,MAAM,UAAU,KAAK;AAAA,gBAC9B,WAAU;AAAA,gBACX;AAAA;AAAA,YAED;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,UAAU,OAAO;AAAA,gBACjB,SAAS,MAAM,OAAO,OAAO,EAAE,KAAK,MAAM,KAAK,QAAQ,MAAM,OAAO,CAAC;AAAA,gBACrE,WAAU;AAAA,gBACX;AAAA;AAAA,YAED;AAAA,aACF,GAEJ,GACF;AAAA,aA9DO,KA+DT;AAAA,MAEJ,CAAC,GACH;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,+CAAC,aAAQ,cAAW,kBAAiB,eAAW,sBAAG,uBAAuB,SAAS,GAChF;AAAA;AAAA,IACA;AAAA,IACA;AAAA,KACH;AAEJ;;;ACrVA,IAAAC,oBAAmB;AACnB,IAAAC,uBAA4B;AAqCtB,IAAAC,uBAAA;AApBN,SAASC,WAAU,MAAoE;AACrF,MAAI,MAAM,QAAQ,IAAI,EAAG,QAAO;AAChC,SAAO,MAAM,WAAW,CAAC;AAC3B;AAMO,SAAS,yBAAyB;AAAA,EACvC,WAAW;AAAA,EACX;AACF,GAAkC;AAChC,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,cAAc;AAAA,IACf,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,uBAAuB;AAAA,EAC3D;AAEA,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,0CAA4B;AAAA,UACrD,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,iDAAmC;AAAA,MAC1E;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,OAAOA,WAAU,IAAI;AAE3B,MAAI,KAAK,WAAW,GAAG;AACrB,WACE,8CAAC,SAAI,eAAW,sBAAG,iDAAiD,SAAS,GAAG,qCAEhF;AAAA,EAEJ;AAEA,SACE,8CAAC,aAAQ,cAAW,wBAAuB,eAAW,sBAAG,uBAAuB,SAAS,GACvF,yDAAC,WAAM,WAAU,kBACf;AAAA,kDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,oDAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,iBAElD;AAAA,MACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAElD;AAAA,MACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,kBAElD;AAAA,OACF,GACF;AAAA,IACA,8CAAC,WACE,eAAK,IAAI,CAAC,KAAK,MACd,+CAAC,QAAyC,WAAU,0BAClD;AAAA,oDAAC,QAAG,WAAU,uCAAuC,cAAI,KAAI;AAAA,MAC7D,8CAAC,QAAG,WAAU,6BAA6B,cAAI,QAAO;AAAA,MACtD,8CAAC,QAAG,WAAU,mCAAmC,cAAI,QAAQ,UAAI;AAAA,SAH1D,GAAG,IAAI,GAAG,IAAI,IAAI,MAAM,IAAI,CAAC,EAItC,CACD,GACH;AAAA,KACF,GACF;AAEJ;;;ACxGA,IAAAC,oBAAmB;AACnB,IAAAC,uBAA4B;AAmCtB,IAAAC,uBAAA;AAjBN,SAASC,WAAU,MAAuE;AACxF,MAAI,MAAM,QAAQ,IAAI,EAAG,QAAO;AAChC,SAAO,MAAM,WAAW,CAAC;AAC3B;AAMO,SAAS,oBAAoB,EAAE,WAAW,QAAQ,UAAU,GAA6B;AAC9F,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,sBAAsB;AAAA,IACvB,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,+BAA+B;AAAA,EACnE;AAEA,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,qCAAuB;AAAA,UAChD,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,4CAA8B;AAAA,MACrE;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,OAAOA,WAAU,IAAI;AAE3B,MAAI,KAAK,WAAW,GAAG;AACrB,WACE,8CAAC,SAAI,eAAW,sBAAG,iDAAiD,SAAS,GAAG,mCAEhF;AAAA,EAEJ;AAEA,SACE,8CAAC,aAAQ,cAAW,mBAAkB,eAAW,sBAAG,uBAAuB,SAAS,GAClF,yDAAC,WAAM,WAAU,kBACf;AAAA,kDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,oDAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,iBAElD;AAAA,MACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,uBAElD;AAAA,MACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,sBAElD;AAAA,MACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,mBAElD;AAAA,OACF,GACF;AAAA,IACA,8CAAC,WACE,eAAK,IAAI,CAAC,KAAK,MACd,+CAAC,QAAkD,WAAU,0BAC3D;AAAA,oDAAC,QAAG,WAAU,uCAAuC,cAAI,KAAI;AAAA,MAC7D,8CAAC,QAAG,WAAU,6BAA6B,cAAI,iBAAgB;AAAA,MAC/D,8CAAC,QAAG,WAAU,6BAA6B,cAAI,gBAAe;AAAA,MAC9D,8CAAC,QAAG,WAAU,mCACX,cAAI,SAAS,IAAI,MAAM,SAAS,IAC/B,8CAAC,QAAG,WAAU,qCACX,cAAI,MAAM,IAAI,CAAC,MAAM,OACpB,+CAAC,QAAyB,WAAU,2BAClC;AAAA,sDAAC,UAAK,WAAU,0DACb,gBACH;AAAA,QACC,MAAM,IAAI,OAAO,UAAU,KAAK,KAC/B,8CAAC,UAAK,eAAY,QAAO,WAAU,yBAAwB,oBAE3D;AAAA,WAPK,GAAG,IAAI,IAAI,EAAE,EAStB,CACD,GACH,IAEA,UAEJ;AAAA,SAvBO,GAAG,IAAI,GAAG,IAAI,IAAI,eAAe,IAAI,CAAC,EAwB/C,CACD,GACH;AAAA,KACF,GACF;AAEJ;;;AC7HA,IAAAC,iBAAyB;AACzB,IAAAC,oBAA6C;AAC7C,IAAAC,uBAA4C;AAwGtC,IAAAC,uBAAA;AA3EN,IAAMC,SAAQ;AAOP,SAAS,oBAAoB,EAAE,WAAW,QAAQ,UAAU,GAA6B;AAC9F,QAAM,YAAQ,4BAAS;AACvB,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAS,CAAC;AAClC,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAS,EAAE;AACvC,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAAS,EAAE;AAErC,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,cAAc,MAAM,KAAK;AAAA,IAC1B,CAAC,WACC,OAAO;AAAA,MACL,GAAG,QAAQ,6BAA6B,IAAI,UAAUA,MAAK,WAAW,mBAAmB,KAAK,CAAC;AAAA,IACjG;AAAA,EACJ;AAEA,QAAM,kBAAkB,CAAC,UAMvB,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,IACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,EACrE,CAAC;AAEH,QAAM,iBAAa;AAAA,IACjB,CAAC,QAAQ,WAAW,OAAO,KAAK,GAAG,QAAQ,wBAAwB,MAAM,WAAW,CAAC,CAAC;AAAA,IACtF;AAAA,MACE,WAAW,MAAM,MAAM,QAAQ,cAAc;AAAA,MAC7C,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,YAAQ;AAAA,IACZ,CAAC,QAAQ,WAAW,OAAO,OAAO,GAAG,QAAQ,wBAAwB,MAAM,QAAQ;AAAA,IACnF;AAAA,MACE,aAAa,CAAC,CAAC,YAAY,CAAC;AAAA,MAC5B,WAAW,MAAM;AACf,cAAM,QAAQ,kBAAkB;AAChC,aAAK,QAAQ;AAAA,MACf;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,WAAW,CAAC,UAA2B;AAC3C,UAAM,eAAe;AACrB,YAAQ,CAAC;AACT,aAAS,OAAO,KAAK,CAAC;AAAA,EACxB;AAEA,QAAM,UAAU,CAAC,WAAmB;AAClC,QAAI,OAAO,QAAQ,2DAA2D,GAAG;AAC/E,YAAM,OAAO,MAAM;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,WAAW,CAAC,QAAkC;AAClD,UAAM,SAAmB,CAAC;AAC1B,QAAI,IAAI,aAAc,QAAO,KAAK,OAAO;AACzC,QAAI,IAAI,YAAa,QAAO,KAAK,MAAM;AACvC,QAAI,IAAI,WAAY,QAAO,KAAK,KAAK;AACrC,WAAO,OAAO,SAAS,IAAI,OAAO,KAAK,IAAI,IAAI;AAAA,EACjD;AAEA,QAAM,aACJ,+CAAC,UAAK,UAAU,UAAU,WAAU,kCAAiC,YAAU,MAC7E;AAAA,mDAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,oBAAmB,WAAU,uCAAsC,+BAElF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK;AAAA,UACzC,WAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,KACF;AAGF,MAAI;AAEJ,MAAI,WAAW;AACb,WACE,+CAAC,SAAI,MAAK,UAAS,cAAW,sBAAqB,WAAU,2BAC3D;AAAA,oDAAC,UAAK,WAAU,WAAU,gCAAkB;AAAA,MAC3C,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA,OACH;AAAA,EAEJ,WAAW,SAAS;AAClB,WACE,+CAAC,SAAI,WAAU,uCACb;AAAA,oDAAC,OAAE,WAAU,2BAA0B,uCAAyB;AAAA,MAChE;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ,OAAO;AACL,UAAM,OAAO,MAAM,SAAS,CAAC;AAC7B,UAAM,aAAa,MAAM,cAAc;AAEvC,QAAI,KAAK,WAAW,GAAG;AACrB,aAAO,8CAAC,SAAI,WAAU,iDAAgD,2BAAa;AAAA,IACrF,OAAO;AACL,aACE,gFACE;AAAA,uDAAC,WAAM,WAAU,kBACf;AAAA,wDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,0DAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,kBAElD;AAAA,YACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,mBAElD;AAAA,YACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,mBAElD;AAAA,YACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,sBAElD;AAAA,YACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,qBAElD;AAAA,YACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBACxB,wDAAC,UAAK,WAAU,WAAU,qBAAO,GACnC;AAAA,aACF,GACF;AAAA,UACA,8CAAC,WACE,eAAK,IAAI,CAAC,QACT,+CAAC,QAAoB,WAAU,0BAC7B;AAAA,0DAAC,QAAG,WAAU,uCAAuC,cAAI,QAAO;AAAA,YAChE,8CAAC,QAAG,WAAU,6BAA6B,cAAI,SAAS,UAAI;AAAA,YAC5D,8CAAC,QAAG,WAAU,6BAA6B,cAAI,SAAS,UAAI;AAAA,YAC5D,8CAAC,QAAG,WAAU,mCAAmC,mBAAS,GAAG,GAAE;AAAA,YAC/D,8CAAC,QAAG,WAAU,mCACX,gDAAe,IAAI,SAAS,GAC/B;AAAA,YACA,8CAAC,QAAG,WAAU,aACZ,yDAAC,SAAI,WAAU,2BACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,UAAU,WAAW;AAAA,kBACrB,SAAS,MAAM,WAAW,OAAO,IAAI,MAAM;AAAA,kBAC3C,WAAU;AAAA,kBACX;AAAA;AAAA,cAED;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,UAAU,MAAM;AAAA,kBAChB,SAAS,MAAM,QAAQ,IAAI,MAAM;AAAA,kBACjC,WAAU;AAAA,kBACX;AAAA;AAAA,cAED;AAAA,eACF,GACF;AAAA,eA3BO,IAAI,MA4Bb,CACD,GACH;AAAA,WACF;AAAA,QACA,+CAAC,SAAI,cAAW,wBAAuB,WAAU,qCAC/C;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AAAA,cAChD,UAAU,QAAQ;AAAA,cAClB,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,UACA,+CAAC,UAAK,WAAU,iCAAgC;AAAA;AAAA,YACxC;AAAA,YAAK;AAAA,YAAK;AAAA,aAClB;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,QAAQ,CAAC,MAAM,KAAK,IAAI,YAAY,IAAI,CAAC,CAAC;AAAA,cACzD,UAAU,QAAQ;AAAA,cAClB,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,WACF;AAAA,SACF;AAAA,IAEJ;AAAA,EACF;AAEA,SACE,+CAAC,aAAQ,cAAW,4BAA2B,eAAW,sBAAG,uBAAuB,SAAS,GAC1F;AAAA;AAAA,IACA;AAAA,KACH;AAEJ;;;ACzPA,IAAAC,iBAAmC;AACnC,IAAAC,oBAA0D;AAC1D,IAAAC,uBAA4C;AAsFtC,IAAAC,uBAAA;AA9CN,IAAM,cAAc;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,mBACP,MACmB;AACnB,MAAI,MAAM,QAAQ,IAAI,EAAG,QAAO;AAChC,SAAO,MAAM,SAAS,CAAC;AACzB;AAEA,SAAS,oBACP,MACmB;AACnB,MAAI,MAAM,QAAQ,IAAI,EAAG,QAAO;AAChC,SAAO,MAAM,SAAS,CAAC;AACzB;AASA,SAAS,WAAW,OAAoC,OAAmB;AACzE,QAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,IACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,EACrE,CAAC;AACH;AAGA,SAAS,kBAAkB,EAAE,YAAY,SAAS,GAA6C;AAC7F,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAE5C,CAAC,sBAAsB,UAAU;AAAA,IAAG,CAAC,WACrC,OAAO,IAAI,GAAG,QAAQ,sBAAsB,UAAU,aAAa;AAAA,EACrE;AAEA,MAAI,WAAW;AACb,WACE,+CAAC,SAAI,MAAK,UAAS,cAAW,sBAAqB,WAAU,2BAC3D;AAAA,oDAAC,UAAK,WAAU,WAAU,gCAAkB;AAAA,MAC3C,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,MACX,8CAAC,SAAY,eAAY,QAAO,WAAU,wCAAhC,CAAqE,CAChF;AAAA,OACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,WAAU,uCACb;AAAA,oDAAC,OAAE,WAAU,2BAA0B,uCAAyB;AAAA,MAChE;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,OAAO,oBAAoB,IAAI;AAErC,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO,8CAAC,SAAI,WAAU,iDAAgD,2BAAa;AAAA,EACrF;AAEA,SACE,+CAAC,WAAM,WAAU,kBACf;AAAA,kDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,oDAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,sBAElD;AAAA,MACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAElD;AAAA,MACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,qBAElD;AAAA,OACF,GACF;AAAA,IACA,8CAAC,WACE,eAAK,IAAI,CAAC,QACT,+CAAC,QAAgB,WAAU,0BACzB;AAAA,oDAAC,QAAG,WAAU,uCAAuC,cAAI,IAAG;AAAA,MAC5D,8CAAC,QAAG,WAAU,mCAAmC,cAAI,QAAO;AAAA,MAC5D,8CAAC,QAAG,WAAU,mCAAmC,gDAAe,IAAI,SAAS,GAAE;AAAA,SAHxE,IAAI,EAIb,CACD,GACH;AAAA,KACF;AAEJ;AAOO,SAAS,uBAAuB;AAAA,EACrC,WAAW;AAAA,EACX;AACF,GAAgC;AAC9B,QAAM,YAAQ,4BAAS;AACvB,QAAM,CAAC,KAAK,MAAM,QAAI,yBAAS,EAAE;AACjC,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAmB,CAAC,CAAC;AACjD,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAS,IAAI;AACzC,QAAM,CAAC,UAAU,WAAW,QAAI,yBAA6B;AAC7D,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAwB,IAAI;AAEhE,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI,kCAE5C,CAAC,mBAAmB,GAAG,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,oBAAoB,CAAC;AAEhF,QAAM,aAAS;AAAA,IACb,CAAC,QAAQ,YAAY,OAAO,KAAK,GAAG,QAAQ,sBAAsB,OAAO;AAAA,IACzE;AAAA,MACE,aAAa,CAAC,CAAC,mBAAmB,CAAC;AAAA,MACnC,WAAW,MAAM;AACf,cAAM,QAAQ,kBAAkB;AAChC,eAAO,EAAE;AACT,kBAAU,CAAC,CAAC;AACZ,kBAAU,IAAI;AACd,aAAK,QAAQ;AAAA,MACf;AAAA,MACA,SAAS,CAAC,UAAU,WAAW,OAAO,KAAK;AAAA,IAC7C;AAAA,EACF;AAEA,QAAM,aAAS;AAAA,IACb,CAAC,QAAQ,YACP,OAAO,MAAM,GAAG,QAAQ,sBAAsB,QAAQ,EAAE,IAAI,EAAE,QAAQ,QAAQ,OAAO,CAAC;AAAA,IACxF;AAAA,MACE,aAAa,CAAC,CAAC,mBAAmB,CAAC;AAAA,MACnC,WAAW,MAAM;AACf,cAAM,QAAQ,kBAAkB;AAChC,aAAK,QAAQ;AAAA,MACf;AAAA,MACA,SAAS,CAAC,UAAU,WAAW,OAAO,KAAK;AAAA,IAC7C;AAAA,EACF;AAEA,QAAM,aAAS;AAAA,IACb,CAAC,QAAQ,OAAO,OAAO,OAAO,GAAG,QAAQ,sBAAsB,EAAE,EAAE;AAAA,IACnE;AAAA,MACE,aAAa,CAAC,CAAC,mBAAmB,CAAC;AAAA,MACnC,WAAW,MAAM;AACf,cAAM,QAAQ,kBAAkB;AAChC,aAAK,QAAQ;AAAA,MACf;AAAA,MACA,SAAS,CAAC,UAAU,WAAW,OAAO,KAAK;AAAA,IAC7C;AAAA,EACF;AAEA,QAAM,cAAc,CAAC,UAAkB;AACrC;AAAA,MAAU,CAAC,SACT,KAAK,SAAS,KAAK,IAAI,KAAK,OAAO,CAAC,MAAM,MAAM,KAAK,IAAI,CAAC,GAAG,MAAM,KAAK;AAAA,IAC1E;AAAA,EACF;AAEA,QAAM,WAAW,CAAC,UAA2B;AAC3C,UAAM,eAAe;AACrB,UAAM,UAAU,IAAI,KAAK;AACzB,QAAI,CAAC,SAAS;AACZ,kBAAY,iBAAiB;AAC7B;AAAA,IACF;AACA,QAAI,CAAC,QAAQ,WAAW,MAAM,GAAG;AAC/B,kBAAY,0BAA0B;AACtC;AAAA,IACF;AACA,gBAAY,MAAS;AACrB,WAAO,OAAO,EAAE,KAAK,SAAS,QAAQ,OAAO,CAAC;AAAA,EAChD;AAEA,QAAM,WAAW,CAAC,OAAe;AAC/B,QAAI,OAAO,QAAQ,+BAA+B,GAAG;AACnD,aAAO,OAAO,EAAE;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,aACJ,+CAAC,UAAK,UAAU,UAAU,WAAU,uBAAsB,YAAU,MAClE;AAAA,mDAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,eAAc,WAAU,uCAAsC,0BAE7E;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,OAAO;AAAA,UACP,gBAAc,WAAW,SAAS;AAAA,UAClC,oBAAkB,WAAW,sBAAsB;AAAA,UACnD,UAAU,CAAC,MAAM,OAAO,EAAE,OAAO,KAAK;AAAA,UACtC,WAAU;AAAA;AAAA,MACZ;AAAA,MACC,YACC,8CAAC,OAAE,IAAG,qBAAoB,WAAU,4BACjC,oBACH;AAAA,OAEJ;AAAA,IACA,+CAAC,cAAS,WAAU,uBAClB;AAAA,oDAAC,YAAO,WAAU,uCAAsC,oBAAM;AAAA,MAC9D,8CAAC,SAAI,WAAU,wBACZ,sBAAY,IAAI,CAAC,QAAQ;AACxB,cAAM,KAAK,iBAAiB,GAAG;AAC/B,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,SAAS;AAAA,YACT,WAAU;AAAA,YAEV;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC;AAAA,kBACA,MAAK;AAAA,kBACL,SAAS,OAAO,SAAS,GAAG;AAAA,kBAC5B,UAAU,MAAM,YAAY,GAAG;AAAA,kBAC/B,WAAU;AAAA;AAAA,cACZ;AAAA,cACC;AAAA;AAAA;AAAA,UAXI;AAAA,QAYP;AAAA,MAEJ,CAAC,GACH;AAAA,OACF;AAAA,IACA,+CAAC,WAAM,SAAQ,kBAAiB,WAAU,mDACxC;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,SAAS;AAAA,UACT,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,OAAO;AAAA,UAC3C,WAAU;AAAA;AAAA,MACZ;AAAA,MAAE;AAAA,OAEJ;AAAA,IACA,8CAAC,SACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAU,OAAO;AAAA,QACjB,WAAU;AAAA,QAET,iBAAO,YAAY,mBAAc;AAAA;AAAA,IACpC,GACF;AAAA,KACF;AAGF,MAAI;AAEJ,MAAI,WAAW;AACb,WACE,+CAAC,SAAI,MAAK,UAAS,cAAW,6BAA4B,WAAU,2BAClE;AAAA,oDAAC,UAAK,WAAU,WAAU,uCAAyB;AAAA,MAClD,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA,OACH;AAAA,EAEJ,WAAW,SAAS;AAClB,WACE,+CAAC,SAAI,WAAU,uCACb;AAAA,oDAAC,OAAE,WAAU,2BAA0B,8CAAgC;AAAA,MACvE;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ,OAAO;AACL,UAAM,OAAO,mBAAmB,IAAI;AAEpC,QAAI,KAAK,WAAW,GAAG;AACrB,aACE,8CAAC,SAAI,WAAU,iDAAgD,kCAAoB;AAAA,IAEvF,OAAO;AACL,aACE,+CAAC,WAAM,WAAU,kBACf;AAAA,sDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,wDAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,iBAElD;AAAA,UACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAElD;AAAA,UACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAElD;AAAA,UACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,qBAElD;AAAA,UACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBACxB,wDAAC,UAAK,WAAU,WAAU,qBAAO,GACnC;AAAA,WACF,GACF;AAAA,QACA,8CAAC,WACE,eAAK,IAAI,CAAC,QAAQ;AACjB,gBAAM,aAAa,eAAe,IAAI;AACtC,iBACE,+CAAC,2BACC;AAAA,2DAAC,QAAG,WAAU,0BACZ;AAAA,4DAAC,QAAG,WAAU,uCAAuC,cAAI,KAAI;AAAA,cAC7D,8CAAC,QAAG,WAAU,mCACX,cAAI,OAAO,SAAS,IAAI,IAAI,OAAO,KAAK,IAAI,IAAI,UACnD;AAAA,cACA,8CAAC,QAAG,WAAU,aACZ,wDAAC,iCAAY,SAAS,IAAI,SAAS,YAAY,WAAW,YAAW,OAClE,cAAI,SAAS,WAAW,YAC3B,GACF;AAAA,cACA,8CAAC,QAAG,WAAU,mCACX,gDAAe,IAAI,SAAS,GAC/B;AAAA,cACA,8CAAC,QAAG,WAAU,aACZ,yDAAC,SAAI,WAAU,2BACb;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,UAAU,OAAO;AAAA,oBACjB,SAAS,MAAM,OAAO,OAAO,EAAE,IAAI,IAAI,IAAI,QAAQ,CAAC,IAAI,OAAO,CAAC;AAAA,oBAChE,WAAU;AAAA,oBAET,cAAI,SAAS,YAAY;AAAA;AAAA,gBAC5B;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS,MAAM,cAAc,aAAa,OAAO,IAAI,EAAE;AAAA,oBACvD,iBAAe;AAAA,oBACf,WAAU;AAAA,oBACX;AAAA;AAAA,gBAED;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,UAAU,OAAO;AAAA,oBACjB,SAAS,MAAM,SAAS,IAAI,EAAE;AAAA,oBAC9B,WAAU;AAAA,oBACX;AAAA;AAAA,gBAED;AAAA,iBACF,GACF;AAAA,eACF;AAAA,YACC,cACC,8CAAC,QAAG,WAAU,0BACZ,wDAAC,QAAG,SAAS,GAAG,WAAU,sBACxB,wDAAC,qBAAkB,YAAY,IAAI,IAAI,UAAoB,GAC7D,GACF;AAAA,eAhDW,IAAI,EAkDnB;AAAA,QAEJ,CAAC,GACH;AAAA,SACF;AAAA,IAEJ;AAAA,EACF;AAEA,SACE,+CAAC,aAAQ,cAAW,qBAAoB,eAAW,sBAAG,uBAAuB,SAAS,GACnF;AAAA;AAAA,IACA;AAAA,KACH;AAEJ;;;ACtaA,IAAAC,oBAYO;AACP,IAAAC,uBAA4B;AA4CpB,IAAAC,uBAAA;AAbD,SAAS,mBAAmB,EAAE,WAAW,QAAQ,UAAU,GAA4B;AAC5F,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,qBAAqB;AAAA,IACtB,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,oBAAoB;AAAA,EACxD;AAEA,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,uBAAuB,SAAS;AAAA,QAE9C;AAAA,wDAAC,UAAK,WAAU,WAAU,yCAA2B;AAAA,UACrD,8CAAC,SAAI,eAAY,QAAO,WAAU,yCAC/B,WAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,0BACC,yDAAC,iCAAY,WAAU,iBACrB;AAAA,0DAAC,8BAAS,WAAU,YAAW;AAAA,YAC/B,8CAAC,8BAAS,WAAU,YAAW;AAAA,aACjC,KAJS,CAKX,CACD,GACH;AAAA,UACA,8CAAC,0BAAK,eAAY,QAChB,wDAAC,iCAAY,WAAU,iBACpB,WAAC,GAAG,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACjB,8CAAC,8BAAiB,WAAU,iBAAb,CAA2B,CAC3C,GACH,GACF;AAAA;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,8CAAC,0BAAK,WACJ,yDAAC,iCAAY,WAAU,oDACrB;AAAA,oDAAC,OAAE,WAAU,2BAA0B,gDAAkC;AAAA,MACzE,8CAAC,4BAAO,MAAK,UAAS,SAAS,MAAM,KAAK,QAAQ,GAAG,uBAErD;AAAA,OACF,GACF;AAAA,EAEJ;AAEA,MAAI,CAAC,MAAM;AACT,WAAO,8CAAC,gCAAW,WAAsB,OAAM,oBAAmB;AAAA,EACpE;AAEA,QAAM,cAAc,KAAK;AACzB,QAAM,WAAW,KAAK,YAAY,CAAC;AACnC,QAAM,aAAa,KAAK;AAExB,QAAM,QAAiD;AAAA,IACrD,EAAE,OAAO,UAAU,WAAW,MAAM,OAAO,KAAK,WAAW;AAAA,IAC3D,EAAE,OAAO,cAAc,WAAW,MAAM,OAAO,KAAK,eAAe;AAAA,IACnE,EAAE,OAAO,WAAW,WAAW,MAAM,OAAO,KAAK,YAAY;AAAA,EAC/D;AAEA,SACE,+CAAC,aAAQ,cAAW,uBAAsB,eAAW,sBAAG,uBAAuB,SAAS,GACtF;AAAA,mDAAC,SAAI,WAAU,uDACb;AAAA,qDAAC,SACC;AAAA,sDAAC,QAAG,WAAU,0DAAyD,iCAEvE;AAAA,QACA,+CAAC,OAAE,WAAU,wCAAuC;AAAA;AAAA,UAAM;AAAA,UAAY;AAAA,WAAC;AAAA,SACzE;AAAA,MACA,+CAAC,OAAE,WAAU,iCAAgC;AAAA;AAAA,YAChC,kCAAe,KAAK,WAAW;AAAA,SAC5C;AAAA,OACF;AAAA,IAEA,8CAAC,SAAI,WAAU,yCACZ,gBAAM,IAAI,CAAC,SACV,8CAAC,8BAA0B,OAAO,KAAK,OAAO,OAAO,KAAK,SAA3C,KAAK,KAA6C,CAClE,GACH;AAAA,IAEA,8CAAC,0BACC,yDAAC,iCAAY,WAAU,mDACrB;AAAA,qDAAC,SAAI,WAAU,2BACb;AAAA,sDAAC,UAAK,WAAU,iCAAgC,yBAAW;AAAA,QAC3D,8CAAC,iCAAY,SAAS,aAAa,IAAI,gBAAgB,WAAW,YAAW,SAC1E,sBACH;AAAA,SACF;AAAA,MACA,+CAAC,SAAI,WAAU,2BACb;AAAA,sDAAC,UAAK,WAAU,iCAAgC,kCAAoB;AAAA,QACpE,8CAAC,UAAK,WAAU,sDACb,eAAK,oBACR;AAAA,SACF;AAAA,MACA,+CAAC,SAAI,WAAU,2BACb;AAAA,sDAAC,UAAK,WAAU,iCAAgC,mBAAK;AAAA,QACrD,8CAAC,iCAAY,SAAS,KAAK,eAAe,YAAY,eAAe,YAAW,SAC7E,eAAK,eAAe,YAAY,aACnC;AAAA,SACF;AAAA,OACF,GACF;AAAA,IAEA,+CAAC,0BACC;AAAA,oDAAC,gCACC,wDAAC,+BAAU,+BAAiB,GAC9B;AAAA,MACA,8CAAC,iCAAY,WAAU,OACrB,yDAAC,WAAM,WAAU,kBACf;AAAA,sDAAC,WACC,yDAAC,QAAG,WAAU,2FACZ;AAAA,wDAAC,QAAG,OAAM,OAAM,WAAU,2BAA0B,qBAEpD;AAAA,UACA,8CAAC,QAAG,OAAM,OAAM,WAAU,oCAAmC,mBAE7D;AAAA,UACA,8CAAC,QAAG,OAAM,OAAM,WAAU,oCAAmC,uBAE7D;AAAA,UACA,8CAAC,QAAG,OAAM,OAAM,WAAU,oCAAmC,oBAE7D;AAAA,WACF,GACF;AAAA,QACA,8CAAC,WACE,mBAAS,WAAW,IACnB,8CAAC,QACC,wDAAC,QAAG,SAAS,GAAG,WAAU,+CAA8C,iCAExE,GACF,IAEA,SAAS,IAAI,CAAC,QACZ;AAAA,UAAC;AAAA;AAAA,YAEC,WAAU;AAAA,YAEV;AAAA,4DAAC,QAAG,WAAU,yCAAyC,cAAI,SAAQ;AAAA,cACnE,8CAAC,QAAG,WAAU,yDACX,cAAI,OACP;AAAA,cACA,8CAAC,QAAG,WAAU,yDACX,cAAI,WACP;AAAA,cACA,8CAAC,QAAG,WAAU,yDACX,cAAI,QACP;AAAA;AAAA;AAAA,UAZK,IAAI;AAAA,QAaX,CACD,GAEL;AAAA,SACF,GACF;AAAA,OACF;AAAA,KACF;AAEJ;;;AC3MA,IAAAC,iBAAyB;AACzB,IAAAC,oBAAmG;AACnG,IAAAC,uBAA4B;AA+GhB,IAAAC,uBAAA;AA1EZ,IAAMC,SAAQ;AAEd,IAAM,gBAAyB;AAAA,EAC7B,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,IAAI;AACN;AAEA,SAAS,eAAe,SAAqC;AAC3D,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAOO,SAAS,oBAAoB,EAAE,WAAW,QAAQ,UAAU,GAA6B;AAC9F,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAS,CAAC;AAClC,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAAkB,aAAa;AACzD,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAkB,aAAa;AAE7D,QAAM,eAAe,MAAM;AACzB,UAAM,SAAS,IAAI,gBAAgB;AACnC,WAAO,IAAI,QAAQ,OAAO,IAAI,CAAC;AAC/B,WAAO,IAAI,SAAS,OAAOA,MAAK,CAAC;AACjC,QAAI,QAAQ,QAAS,QAAO,IAAI,WAAW,QAAQ,OAAO;AAC1D,QAAI,QAAQ,OAAQ,QAAO,IAAI,UAAU,QAAQ,MAAM;AACvD,QAAI,QAAQ,OAAQ,QAAO,IAAI,UAAU,QAAQ,MAAM;AACvD,QAAI,QAAQ,UAAW,QAAO,IAAI,aAAa,QAAQ,SAAS;AAChE,QAAI,QAAQ,KAAM,QAAO,IAAI,QAAQ,QAAQ,IAAI;AACjD,QAAI,QAAQ,GAAI,QAAO,IAAI,MAAM,QAAQ,EAAE;AAC3C,WAAO,OAAO,SAAS;AAAA,EACzB,GAAG;AAEH,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,iBAAiB,MAAM,OAAO;AAAA,IAC/B,CAAC,WAAW,OAAO,IAAI,GAAG,QAAQ,2BAA2B,WAAW,EAAE;AAAA,EAC5E;AAEA,QAAM,UAAU,CAAC,UAA2B;AAC1C,UAAM,eAAe;AACrB,YAAQ,CAAC;AACT,eAAW;AAAA,MACT,SAAS,MAAM;AAAA,MACf,QAAQ,MAAM,OAAO,KAAK;AAAA,MAC1B,WAAW,MAAM,UAAU,KAAK;AAAA,MAChC,QAAQ,MAAM,OAAO,KAAK;AAAA,MAC1B,MAAM,MAAM;AAAA,MACZ,IAAI,MAAM;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,QAAM,WAAW,CAAC,KAAoB,UACpC,SAAS,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,GAAG,GAAG,MAAM,EAAE;AAEhD,QAAM,OAAO,MAAM,SAAS,CAAC;AAC7B,QAAM,aAAa,MAAM,cAAc;AAEvC,SACE,+CAAC,aAAQ,cAAW,yBAAwB,eAAW,sBAAG,uBAAuB,SAAS,GACxF;AAAA,kDAAC,0BACC,yDAAC,UAAK,UAAU,SAAS,WAAU,sCAAqC,YAAU,MAChF;AAAA,qDAAC,WAAM,SAAQ,eAAc,WAAU,+BACrC;AAAA,sDAAC,UAAK,WAAU,+BAA8B,qBAAO;AAAA,QACrD;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,OAAO,MAAM;AAAA,YACb,UAAU,CAAC,MAAM,SAAS,WAAW,EAAE,OAAO,KAAK;AAAA,YACnD,WAAW;AAAA,YAEX;AAAA,4DAAC,YAAO,OAAM,IAAG,iBAAG;AAAA,cACpB,8CAAC,YAAO,OAAM,SAAQ,mBAAK;AAAA,cAC3B,8CAAC,YAAO,OAAM,OAAM,iBAAG;AAAA;AAAA;AAAA,QACzB;AAAA,SACF;AAAA,MACA,+CAAC,WAAM,SAAQ,cAAa,WAAU,+BACpC;AAAA,sDAAC,UAAK,WAAU,+BAA8B,oBAAM;AAAA,QACpD,8CAAC,WAAM,IAAG,cAAa,MAAK,QAAO,OAAO,MAAM,QAAQ,UAAU,CAAC,MAAM,SAAS,UAAU,EAAE,OAAO,KAAK,GAAG,WAAW,aAAa;AAAA,SACvI;AAAA,MACA,+CAAC,WAAM,SAAQ,iBAAgB,WAAU,+BACvC;AAAA,sDAAC,UAAK,WAAU,+BAA8B,uBAAS;AAAA,QACvD,8CAAC,WAAM,IAAG,iBAAgB,MAAK,QAAO,OAAO,MAAM,WAAW,UAAU,CAAC,MAAM,SAAS,aAAa,EAAE,OAAO,KAAK,GAAG,WAAW,aAAa;AAAA,SAChJ;AAAA,MACA,+CAAC,WAAM,SAAQ,YAAW,WAAU,+BAClC;AAAA,sDAAC,UAAK,WAAU,+BAA8B,qBAAO;AAAA,QACrD,8CAAC,WAAM,IAAG,YAAW,MAAK,QAAO,OAAO,MAAM,QAAQ,UAAU,CAAC,MAAM,SAAS,UAAU,EAAE,OAAO,KAAK,GAAG,WAAW,aAAa;AAAA,SACrI;AAAA,MACA,+CAAC,WAAM,SAAQ,YAAW,WAAU,+BAClC;AAAA,sDAAC,UAAK,WAAU,+BAA8B,kBAAI;AAAA,QAClD,8CAAC,WAAM,IAAG,YAAW,MAAK,QAAO,OAAO,MAAM,MAAM,UAAU,CAAC,MAAM,SAAS,QAAQ,EAAE,OAAO,KAAK,GAAG,WAAW,aAAa;AAAA,SACjI;AAAA,MACA,+CAAC,WAAM,SAAQ,UAAS,WAAU,+BAChC;AAAA,sDAAC,UAAK,WAAU,+BAA8B,gBAAE;AAAA,QAChD,8CAAC,WAAM,IAAG,UAAS,MAAK,QAAO,OAAO,MAAM,IAAI,UAAU,CAAC,MAAM,SAAS,MAAM,EAAE,OAAO,KAAK,GAAG,WAAW,aAAa;AAAA,SAC3H;AAAA,MACA,8CAAC,4BAAO,MAAK,UAAS,WAAU,WAAU,mBAE1C;AAAA,OACF,GACF;AAAA,IAEA,+CAAC,0BACC;AAAA,oDAAC,eAAY,OAAM,YAAW,UAAU,CAAC,aAAa,CAAC,UAAU,GAAG,MAAM,SAAS,KAAK,MAAM,sBAAsB,QAAW;AAAA,MAC9H,YACC,8CAAC,gBAAa,OAAM,yBAAwB,IAC1C,UACF,8CAAC,cAAW,SAAQ,gCAA+B,SAAS,MAAM,KAAK,QAAQ,GAAG,IAChF,KAAK,WAAW,IAClB,8CAAC,gCAAW,MAAM,8CAAC,aAAU,GAAI,OAAM,oBAAmB,aAAY,0CAAyC,IAE/G,gFACE;AAAA,uDAAC,WAAM,WAAU,kBACf;AAAA,wDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,0DAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,qBAAO;AAAA,YACzD,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,uBAAS;AAAA,YAC3D,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,kBAAI;AAAA,YACtD,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAAM;AAAA,YACxD,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,sBAAQ;AAAA,YAC1D,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,sBAAQ;AAAA,YAC1D,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,qBAAO;AAAA,aAC3D,GACF;AAAA,UACA,8CAAC,WACE,eAAK,IAAI,CAAC,QACT,+CAAC,QAAgB,WAAU,0DACzB;AAAA,0DAAC,QAAG,WAAU,aACZ,wDAAC,iCAAY,SAAS,eAAe,IAAI,OAAO,GAAG,YAAW,OAC3D,cAAI,SACP,GACF;AAAA,YACA,8CAAC,QAAG,WAAU,6BAA6B,cAAI,aAAa,UAAI;AAAA,YAChE,8CAAC,QAAG,WAAU,uCAAuC,cAAI,QAAO;AAAA,YAChE,8CAAC,QAAG,WAAU,6BAA6B,cAAI,QAAO;AAAA,YACtD,8CAAC,QAAG,WAAU,mCAAmC,cAAI,YAAY,UAAI;AAAA,YACrE,8CAAC,QAAG,WAAU,gDAAgD,cAAI,UAAS;AAAA,YAC3E,8CAAC,QAAG,WAAU,mCAAmC,gDAAe,IAAI,SAAS,GAAE;AAAA,eAXxE,IAAI,EAYb,CACD,GACH;AAAA,WACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA,QAAQ,MAAM,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AAAA,YAC/C,QAAQ,MAAM,QAAQ,CAAC,MAAM,KAAK,IAAI,YAAY,IAAI,CAAC,CAAC;AAAA;AAAA,QAC1D;AAAA,SACF;AAAA,OAEJ;AAAA,KACF;AAEJ;AAIA,SAAS,YAAY;AACnB,SACE,+CAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAC9G;AAAA,kDAAC,UAAK,GAAE,4BAA2B;AAAA,IACnC,8CAAC,UAAK,GAAE,8GAA6G;AAAA,KACvH;AAEJ;;;ACtNA,IAAAC,iBAAoC;AACpC,IAAAC,oBAA6B;AAC7B,IAAAC,uBAA4C;AAiFtC,IAAAC,uBAAA;AAnEN,IAAM,WAAuB;AAAA,EAC3B,SAAS;AAAA,EACT,OAAO;AAAA,EACP,KAAK;AAAA,EACL,UAAU;AACZ;AAGA,SAASC,WAAU,KAA0B;AAC3C,QAAM,MAAO,OAAO,CAAC;AACrB,SAAO;AAAA,IACL,SAAS,OAAO,IAAI,YAAY,YAAY,IAAI,UAAU,SAAS;AAAA,IACnE,OACE,OAAO,IAAI,UAAU,WACjB,IAAI,QACJ,OAAO,IAAI,cAAc,WACvB,IAAI,YACJ,SAAS;AAAA,IACjB,KACE,OAAO,IAAI,QAAQ,WACf,IAAI,MACJ,OAAO,IAAI,YAAY,WACrB,IAAI,UACJ,SAAS;AAAA,IACjB,UAAU,OAAO,IAAI,aAAa,WAAW,IAAI,WAAW,SAAS;AAAA,EACvE;AACF;AAOO,SAAS,eAAe,EAAE,WAAW,QAAQ,UAAU,GAAwB;AACpF,QAAM,YAAQ,4BAAS;AACvB,QAAM,MAAM,GAAG,QAAQ;AAEvB,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAAqB,CAAC,aAAa;AAAA,IAAG,CAAC,WACnF,OAAO,IAAI,GAAG;AAAA,EAChB;AAEA,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAqB,QAAQ;AAErD,gCAAU,MAAM;AACd,QAAI,SAAS,QAAW;AACtB,cAAQA,WAAU,IAAI,CAAC;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,WAAO,qCAAoC,CAAC,QAAQ,YAAY,OAAO,IAAI,KAAK,OAAO,GAAG;AAAA,IAC9F,aAAa,CAAC,CAAC,aAAa,CAAC;AAAA,IAC7B,WAAW,MAAM,MAAM,QAAQ,mBAAmB;AAAA,IAClD,SAAS,CAAC,UACR,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,MACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,IACrE,CAAC;AAAA,EACL,CAAC;AAED,QAAM,WAAW,CAAC,UAA2B;AAC3C,UAAM,eAAe;AACrB,SAAK,OAAO,IAAI;AAAA,EAClB;AAEA,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,iCAAmB;AAAA,UAC5C,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,wCAA0B;AAAA,MACjE;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,+CAAC,UAAK,UAAoB,eAAW,sBAAG,uBAAuB,SAAS,GAAG,YAAU,MACnF;AAAA,kDAAC,QAAG,WAAU,yCAAwC,yBAAW;AAAA,IAEjE,+CAAC,WAAM,WAAU,mDACf;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,KAAK;AAAA,UACd,UAAU,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,GAAG,MAAM,SAAS,EAAE,OAAO,QAAQ,EAAE;AAAA,UAC3E,WAAU;AAAA;AAAA,MACZ;AAAA,MAAE;AAAA,OAEJ;AAAA,IAEA,+CAAC,SAAI,WAAU,wBACb;AAAA,qDAAC,SAAI,WAAU,uBACb;AAAA,sDAAC,WAAM,SAAQ,YAAW,WAAU,uCAAsC,mBAE1E;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACL,OAAO,KAAK;AAAA,YACZ,UAAU,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,EAAE,OAAO,MAAM,EAAE;AAAA,YACvE,WAAU;AAAA;AAAA,QACZ;AAAA,SACF;AAAA,MACA,+CAAC,SAAI,WAAU,uBACb;AAAA,sDAAC,WAAM,SAAQ,UAAS,WAAU,uCAAsC,iBAExE;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACL,OAAO,KAAK;AAAA,YACZ,UAAU,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,GAAG,MAAM,KAAK,EAAE,OAAO,MAAM,EAAE;AAAA,YACrE,WAAU;AAAA;AAAA,QACZ;AAAA,SACF;AAAA,MACA,+CAAC,SAAI,WAAU,uBACb;AAAA,sDAAC,WAAM,SAAQ,SAAQ,WAAU,uCAAsC,sBAEvE;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACL,OAAO,KAAK;AAAA,YACZ,UAAU,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,GAAG,MAAM,UAAU,EAAE,OAAO,MAAM,EAAE;AAAA,YAC1E,WAAU;AAAA;AAAA,QACZ;AAAA,SACF;AAAA,OACF;AAAA,IAEA,8CAAC,SACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAU,KAAK;AAAA,QACf,WAAU;AAAA,QAET,eAAK,YAAY,iBAAY;AAAA;AAAA,IAChC,GACF;AAAA,KACF;AAEJ;;;AC/KA,IAAAC,iBAAoC;AACpC,IAAAC,oBAA6B;AAC7B,IAAAC,uBAA4C;AAsFtC,IAAAC,uBAAA;AAzEN,SAASC,WAAU,KAAqB;AACtC,QAAM,OAAO,MAAM,QAAQ,GAAG,IAC1B,MACA,MAAM,QAAS,KAAiC,IAAI,IAChD,IAAgC,OAClC,CAAC;AACP,SAAO,KAAK,IAAI,CAAC,UAAU;AACzB,UAAM,MAAO,SAAS,CAAC;AACvB,UAAM,MACJ,OAAO,IAAI,cAAc,WACrB,IAAI,YACJ,OAAO,IAAI,UAAU,WACnB,IAAI,QACJ,OAAO,IAAI,WAAW,WACpB,IAAI,SACJ;AACV,WAAO,EAAE,MAAM,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO,IAAI,WAAW,IAAI;AAAA,EAC9E,CAAC;AACH;AAOO,SAAS,kBAAkB,EAAE,WAAW,QAAQ,UAAU,GAA2B;AAC1F,QAAM,YAAQ,4BAAS;AACvB,QAAM,MAAM,GAAG,QAAQ;AAEvB,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAAqB,CAAC,eAAe;AAAA,IAAG,CAAC,WACrF,OAAO,IAAI,GAAG;AAAA,EAChB;AAEA,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAgB,CAAC,CAAC;AAC1C,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,EAAE;AACzC,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAS,CAAC;AAEtC,gCAAU,MAAM;AACd,QAAI,SAAS,QAAW;AACtB,cAAQA,WAAU,IAAI,CAAC;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,WAAO;AAAA,IACX,CAAC,QAAQ,YAAY,OAAO,IAAI,KAAK,OAAO;AAAA,IAC5C;AAAA,MACE,aAAa,CAAC,CAAC,eAAe,CAAC;AAAA,MAC/B,WAAW,MAAM,MAAM,QAAQ,sBAAsB;AAAA,MACrD,SAAS,CAAC,UACR,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,QACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,MACrE,CAAC;AAAA,IACL;AAAA,EACF;AAEA,QAAM,YAAY,CAAC,OAAe,UAChC,QAAQ,CAAC,SAAS,KAAK,IAAI,CAAC,KAAK,MAAO,MAAM,QAAQ,EAAE,GAAG,KAAK,WAAW,MAAM,IAAI,GAAI,CAAC;AAE5F,QAAM,YAAY,CAAC,UAAkB,QAAQ,CAAC,SAAS,KAAK,OAAO,CAAC,GAAG,MAAM,MAAM,KAAK,CAAC;AAEzF,QAAM,SAAS,CAAC,UAA2B;AACzC,UAAM,eAAe;AACrB,UAAM,OAAO,QAAQ,KAAK;AAC1B,QAAI,CAAC,KAAM;AACX,YAAQ,CAAC,SAAS,CAAC,GAAG,MAAM,EAAE,MAAM,WAAW,OAAO,CAAC,CAAC;AACxD,eAAW,EAAE;AACb,cAAU,CAAC;AAAA,EACb;AAEA,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,oCAAsB;AAAA,UAC/C,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,2CAA6B;AAAA,MACpE;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,+CAAC,aAAQ,cAAW,kBAAiB,eAAW,sBAAG,uBAAuB,SAAS,GACjF;AAAA,kDAAC,QAAG,WAAU,yCAAwC,4BAAc;AAAA,IAEpE,+CAAC,WAAM,WAAU,kBACf;AAAA,oDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,sDAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,kBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,yBAElD;AAAA,QACA,8CAAC,QAAG,OAAM,OAAM,WAAU,yBACxB,wDAAC,UAAK,WAAU,WAAU,qBAAO,GACnC;AAAA,SACF,GACF;AAAA,MACA,8CAAC,WACE,eAAK,IAAI,CAAC,KAAK,UAAU;AACxB,cAAM,UAAU,OAAO,KAAK;AAC5B,eACE,+CAAC,QAAgC,WAAU,0BACzC;AAAA,wDAAC,QAAG,WAAU,6BAA6B,cAAI,MAAK;AAAA,UACpD,+CAAC,QAAG,WAAU,aACZ;AAAA,2DAAC,WAAM,SAAS,SAAS,WAAU,WAAU;AAAA;AAAA,cAC1B,IAAI;AAAA,eACvB;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,IAAI;AAAA,gBACJ,MAAK;AAAA,gBACL,KAAK;AAAA,gBACL,OAAO,IAAI;AAAA,gBACX,UAAU,CAAC,MAAM,UAAU,OAAO,OAAO,EAAE,OAAO,KAAK,CAAC;AAAA,gBACxD,WAAU;AAAA;AAAA,YACZ;AAAA,aACF;AAAA,UACA,8CAAC,QAAG,WAAU,aACZ;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,UAAU,KAAK;AAAA,cAC9B,WAAU;AAAA,cACX;AAAA;AAAA,UAED,GACF;AAAA,aAvBO,GAAG,IAAI,IAAI,IAAI,KAAK,EAwB7B;AAAA,MAEJ,CAAC,GACH;AAAA,OACF;AAAA,IAEA,+CAAC,UAAK,UAAU,QAAQ,WAAU,kCAAiC,YAAU,MAC3E;AAAA,qDAAC,SAAI,WAAU,uBACb;AAAA,sDAAC,WAAM,SAAQ,gBAAe,WAAU,uCAAsC,sBAE9E;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACL,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,WAAW,EAAE,OAAO,KAAK;AAAA,YAC1C,WAAU;AAAA;AAAA,QACZ;AAAA,SACF;AAAA,MACA,+CAAC,SAAI,WAAU,uBACb;AAAA,sDAAC,WAAM,SAAQ,eAAc,WAAU,uCAAsC,yBAE7E;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACL,KAAK;AAAA,YACL,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,UAAU,OAAO,EAAE,OAAO,KAAK,CAAC;AAAA,YACjD,WAAU;AAAA;AAAA,QACZ;AAAA,SACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,IAEA,8CAAC,SACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAU,KAAK;AAAA,QACf,SAAS,MAAM,KAAK,OAAO,EAAE,KAAK,CAAC;AAAA,QACnC,WAAU;AAAA,QAET,eAAK,YAAY,iBAAY;AAAA;AAAA,IAChC,GACF;AAAA,KACF;AAEJ;;;ACtNA,IAAAC,iBAAoC;AACpC,IAAAC,oBAA6B;AAC7B,IAAAC,uBAA4C;AA4CtC,IAAAC,uBAAA;AA/BN,SAASC,WAAU,KAA4B;AAC7C,QAAM,MAAO,OAAO,CAAC;AACrB,QAAM,SAAS,CAAC,UACd,MAAM,QAAQ,KAAK,IAAI,MAAM,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,IAAI,CAAC;AACpF,SAAO;AAAA,IACL,mBAAmB,OAAO,IAAI,iBAAiB;AAAA,IAC/C,qBAAqB,OAAO,IAAI,mBAAmB;AAAA,EACrD;AACF;AAUA,SAAS,UAAU,EAAE,IAAI,OAAO,QAAQ,OAAO,SAAS,GAAmB;AACzE,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAAS,EAAE;AAErC,QAAM,MAAM,CAAC,UAA2B;AACtC,UAAM,eAAe;AACrB,UAAM,QAAQ,MAAM,KAAK;AACzB,QAAI,CAAC,MAAO;AACZ,UAAM,KAAK;AACX,aAAS,EAAE;AAAA,EACb;AAEA,SACE,+CAAC,SAAI,WAAU,uBACb;AAAA,kDAAC,UAAK,WAAU,uCAAuC,iBAAM;AAAA,IAC7D,8CAAC,QAAG,WAAU,wBACX,iBAAO,WAAW,IACjB,8CAAC,QAAG,WAAU,iCAAgC,kBAAI,IAElD,OAAO,IAAI,CAAC,UACV;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAET;AAAA;AAAA,UACD;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAY,UAAU,KAAK;AAAA,cAC3B,SAAS,MAAM,SAAS,KAAK;AAAA,cAC7B,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA;AAAA;AAAA,MAXK;AAAA,IAYP,CACD,GAEL;AAAA,IACA,+CAAC,UAAK,UAAU,KAAK,WAAU,wBAAuB,YAAU,MAC9D;AAAA,qDAAC,SAAI,WAAU,uBACb;AAAA,uDAAC,WAAM,SAAS,IAAI,WAAU,WAAU;AAAA;AAAA,UAC9B;AAAA,WACV;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,MAAK;AAAA,YACL,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,YACxC,WAAU;AAAA;AAAA,QACZ;AAAA,SACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,KACF;AAEJ;AAOO,SAAS,iBAAiB,EAAE,WAAW,QAAQ,UAAU,GAA0B;AACxF,QAAM,YAAQ,4BAAS;AACvB,QAAM,MAAM,GAAG,QAAQ;AAEvB,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAAqB,CAAC,eAAe;AAAA,IAAG,CAAC,WACrF,OAAO,IAAI,GAAG;AAAA,EAChB;AAEA,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAuB;AAAA,IACjD,mBAAmB,CAAC;AAAA,IACpB,qBAAqB,CAAC;AAAA,EACxB,CAAC;AACD,QAAM,CAAC,aAAa,cAAc,QAAI,yBAA6B,MAAS;AAE5E,gCAAU,MAAM;AACd,QAAI,SAAS,QAAW;AACtB,gBAAUA,WAAU,IAAI,CAAC;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,WAAO;AAAA,IACX,CAAC,QAAQ,YAAY,OAAO,IAAI,KAAK,OAAO;AAAA,IAC5C;AAAA,MACE,aAAa,CAAC,CAAC,eAAe,CAAC;AAAA,MAC/B,WAAW,MAAM,MAAM,QAAQ,qBAAqB;AAAA,MACpD,SAAS,CAAC,UACR,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,QACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,MACrE,CAAC;AAAA,IACL;AAAA,EACF;AAEA,QAAM,UAAU,CAAC,UACf;AAAA,IAAU,CAAC,SACT,KAAK,kBAAkB,SAAS,KAAK,IACjC,OACA,EAAE,GAAG,MAAM,mBAAmB,CAAC,GAAG,KAAK,mBAAmB,KAAK,EAAE;AAAA,EACvE;AAEF,QAAM,aAAa,CAAC,UAClB,UAAU,CAAC,UAAU;AAAA,IACnB,GAAG;AAAA,IACH,mBAAmB,KAAK,kBAAkB,OAAO,CAAC,MAAM,MAAM,KAAK;AAAA,EACrE,EAAE;AAEJ,QAAM,eAAe,CAAC,UACpB;AAAA,IAAU,CAAC,SACT,KAAK,oBAAoB,SAAS,KAAK,IACnC,OACA,EAAE,GAAG,MAAM,qBAAqB,CAAC,GAAG,KAAK,qBAAqB,KAAK,EAAE;AAAA,EAC3E;AAEF,QAAM,kBAAkB,CAAC,UACvB,UAAU,CAAC,UAAU;AAAA,IACnB,GAAG;AAAA,IACH,qBAAqB,KAAK,oBAAoB,OAAO,CAAC,MAAM,MAAM,KAAK;AAAA,EACzE,EAAE;AAEJ,QAAM,WAAW,CAAC,UAA2B;AAC3C,UAAM,eAAe;AACrB,UAAM,UAAU,OAAO,oBAAoB,OAAO,CAAC,MAAM,CAAC,OAAO,kBAAkB,SAAS,CAAC,CAAC;AAC9F,QAAI,QAAQ,SAAS,GAAG;AACtB;AAAA,QACE,8EAA8E,QAAQ,KAAK,IAAI,CAAC;AAAA,MAClG;AACA;AAAA,IACF;AACA,mBAAe,MAAS;AACxB,SAAK,OAAO,MAAM;AAAA,EACpB;AAEA,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,0CAA4B;AAAA,UACrD,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,iDAAmC;AAAA,MAC1E;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,UAAU;AAEhB,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,eAAW,sBAAG,uBAAuB,SAAS;AAAA,MAC9C,YAAU;AAAA,MACV,gBAAc,cAAc,SAAS;AAAA,MACrC,oBAAkB,cAAc,UAAU;AAAA,MAE1C;AAAA,sDAAC,QAAG,WAAU,yCAAwC,wCAA0B;AAAA,QAEhF;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,OAAM;AAAA,YACN,QAAQ,OAAO;AAAA,YACf,OAAO;AAAA,YACP,UAAU;AAAA;AAAA,QACZ;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,OAAM;AAAA,YACN,QAAQ,OAAO;AAAA,YACf,OAAO;AAAA,YACP,UAAU;AAAA;AAAA,QACZ;AAAA,QAEC,eACC,8CAAC,OAAE,IAAI,SAAS,WAAU,4BACvB,uBACH;AAAA,QAGF,8CAAC,SACC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,UAAU,KAAK;AAAA,YACf,WAAU;AAAA,YAET,eAAK,YAAY,iBAAY;AAAA;AAAA,QAChC,GACF;AAAA;AAAA;AAAA,EACF;AAEJ;;;ACtPA,IAAAC,iBAAoC;AACpC,IAAAC,oBAA6B;AAC7B,IAAAC,uBAA4C;AAyEtC,IAAAC,uBAAA;AA5DN,SAASC,WAAU,KAA8B;AAC/C,QAAM,MAAO,OAAO,CAAC;AACrB,QAAM,OAAO,IAAI,SAA4B;AAC3C,eAAW,OAAO,MAAM;AACtB,UAAI,OAAO,IAAI,GAAG,MAAM,UAAW,QAAO,IAAI,GAAG;AAAA,IACnD;AACA,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,qBAAqB,KAAK,uBAAuB,cAAc;AAAA,IAC/D,sBAAsB,KAAK,wBAAwB,eAAe;AAAA,EACpE;AACF;AAOO,SAAS,mBAAmB,EAAE,WAAW,QAAQ,UAAU,GAA4B;AAC5F,QAAM,YAAQ,4BAAS;AACvB,QAAM,MAAM,GAAG,QAAQ;AAEvB,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAC5C,CAAC,iBAAiB;AAAA,IAClB,CAAC,WAAW,OAAO,IAAI,GAAG;AAAA,EAC5B;AAEA,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAyB;AAAA,IAC/C,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,EACxB,CAAC;AAED,gCAAU,MAAM;AACd,QAAI,SAAS,QAAW;AACtB,cAAQA,WAAU,IAAI,CAAC;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,WAAO;AAAA,IACX,CAAC,QAAQ,YAAY,OAAO,KAAK,KAAK,OAAO;AAAA,IAC7C;AAAA,MACE,aAAa,CAAC,CAAC,iBAAiB,CAAC;AAAA,MACjC,WAAW,MAAM,MAAM,QAAQ,8BAA8B;AAAA,MAC7D,SAAS,CAAC,UACR,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,QACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,MACrE,CAAC;AAAA,IACL;AAAA,EACF;AAEA,QAAM,WAAW,CAAC,UAA2B;AAC3C,UAAM,eAAe;AACrB,SAAK,OAAO,IAAI;AAAA,EAClB;AAEA,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,4CAA8B;AAAA,UACvD,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,MACX,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,mDAAqC;AAAA,MAC5E;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,+CAAC,UAAK,UAAoB,eAAW,sBAAG,uBAAuB,SAAS,GAAG,YAAU,MACnF;AAAA,kDAAC,QAAG,WAAU,yCAAwC,oCAAsB;AAAA,IAE5E,+CAAC,WAAM,WAAU,mDACf;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,KAAK;AAAA,UACd,UAAU,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,GAAG,MAAM,qBAAqB,EAAE,OAAO,QAAQ,EAAE;AAAA,UACvF,WAAU;AAAA;AAAA,MACZ;AAAA,MAAE;AAAA,OAEJ;AAAA,IAEA,+CAAC,WAAM,WAAU,mDACf;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,KAAK;AAAA,UACd,UAAU,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,GAAG,MAAM,sBAAsB,EAAE,OAAO,QAAQ,EAAE;AAAA,UACxF,WAAU;AAAA;AAAA,MACZ;AAAA,MAAE;AAAA,OAEJ;AAAA,IAEA,8CAAC,SACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAU,KAAK;AAAA,QACf,WAAU;AAAA,QAET,eAAK,YAAY,iBAAY;AAAA;AAAA,IAChC,GACF;AAAA,KACF;AAEJ;;;ACpIA,IAAAC,iBAAyB;AACzB,IAAAC,oBAAoF;AACpF,IAAAC,uBAA4C;AAoHlC,IAAAC,uBAAA;AAzFV,SAASC,WAAU,KAAwB;AACzC,QAAM,OAAO,MAAM,QAAQ,GAAG,IAC1B,MACA,MAAM,QAAS,KAAiC,KAAK,IACjD,IAAgC,QAClC,CAAC;AACP,SAAO;AACT;AAOO,SAAS,cAAc,EAAE,WAAW,QAAQ,UAAU,GAAuB;AAClF,QAAM,YAAQ,4BAAS;AACvB,QAAM,MAAM,GAAG,QAAQ;AAEvB,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAAqB,CAAC,UAAU;AAAA,IAAG,CAAC,WAChF,OAAO,IAAI,GAAG;AAAA,EAChB;AAEA,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAS,EAAE;AACnC,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,yBAAS,EAAE;AAEvD,QAAM,kBAAkB,CAAC,UAMvB,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,IACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,EACrE,CAAC;AAEH,QAAM,aAAS;AAAA,IACb,CAAC,QAAQ,SACP,OAAO,KAAK,KAAK;AAAA,MACf,MAAM,KAAK;AAAA,MACX,GAAI,KAAK,iBAAiB,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;AAAA,IACvE,CAAC;AAAA,IACH;AAAA,MACE,aAAa,CAAC,CAAC,UAAU,CAAC;AAAA,MAC1B,WAAW,CAAC,WAAW;AACrB,cAAM,SAAS,QAAQ,OAAO,QAAQ;AACtC,YAAI,QAAQ;AACV,gBAAM,QAAQ,sCAAiC;AAAA,YAC7C,aAAa,mCAAmC,MAAM;AAAA,UACxD,CAAC;AAAA,QACH,OAAO;AACL,gBAAM,QAAQ,iBAAiB;AAAA,QACjC;AACA,gBAAQ,EAAE;AACV,0BAAkB,EAAE;AAAA,MACtB;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,aAAS,qCAA6B,CAAC,QAAQ,OAAO,OAAO,OAAO,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG;AAAA,IACzF,aAAa,CAAC,CAAC,UAAU,CAAC;AAAA,IAC1B,WAAW,MAAM;AACf,YAAM,QAAQ,iBAAiB;AAC/B,WAAK,QAAQ;AAAA,IACf;AAAA,IACA,SAAS;AAAA,EACX,CAAC;AAED,QAAM,WAAW,CAAC,UAA2B;AAC3C,UAAM,eAAe;AACrB,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,QAAS;AACd,WAAO,OAAO,EAAE,MAAM,SAAS,gBAAgB,eAAe,KAAK,KAAK,OAAU,CAAC;AAAA,EACrF;AAEA,QAAM,WAAW,CAAC,OAAe;AAC/B,QAAI,OAAO,QAAQ,8DAA8D,GAAG;AAClF,aAAO,OAAO,EAAE;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,OAAOA,WAAU,IAAI;AAE3B,SACE,+CAAC,aAAQ,cAAW,sBAAqB,eAAW,sBAAG,uBAAuB,SAAS,GACrF;AAAA,kDAAC,0BACC,yDAAC,UAAK,UAAU,UAAU,WAAU,sCAAqC,YAAU,MACjF;AAAA,qDAAC,WAAM,WAAU,sCACf;AAAA,sDAAC,UAAK,WAAU,+BAA8B,0BAAY;AAAA,QAC1D,8CAAC,WAAM,MAAK,QAAO,OAAO,MAAM,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK,GAAG,WAAW,aAAa;AAAA,SACpG;AAAA,MACA,+CAAC,WAAM,WAAU,sCACf;AAAA,sDAAC,UAAK,WAAU,+BAA8B,oCAAsB;AAAA,QACpE;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,kBAAkB,EAAE,OAAO,KAAK;AAAA,YACjD,aAAY;AAAA,YACZ,WAAW;AAAA;AAAA,QACb;AAAA,SACF;AAAA,MACA,8CAAC,4BAAO,MAAK,UAAS,UAAU,OAAO,WACpC,iBAAO,YAAY,mBAAc,cACpC;AAAA,OACF,GACF;AAAA,IAEA,+CAAC,0BACC;AAAA,oDAAC,eAAY,OAAM,QAAO,UAAU,CAAC,aAAa,CAAC,UAAU,GAAG,KAAK,MAAM,UAAU,QAAW;AAAA,MAC/F,YACC,8CAAC,gBAAa,OAAM,oBAAmB,IACrC,UACF,8CAAC,cAAW,SAAQ,2BAA0B,SAAS,MAAM,KAAK,QAAQ,GAAG,IAC3E,KAAK,WAAW,IAClB,8CAAC,gCAAW,MAAM,8CAAC,WAAQ,GAAI,OAAM,eAAc,aAAY,gCAA+B,IAE9F,+CAAC,WAAM,WAAU,kBACf;AAAA,sDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,wDAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,kBAAI;AAAA,UACtD,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAAM;AAAA,UACxD,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,yBAAW;AAAA,UAC7D,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAAM;AAAA,UACxD,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,qBAAO;AAAA,UACzD,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,uBAAS;AAAA,UAC3D,8CAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,wDAAC,UAAK,WAAU,WAAU,qBAAO,GAAO;AAAA,WAC5F,GACF;AAAA,QACA,8CAAC,WACE,eAAK,IAAI,CAAC,QACT,+CAAC,QAAgB,WAAU,0DACzB;AAAA,wDAAC,QAAG,WAAU,6BAA6B,cAAI,MAAK;AAAA,UACpD,8CAAC,QAAG,WAAU,6CAA6C,cAAI,UAAU,UAAI;AAAA,UAC7E,8CAAC,QAAG,WAAU,6CAA6C,cAAI,kBAAkB,UAAI;AAAA,UACrF,8CAAC,QAAG,WAAU,aACZ,wDAAC,iCAAY,SAAS,IAAI,UAAU,gBAAgB,WACjD,cAAI,UAAU,YAAY,UAC7B,GACF;AAAA,UACA,8CAAC,QAAG,WAAU,mCAAmC,gDAAe,IAAI,SAAS,GAAE;AAAA,UAC/E,8CAAC,QAAG,WAAU,mCACX,cAAI,iBAAa,kCAAe,IAAI,UAAU,IAAI,UACrD;AAAA,UACA,8CAAC,QAAG,WAAU,sBACZ;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,WAAU;AAAA,cACV,UAAU,OAAO,aAAa,IAAI;AAAA,cAClC,SAAS,MAAM,SAAS,IAAI,EAAE;AAAA,cAC/B;AAAA;AAAA,UAED,GACF;AAAA,aAxBO,IAAI,EAyBb,CACD,GACH;AAAA,SACF;AAAA,OAEJ;AAAA,KACF;AAEJ;AAIA,SAAS,UAAU;AACjB,SACE,+CAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAC9G;AAAA,kDAAC,UAAK,GAAE,kEAAiE;AAAA,IACzE,8CAAC,UAAK,GAAE,iBAAgB;AAAA,IACxB,8CAAC,YAAO,IAAG,OAAM,IAAG,QAAO,GAAE,OAAM;AAAA,KACrC;AAEJ;;;ACpNA,IAAAC,iBAAyB;AACzB,IAAAC,oBAA0D;AAC1D,IAAAC,uBAA4C;AAmGtC,IAAAC,uBAAA;AAzEN,SAASC,YAAU,KAA6B;AAC9C,QAAM,OAAO,MAAM,QAAQ,GAAG,IAC1B,MACA,MAAM,QAAS,KAAiC,KAAK,IACjD,IAAgC,QAClC,CAAC;AACP,SAAO;AACT;AAQO,SAAS,yBAAyB;AAAA,EACvC,WAAW;AAAA,EACX;AACF,GAAkC;AAChC,QAAM,YAAQ,4BAAS;AACvB,QAAM,MAAM,GAAG,QAAQ;AAEvB,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAI;AAAA,IAAqB,CAAC,cAAc;AAAA,IAAG,CAAC,WACpF,OAAO,IAAI,GAAG;AAAA,EAChB;AAEA,QAAM,CAAC,KAAK,MAAM,QAAI,yBAAS,EAAE;AACjC,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,EAAE;AACjD,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,EAAE;AAEjD,QAAM,kBAAkB,CAAC,UACvB,MAAM,MAAM,MAAM,gBAAgB,yBAAyB,MAAM,OAAO;AAAA,IACtE,aAAa,MAAM,gBACf,2BAA2B,MAAM,iBAAiB,SAAS,MAC3D,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,SAAS;AAAA,EACrE,CAAC;AAEH,QAAM,eAAW,qCAGf,CAAC,QAAQ,SAAS,OAAO,KAAK,KAAK,IAAI,GAAG;AAAA,IAC1C,aAAa,CAAC,CAAC,cAAc,CAAC;AAAA,IAC9B,WAAW,MAAM;AACf,YAAM,QAAQ,wBAAwB;AACtC,aAAO,EAAE;AACT,qBAAe,EAAE;AACjB,qBAAe,EAAE;AAAA,IACnB;AAAA,IACA,SAAS;AAAA,EACX,CAAC;AAED,QAAM,gBAAY,qCAGhB,CAAC,QAAQ,SAAS,OAAO,MAAM,GAAG,GAAG,IAAI,KAAK,GAAG,IAAI,EAAE,QAAQ,KAAK,OAAO,CAAC,GAAG;AAAA,IAC/E,aAAa,CAAC,CAAC,cAAc,CAAC;AAAA,IAC9B,WAAW,MAAM;AACf,YAAM,QAAQ,qBAAqB;AACnC,WAAK,QAAQ;AAAA,IACf;AAAA,IACA,SAAS;AAAA,EACX,CAAC;AAED,QAAM,aAAa,CAAC,UAA2B;AAC7C,UAAM,eAAe;AACrB,UAAM,IAAI,IAAI,KAAK;AACnB,UAAM,OAAO,YAAY,KAAK;AAC9B,QAAI,CAAC,KAAK,CAAC,KAAM;AACjB,aAAS,OAAO,EAAE,KAAK,GAAG,aAAa,MAAM,aAAa,YAAY,KAAK,KAAK,OAAU,CAAC;AAAA,EAC7F;AAEA,QAAM,eACJ,+CAAC,UAAK,UAAU,YAAY,WAAU,kCAAiC,YAAU,MAC/E;AAAA,mDAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,mBAAkB,WAAU,uCAAsC,wBAEjF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,OAAO,EAAE,OAAO,KAAK;AAAA,UACtC,aAAY;AAAA,UACZ,WAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,IACA,+CAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,oBAAmB,WAAU,uCAAsC,0BAElF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA,UAC9C,aAAY;AAAA,UACZ,WAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,IACA,+CAAC,SAAI,WAAU,uBACb;AAAA,oDAAC,WAAM,SAAQ,2BAA0B,WAAU,uCAAsC,oCAEzF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA,UAC9C,WAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAU,SAAS;AAAA,QACnB,WAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,KACF;AAGF,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,eAAW,sBAAG,2BAA2B,SAAS;AAAA,QAElD;AAAA,wDAAC,UAAK,WAAU,WAAU,kCAAoB;AAAA,UAC7C,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,8CAAC,SAAY,eAAY,QAAO,WAAU,yCAAhC,CAAsE,CACjF;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,+CAAC,SAAI,eAAW,sBAAG,uCAAuC,SAAS,GACjE;AAAA,oDAAC,OAAE,WAAU,2BAA0B,yCAA2B;AAAA,MAClE;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,QAAQ;AAAA,UAC5B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,OAAOA,YAAU,IAAI;AAE3B,SACE,+CAAC,aAAQ,cAAW,gBAAe,eAAW,sBAAG,2BAA2B,SAAS,GAClF;AAAA;AAAA,IAEA,KAAK,WAAW,IACf,8CAAC,OAAE,WAAU,iDAAgD,wCAA0B,IAEvF,+CAAC,WAAM,WAAU,kBACf;AAAA,oDAAC,WACC,yDAAC,QAAG,WAAU,2DACZ;AAAA,sDAAC,QAAG,WAAU,oBAAmB,iBAAG;AAAA,QACpC,8CAAC,QAAG,WAAU,oBAAmB,kBAAI;AAAA,QACrC,8CAAC,QAAG,WAAU,oBAAmB,oBAAM;AAAA,QACvC,8CAAC,QAAG,WAAU,oBAAmB,qBAAO;AAAA,QACxC,8CAAC,QAAG,WAAU,oBAAmB,qBAAO;AAAA,SAC1C,GACF;AAAA,MACA,8CAAC,WACE,eAAK,IAAI,CAAC,QACT,+CAAC,QAAgB,WAAU,0BACzB;AAAA,sDAAC,QAAG,WAAU,kCAAkC,cAAI,KAAI;AAAA,QACxD,8CAAC,QAAG,WAAU,wBAAwB,cAAI,aAAY;AAAA,QACtD,8CAAC,QAAG,WAAU,QACZ,wDAAC,iCAAY,SAAS,IAAI,WAAW,WAAW,YAAY,WACzD,cAAI,QACP,GACF;AAAA,QACA,8CAAC,QAAG,WAAU,8BAA8B,gDAAe,IAAI,SAAS,GAAE;AAAA,QAC1E,8CAAC,QAAG,WAAU,QACZ;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,UAAU,UAAU;AAAA,YACpB,SAAS,MACP,UAAU,OAAO;AAAA,cACf,KAAK,IAAI;AAAA,cACT,QAAQ,IAAI,WAAW,WAAW,aAAa;AAAA,YACjD,CAAC;AAAA,YAEH,WAAU;AAAA,YAET,cAAI,WAAW,WAAW,YAAY;AAAA;AAAA,QACzC,GACF;AAAA,WAvBO,IAAI,EAwBb,CACD,GACH;AAAA,OACF;AAAA,KAEJ;AAEJ;","names":["import_react","import_jsx_runtime","import_react","import_react_query","import_jsx_runtime","import_react_query","import_react","import_react_query","import_react_ui","import_react_ui","import_jsx_runtime","import_react_ui","import_jsx_runtime","import_react","import_react_ui","import_jsx_runtime","import_react","import_react_ui","import_react_query","import_react_query","import_react_query","import_react_ui","import_jsx_runtime","import_react_ui","import_jsx_runtime","import_react_ui","import_jsx_runtime","pct","import_jsx_runtime","import_react_ui","import_jsx_runtime","import_react_ui","import_react_query","import_jsx_runtime","AlertIcon","import_react","import_react_ui","import_react_query","import_jsx_runtime","import_react","import_react_ui","import_react_query","import_jsx_runtime","import_react_ui","import_react_query","import_jsx_runtime","import_react","import_react_ui","import_react_query","import_jsx_runtime","import_react_query","LIMIT","import_react","import_react_ui","import_jsx_runtime","import_react_ui","import_react_query","import_jsx_runtime","statusVariant","pct","import_react","import_react_ui","import_react_query","import_jsx_runtime","CHANNELS","import_react_ui","import_react_query","import_jsx_runtime","import_react","import_react_ui","import_react_query","import_jsx_runtime","import_react","import_react_ui","import_react_query","import_react_ui","import_jsx_runtime","AlertIcon","import_jsx_runtime","LIMIT","CHANNELS","import_react","import_react_ui","import_react_query","import_jsx_runtime","LIMIT","statusVariant","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react","import_react_ui","import_react_query","import_jsx_runtime","LIMIT","import_react","import_react_ui","import_react_query","import_jsx_runtime","import_react_ui","import_react_query","import_jsx_runtime","import_react","import_react_ui","import_react_query","import_jsx_runtime","LIMIT","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize","import_react","import_react_ui","import_react_query","import_jsx_runtime","normalize"]}
|