@odla-ai/chapter 0.20.2 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -32
- package/dist/chunk-3JG5X2LT.js +80 -0
- package/dist/chunk-3JG5X2LT.js.map +1 -0
- package/dist/chunk-AOTWFOH4.js +1481 -0
- package/dist/chunk-AOTWFOH4.js.map +1 -0
- package/dist/{chunk-LME2IHY5.js → chunk-ILGUJXSB.js} +1 -1
- package/dist/chunk-ILGUJXSB.js.map +1 -0
- package/dist/index.cjs +61 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -19
- package/dist/index.d.ts +64 -19
- package/dist/index.js +61 -6
- package/dist/index.js.map +1 -1
- package/dist/{types-D2fGiNG8.d.ts → types-CXDiDj_s.d.ts} +36 -8
- package/dist/ui/admin/index.d.ts +85 -84
- package/dist/ui/admin/index.js +8 -2
- package/dist/ui/index.d.ts +3 -2
- package/dist/ui/index.js +9 -3
- package/dist/ui/member/index.d.ts +3 -1
- package/dist/ui/member/index.js +2 -2
- package/dist/worker/index.cjs +28 -16
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +36 -8
- package/dist/worker/index.d.ts +36 -8
- package/dist/worker/index.js +28 -16
- package/dist/worker/index.js.map +1 -1
- package/package.json +3 -3
- package/runbooks/adopt-existing.md +13 -4
- package/runbooks/greenfield.md +19 -9
- package/dist/chunk-LME2IHY5.js.map +0 -1
- package/dist/chunk-MKXHZMAP.js +0 -51
- package/dist/chunk-MKXHZMAP.js.map +0 -1
- package/dist/chunk-UIWFEESI.js +0 -922
- package/dist/chunk-UIWFEESI.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ui/admin.tsx","../src/ui/chrome.tsx","../src/ui/admin-layout.tsx","../src/ui/admin-brand.tsx","../src/ui/admin-route.ts","../src/ui/admin-workspaces.tsx","../src/ui/admin-availability.tsx","../src/ui/admin-api.ts","../src/ui/admin-billing.tsx","../src/ui/admin-dashboard.tsx","../src/ui/admin-email.tsx","../src/ui/admin-people.tsx","../src/ui/admin-record-actions.tsx","../src/ui/admin-network.tsx","../src/ui/admin-record-activity.tsx","../src/ui/admin-record-comms.tsx","../src/ui/admin-record-scheduling.tsx","../src/ui/admin-defaults.ts","../src/ui/admin-meetings.tsx"],"sourcesContent":["// ChapterAdmin owns auth and operational wiring; sites choose or replace chrome\n// and workspaces without reimplementing the boundary.\nimport { useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport {\n ClerkGate,\n SignedIn,\n SignedOut,\n SignIn,\n useClerkAuth,\n clerkAppearanceFromTokens,\n} from \"@odla-ai/auth-clerk\";\nimport { CrmClient } from \"@odla-ai/crm\";\nimport { ThemeScope } from \"@odla-ai/ui/components\";\nimport { S, Gate, AdminShell } from \"./chrome.js\";\nimport { defaultAdminWorkspaces } from \"./admin-workspaces.js\";\nimport { adminRouteFromUrl, adminRouteHref } from \"./admin-route.js\";\nimport { BrandStyle } from \"./brand-style.js\";\nimport type {\n AdminChrome,\n AdminRouting,\n AdminSection,\n AdminShellProps,\n AdminWorkspace,\n Brand,\n} from \"./chrome.js\";\nimport type { Chapter } from \"../types\";\n\nexport type {\n AdminSection,\n AdminSectionContext,\n AdminWorkspace,\n AdminRouteState,\n AdminRouteTarget,\n} from \"./chrome.js\";\n\n/** Configuration for the Clerk-gated, brand-scoped Chapter admin console. */\nexport interface ChapterAdminProps {\n chapter?: Chapter;\n /** Replace or transform the standard workspace set. */\n workspaces?:\n | AdminWorkspace[]\n | ((defaults: readonly AdminWorkspace[]) => AdminWorkspace[]);\n /** @deprecated Use workspaces. */\n sections?: AdminSection[];\n basePath?: string;\n brand?: Brand;\n crmBasePath?: string;\n apiBase?: string;\n /** Default fragment: `/admin/#people/person/record-id/profile`. */\n routing?: AdminRouting;\n /** Default editorial. Topbar retains the legacy global-nav shell. */\n chrome?: AdminChrome;\n renderHeader?: AdminShellProps[\"renderHeader\"];\n}\n\nfunction AdminTheme(props: { chapter?: Chapter; children: ReactNode }) {\n const brand = props.chapter?.brand;\n return (\n <ThemeScope\n data-chapter-admin=\"\"\n theme={brand?.theme}\n colorScheme={brand?.colorScheme ?? \"light\"}\n >\n <BrandStyle brand={brand} selector=\"[data-chapter-admin]\" />\n {props.children}\n </ThemeScope>\n );\n}\n\nfunction Authed(props: {\n workspaces: AdminWorkspace[];\n basePath: string;\n brand: Brand;\n crmBasePath: string;\n apiBase: string;\n routing: AdminRouting;\n chrome: AdminChrome;\n renderHeader?: AdminShellProps[\"renderHeader\"];\n}) {\n const {\n workspaces,\n basePath,\n brand,\n crmBasePath,\n apiBase,\n routing,\n chrome,\n renderHeader,\n } = props;\n const { getToken, signOut } = useClerkAuth();\n const client = useMemo(\n () =>\n new CrmClient({\n basePath: crmBasePath,\n headers: async (): Promise<Record<string, string>> => {\n const token = await getToken();\n return token ? { authorization: `Bearer ${token}` } : {};\n },\n }),\n [getToken, crmBasePath],\n );\n const [state, setState] = useState<{\n status: \"checking\" | \"ok\" | \"denied\";\n email?: string | null;\n }>({ status: \"checking\" });\n\n useEffect(() => {\n let live = true;\n void (async () => {\n try {\n const token = await getToken();\n const response = await fetch(`${apiBase}/api/me`, {\n headers: token ? { authorization: `Bearer ${token}` } : {},\n });\n const body = (await response.json().catch(() => ({}))) as {\n authorized?: boolean;\n email?: string | null;\n };\n if (live) setState({\n status: body.authorized ? \"ok\" : \"denied\",\n email: body.email ?? null,\n });\n } catch {\n if (live) setState({ status: \"denied\" });\n }\n })();\n return () => {\n live = false;\n };\n }, [getToken, apiBase]);\n\n if (state.status === \"checking\") return <Gate brand={brand}><p style={S.muted}>Checking access…</p></Gate>;\n if (state.status === \"denied\") {\n return (\n <Gate brand={brand}>\n <div className=\"card\" style={S.card}>\n <h2 style={{ marginTop: 0 }}>Not authorized</h2>\n <p style={S.muted}>\n {state.email ? `${state.email} isn't` : \"This account isn't\"} on the admin list.\n </p>\n <button className=\"btn secondary\" onClick={() => signOut()}>Sign out</button>\n </div>\n </Gate>\n );\n }\n return (\n <AdminShell\n workspaces={workspaces}\n basePath={basePath}\n brand={brand}\n client={client}\n getToken={getToken}\n signOut={signOut}\n email={state.email ?? null}\n routing={routing}\n chrome={chrome}\n renderHeader={renderHeader}\n />\n );\n}\n\nconst signInRedirect = (\n basePath: string,\n workspaces: readonly AdminWorkspace[],\n): string => {\n if (typeof window === \"undefined\") return basePath;\n const current = new URL(window.location.href);\n const route = adminRouteFromUrl(current, basePath, workspaces.map((workspace) => workspace.id));\n // Clerk owns the hash while signed out. Carry the requested admin state\n // through its redirect as an inbound query, then AdminShell canonicalizes.\n return adminRouteHref(current, basePath, route, \"query\");\n};\n\n/** Render the complete authenticated admin application from one Chapter config. */\nexport function ChapterAdmin(props: ChapterAdminProps) {\n const defaults = useMemo(\n () => (props.chapter ? defaultAdminWorkspaces(props.chapter) : []),\n [props.chapter],\n );\n const workspaces = useMemo(() => {\n if (typeof props.workspaces === \"function\") return props.workspaces(defaults);\n return props.workspaces ?? props.sections ?? defaults;\n }, [props.workspaces, props.sections, defaults]);\n const basePath = props.basePath ?? \"/admin\";\n const brand = props.brand ?? {\n name: props.chapter?.name ?? \"Admin\",\n badge: props.chapter?.brand.badge,\n wordmark: props.chapter?.brand.wordmark,\n };\n const crmBasePath = props.crmBasePath ?? \"/api/crm\";\n const apiBase = props.apiBase ?? \"\";\n const routing = props.routing ?? \"fragment\";\n const chrome = props.chrome ?? \"editorial\";\n const redirect = signInRedirect(basePath, workspaces);\n const [publishableKey, setPublishableKey] = useState<string | null | undefined>(undefined);\n\n useEffect(() => {\n let live = true;\n void fetch(`${apiBase}/api/config`)\n .then((response) => response.json())\n .then((body: { clerkPublishableKey?: string | null }) =>\n live && setPublishableKey(body.clerkPublishableKey ?? null))\n .catch(() => live && setPublishableKey(null));\n return () => {\n live = false;\n };\n }, [apiBase]);\n\n let content: ReactNode;\n if (publishableKey === undefined) {\n content = <Gate brand={brand}><p style={S.muted}>Loading…</p></Gate>;\n } else if (!publishableKey) {\n content = (\n <Gate brand={brand}>\n <div className=\"card\" style={S.card}>\n <h2 style={{ marginTop: 0 }}>Sign-in not configured</h2>\n <p style={S.muted}>No Clerk publishable key is set for this environment yet.</p>\n </div>\n </Gate>\n );\n } else if (workspaces.length === 0) {\n content = <Gate brand={brand}><p style={S.muted}>No admin workspaces are configured.</p></Gate>;\n } else {\n content = (\n <ClerkGate\n publishableKey={publishableKey}\n appearance={clerkAppearanceFromTokens()}\n afterSignOutUrl=\"/\"\n >\n <SignedOut>\n <Gate brand={brand} tagline=\"Admin sign-in — invite only\">\n <SignIn\n routing=\"hash\"\n forceRedirectUrl={redirect}\n signUpForceRedirectUrl={redirect}\n />\n </Gate>\n </SignedOut>\n <SignedIn>\n <Authed\n workspaces={workspaces}\n basePath={basePath}\n brand={brand}\n crmBasePath={crmBasePath}\n apiBase={apiBase}\n routing={routing}\n chrome={chrome}\n renderHeader={props.renderHeader}\n />\n </SignedIn>\n </ClerkGate>\n );\n }\n return <AdminTheme chapter={props.chapter}>{content}</AdminTheme>;\n}\n","// Shared chrome for ChapterAdmin: workspace contracts, auth gates, and the\n// signed-in shell. Workspace navigation is in-content Tabs by default; the\n// legacy global TopBar is an explicit compatibility mode.\nimport { useCallback, useEffect, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { Tabs, TopBar, TopBarLink } from \"@odla-ai/ui/components\";\nimport type { CrmClient } from \"@odla-ai/crm\";\nimport { ThemeWarning } from \"./admin-layout.js\";\nimport { badgeText, brandDisplay, S, type Brand } from \"./admin-brand.js\";\nimport {\n adminRouteFromUrl,\n adminRouteHref,\n adminSectionFromUrl,\n adminSectionHref,\n type AdminRouteState,\n type AdminRouting,\n} from \"./admin-route.js\";\n\nexport {\n adminRouteFromUrl,\n adminRouteHref,\n adminSectionFromUrl,\n adminSectionHref,\n};\nexport type { AdminRouteState, AdminRouting };\nexport { Gate, S } from \"./admin-brand.js\";\nexport type { Brand } from \"./admin-brand.js\";\n\n/** A workspace id or partial nested route passed to navigation helpers. */\nexport type AdminRouteTarget =\n | string\n | {\n workspaceId?: string;\n viewId?: string | null;\n recordId?: string | null;\n detailTab?: string | null;\n };\n\n/** Context shared by every admin workspace and its nested views. */\nexport interface AdminSectionContext {\n client: CrmClient;\n getToken: () => Promise<string | null>;\n route: AdminRouteState;\n navigate: (target: AdminRouteTarget) => void;\n href: (target: AdminRouteTarget) => string;\n}\n\n/** One top-level admin workspace rendered inside the signed-in shell. */\nexport interface AdminWorkspace {\n id: string;\n label: string;\n render: (ctx: AdminSectionContext) => ReactNode;\n}\n\n/** Legacy name for a top-level workspace. @deprecated Use AdminWorkspace. */\nexport type AdminSection = AdminWorkspace;\n/** Built-in shell presentation: editorial, legacy top bar, or host-owned. */\nexport type AdminChrome = \"editorial\" | \"topbar\" | \"none\";\n\nconst mergeRoute = (current: AdminRouteState, target: AdminRouteTarget): AdminRouteState => {\n if (typeof target === \"string\") return { workspaceId: target };\n const changingWorkspace = target.workspaceId != null && target.workspaceId !== current.workspaceId;\n const next: AdminRouteState = changingWorkspace\n ? { workspaceId: target.workspaceId! }\n : { ...current, ...(target.workspaceId ? { workspaceId: target.workspaceId } : {}) };\n for (const key of [\"viewId\", \"recordId\", \"detailTab\"] as const) {\n const value = target[key];\n if (value === null) delete next[key];\n else if (value !== undefined) next[key] = value;\n }\n if (target.viewId !== undefined && target.recordId === undefined) {\n delete next.recordId;\n delete next.detailTab;\n }\n if (target.recordId === null) delete next.detailTab;\n return next;\n};\n\nexport interface AdminShellProps {\n workspaces: AdminWorkspace[];\n basePath: string;\n brand: Brand;\n client: CrmClient;\n getToken: () => Promise<string | null>;\n signOut: () => void;\n email: string | null;\n routing?: AdminRouting;\n chrome?: AdminChrome;\n renderHeader?: (props: { brand: Brand; email: string | null; signOut: () => void }) => ReactNode;\n}\n\nexport function AdminShell({\n workspaces,\n basePath,\n brand,\n client,\n getToken,\n signOut,\n email,\n routing = \"fragment\",\n chrome = \"editorial\",\n renderHeader,\n}: AdminShellProps) {\n const routeFromLocation = useCallback(() => {\n if (typeof window === \"undefined\") return { workspaceId: workspaces[0]?.id ?? \"\" };\n return adminRouteFromUrl(new URL(window.location.href), basePath, workspaces.map((workspace) => workspace.id));\n }, [workspaces, basePath]);\n const [route, setRoute] = useState<AdminRouteState>(routeFromLocation);\n const href = useCallback(\n (target: AdminRouteTarget) =>\n typeof window === \"undefined\"\n ? `#${mergeRoute(route, target).workspaceId}`\n : adminRouteHref(new URL(window.location.href), basePath, mergeRoute(route, target), routing),\n [route, basePath, routing],\n );\n const navigate = useCallback(\n (target: AdminRouteTarget) => {\n const next = mergeRoute(route, target);\n if (typeof window !== \"undefined\") {\n window.history.pushState(null, \"\", adminRouteHref(new URL(window.location.href), basePath, next, routing));\n }\n setRoute(next);\n },\n [route, basePath, routing],\n );\n\n useEffect(() => {\n const sync = () => setRoute(routeFromLocation());\n window.addEventListener(\"popstate\", sync);\n window.addEventListener(\"hashchange\", sync);\n return () => {\n window.removeEventListener(\"popstate\", sync);\n window.removeEventListener(\"hashchange\", sync);\n };\n }, [routeFromLocation]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const canonical = adminRouteHref(new URL(window.location.href), basePath, route, routing);\n const actual = `${window.location.pathname}${window.location.search}${window.location.hash}`;\n if (canonical !== actual) window.history.replaceState(null, \"\", canonical);\n // Canonicalize only initial/inbound state; route changes already own history.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const context: AdminSectionContext = { client, getToken, route, navigate, href };\n const active = workspaces.find((workspace) => workspace.id === route.workspaceId) ?? workspaces[0];\n const identity = (\n <>\n <span style={{ ...S.role, color: \"inherit\", borderColor: \"currentColor\", background: \"transparent\" }}>admin</span>\n {email ? <span style={{ opacity: 0.72, fontSize: 12 }}>{email}</span> : null}\n <button className=\"btn secondary mini\" onClick={signOut}>Sign out</button>\n </>\n );\n\n if (chrome === \"topbar\") {\n return (\n <>\n <TopBar>\n <a className=\"topbar-brand\" href=\"/\"><span style={S.badgeSm}>{badgeText(brand)}</span>{brandDisplay(brand)}</a>\n <nav className=\"topbar-nav\" aria-label=\"Admin navigation\">\n {workspaces.map((workspace) => (\n <TopBarLink key={workspace.id} active={workspace.id === route.workspaceId} onClick={() => navigate(workspace.id)}>\n {workspace.label}\n </TopBarLink>\n ))}\n </nav>\n <span className=\"topbar-spacer\" />\n <div className=\"topbar-actions\">{identity}</div>\n </TopBar>\n <main className=\"shell-main\" style={S.main}><ThemeWarning />{active?.render(context)}</main>\n </>\n );\n }\n\n const header = renderHeader ? renderHeader({ brand, email, signOut }) : chrome === \"editorial\" ? (\n <header style={S.masthead}>\n <a href=\"/\" style={S.mastheadBrand}><span style={S.badgeSm}>{badgeText(brand)}</span>{brandDisplay(brand)}</a>\n <span style={{ opacity: 0.68 }}>Admin Console</span>\n <span style={{ flex: 1 }} />\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 10 }}>{identity}</div>\n </header>\n ) : null;\n return (\n <>\n {header}\n <main className=\"shell-main\" style={S.main}>\n <ThemeWarning />\n <Tabs\n style={S.workspaceTabs}\n ariaLabel=\"Admin workspaces\"\n value={route.workspaceId}\n onValueChange={(workspaceId) => setRoute({ workspaceId })}\n items={workspaces.map((workspace) => ({\n value: workspace.id,\n label: workspace.label,\n href: href(workspace.id),\n panel: workspace.render(context),\n }))}\n />\n </main>\n </>\n );\n}\n","// Shared layout for the admin sections, so every section is a centered column of\n// odla-ui `.panel` cards with consistent width and spacing — the container the\n// chrome expects sections to own. No invented classes: `.panel`/`.muted` are\n// odla-ui's, and the width/gap is inline so it works without a per-site stylesheet.\nimport { useEffect, useState } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\n\nconst PAGE: CSSProperties = { maxWidth: 1120, margin: \"0 auto\", padding: \"28px 20px 64px\", display: \"flex\", flexDirection: \"column\", gap: 20 };\nconst HEAD: CSSProperties = { display: \"flex\", alignItems: \"baseline\", justifyContent: \"space-between\", gap: 16, flexWrap: \"wrap\" };\n\n/** The centered content column every admin section renders into. */\nexport function AdminPage({ children }: { children: ReactNode }) {\n return <div style={PAGE}>{children}</div>;\n}\n\n/** An odla-ui `.panel` card with an optional heading + trailing actions. */\nexport function Panel({ title, actions, children }: { title?: ReactNode; actions?: ReactNode; children: ReactNode }) {\n return (\n <section className=\"panel\" style={{ display: \"flex\", flexDirection: \"column\", gap: 14 }}>\n {title || actions ? (\n <header style={HEAD}>\n {title ? <h2 style={{ margin: 0, fontSize: 18 }}>{title}</h2> : <span />}\n {actions ? <div style={{ display: \"flex\", gap: 8, alignItems: \"center\" }}>{actions}</div> : null}\n </header>\n ) : null}\n {children}\n </section>\n );\n}\n\n// odla-ui components read their colors from `--ui-*` design tokens whose VALUES\n// come from the theme layer (e.g. @odla-ai/ui/themes/paper/tokens.css + ui.css),\n// NOT from @odla-ai/ui/index.css. Loading only index.css (or a theme whose remap\n// has no primitives behind it) leaves tokens like `--ui-surface` undefined, and\n// the whole console renders transparent/broken — silently. This probes a real\n// `.panel` background and, if it's transparent, says so LOUDLY instead.\nfunction themeLooksMissing(): boolean {\n if (typeof document === \"undefined\") return false;\n const probe = document.createElement(\"div\");\n probe.className = \"panel\";\n probe.style.cssText = \"position:absolute;visibility:hidden;pointer-events:none\";\n document.body.appendChild(probe);\n const bg = getComputedStyle(probe).backgroundColor;\n probe.remove();\n return !bg || bg === \"transparent\" || bg === \"rgba(0, 0, 0, 0)\";\n}\n\n/** A loud banner when the odla-ui theme token layer is missing. */\nexport function ThemeWarning() {\n const [missing, setMissing] = useState(false);\n useEffect(() => setMissing(themeLooksMissing()), []);\n if (!missing) return null;\n return (\n <div\n role=\"alert\"\n style={{ background: \"#7f1d1d\", color: \"#fff\", padding: \"12px 20px\", fontSize: 14, lineHeight: 1.5, textAlign: \"center\" }}\n >\n <strong>odla-ui theme tokens are missing.</strong> The console reads colors from a theme layer, not{\" \"}\n <code>@odla-ai/ui/index.css</code> alone. Import a theme before it — e.g.{\" \"}\n <code>@odla-ai/ui/themes/paper/tokens.css</code> and <code>@odla-ai/ui/themes/paper/ui.css</code> — then{\" \"}\n <code>@odla-ai/ui/index.css</code>. See the @odla-ai/chapter README (“Theme tokens”).\n </div>\n );\n}\n\n/** A centered status line for loading / empty / error states. */\nexport function AdminNote({ children }: { children: ReactNode }) {\n return (\n <AdminPage>\n <section className=\"panel\">\n <p className=\"muted\" style={{ margin: 0 }}>{children}</p>\n </section>\n </AdminPage>\n );\n}\n","import type { CSSProperties, ReactNode } from \"react\";\n\nexport type Brand = { name: string; badge?: string; wordmark?: ReactNode };\n\nexport const badgeText = (brand: Brand): string =>\n brand.badge ?? brand.name.slice(0, 3).toUpperCase();\n\nexport const brandDisplay = (brand: Brand): ReactNode => {\n const display = brand.wordmark ?? brand.name;\n if (typeof display !== \"string\" || !display.includes(\"&\")) return display;\n return (\n <span>\n {display.split(\"&\").map((part, index, all) => (\n <span key={`${part}:${index}`}>\n {part}\n {index < all.length - 1 ? <span className=\"mk-amp\">&</span> : null}\n </span>\n ))}\n </span>\n );\n};\n\nexport const S: Record<string, CSSProperties> = {\n gate: {\n minHeight: \"100vh\",\n display: \"grid\",\n placeItems: \"center\",\n padding: 24,\n background:\n \"radial-gradient(900px 480px at 50% -8%, var(--ui-accent-soft), transparent 70%),\" +\n \" radial-gradient(700px 500px at 110% 10%, var(--ui-good-soft), transparent 60%)\",\n },\n gateInner: { width: \"100%\", maxWidth: 400, display: \"flex\", flexDirection: \"column\", alignItems: \"center\" },\n brandBox: { textAlign: \"center\", marginBottom: 22 },\n badge: {\n width: 52, height: 52, margin: \"0 auto 14px\", display: \"grid\", placeItems: \"center\",\n fontSize: 15, fontWeight: 700, color: \"var(--ui-on-accent)\",\n background: \"linear-gradient(135deg, var(--ui-accent), var(--ui-accent-strong))\",\n borderRadius: 14, boxShadow: \"0 10px 28px var(--ui-accent-soft)\",\n },\n badgeSm: {\n width: 30, height: 30, display: \"grid\", placeItems: \"center\", fontSize: 10,\n fontWeight: 700, color: \"var(--ui-on-accent)\", background: \"var(--ui-accent)\",\n borderRadius: 8, marginRight: 10,\n },\n h1: { margin: 0, fontSize: 28, letterSpacing: \"-0.02em\", fontWeight: 700 },\n muted: { color: \"var(--ui-text-muted)\" },\n role: {\n fontFamily: \"var(--ui-font-mono)\", fontSize: 11, textTransform: \"uppercase\",\n letterSpacing: \"0.04em\", padding: \"2px 8px\", borderRadius: 999,\n background: \"var(--ui-accent-soft)\", border: \"1px solid var(--ui-accent)\",\n color: \"var(--ui-accent-strong)\",\n },\n main: { minHeight: \"calc(100vh - 61px)\", background: \"var(--ui-bg)\" },\n card: { width: \"100%\", textAlign: \"center\" },\n masthead: {\n display: \"flex\", alignItems: \"center\", gap: 16, flexWrap: \"wrap\",\n padding: \"18px max(20px, calc((100% - 1120px) / 2))\",\n color: \"var(--ui-bg)\", background: \"var(--ui-text)\",\n },\n mastheadBrand: {\n display: \"inline-flex\", alignItems: \"center\", color: \"inherit\",\n fontFamily: \"var(--ui-font-display)\", fontSize: 22, textDecoration: \"none\",\n },\n workspaceTabs: { maxWidth: 1160, margin: \"0 auto\", padding: \"18px 20px 0\" },\n};\n\nexport function Gate(props: { brand: Brand; tagline?: string; children: ReactNode }) {\n const { brand, tagline, children } = props;\n return (\n <div style={S.gate}>\n <div style={S.gateInner}>\n <div style={S.brandBox}>\n <div style={S.badge}>{badgeText(brand)}</div>\n <h1 style={S.h1}>{brandDisplay(brand)}</h1>\n {tagline ? <p style={{ ...S.muted, margin: \"8px 0 0\", fontSize: 14 }}>{tagline}</p> : null}\n </div>\n {children}\n </div>\n </div>\n );\n}\n","/** Typed URL state for the admin's nested in-page workspaces. */\nexport interface AdminRouteState {\n workspaceId: string;\n viewId?: string;\n recordId?: string;\n detailTab?: string;\n}\n\n/** URL encoding used for admin workspace state. */\nexport type AdminRouting = \"fragment\" | \"query\" | \"path\";\nexport type AdminRouteAliases = Readonly<Record<string, AdminRouteState>>;\n\nconst DEFAULT_ALIASES: AdminRouteAliases = {\n billing: { workspaceId: \"dashboard\", viewId: \"billing\" },\n meetings: { workspaceId: \"dashboard\" },\n calls: { workspaceId: \"dashboard\" },\n availability: { workspaceId: \"settings\", viewId: \"calendar\" },\n calendar: { workspaceId: \"settings\", viewId: \"calendar\" },\n email: { workspaceId: \"settings\", viewId: \"email\" },\n};\n\nconst cleanBase = (basePath: string): string =>\n basePath.length > 1 ? basePath.replace(/\\/+$/, \"\") : basePath;\n\nconst decode = (segment: string | undefined): string | undefined => {\n if (!segment) return undefined;\n try {\n return decodeURIComponent(segment);\n } catch {\n return undefined;\n }\n};\n\nconst fromParts = (parts: readonly string[]): AdminRouteState | null => {\n const workspaceId = decode(parts[0]);\n if (!workspaceId) return null;\n const viewId = decode(parts[1]);\n const recordId = decode(parts[2]);\n const detailTab = decode(parts[3]);\n return {\n workspaceId,\n ...(viewId ? { viewId } : {}),\n ...(recordId ? { recordId } : {}),\n ...(detailTab ? { detailTab } : {}),\n };\n};\n\nconst resolve = (\n candidate: AdminRouteState | null,\n workspaceIds: readonly string[],\n aliases: AdminRouteAliases,\n): AdminRouteState | null => {\n if (!candidate) return null;\n if (workspaceIds.includes(candidate.workspaceId)) return candidate;\n const alias = aliases[candidate.workspaceId] ?? DEFAULT_ALIASES[candidate.workspaceId];\n return alias && workspaceIds.includes(alias.workspaceId) ? alias : null;\n};\n\n/** Read canonical fragments first, then inbound query and legacy path links. */\nexport function adminRouteFromUrl(\n url: URL,\n basePath: string,\n workspaceIds: readonly string[],\n aliases: AdminRouteAliases = {},\n): AdminRouteState {\n const fallback = { workspaceId: workspaceIds[0] ?? \"\" };\n const hashParts = url.hash.replace(/^#\\/?/, \"\").split(\"/\").filter(Boolean);\n const fromHash = resolve(fromParts(hashParts), workspaceIds, aliases);\n if (fromHash) return fromHash;\n\n const tab = url.searchParams.get(\"tab\");\n const fromQuery = resolve(\n tab\n ? {\n workspaceId: tab,\n ...(url.searchParams.get(\"view\") ? { viewId: url.searchParams.get(\"view\")! } : {}),\n ...(url.searchParams.get(\"record\") ? { recordId: url.searchParams.get(\"record\")! } : {}),\n ...(url.searchParams.get(\"detail\") ? { detailTab: url.searchParams.get(\"detail\")! } : {}),\n }\n : null,\n workspaceIds,\n aliases,\n );\n if (fromQuery) return fromQuery;\n\n const base = cleanBase(basePath);\n const rest = url.pathname.startsWith(base) ? url.pathname.slice(base.length).replace(/^\\//, \"\") : \"\";\n return resolve(fromParts(rest.split(\"/\").filter(Boolean)), workspaceIds, aliases) ?? fallback;\n}\n\nconst encodedParts = (route: AdminRouteState): string[] =>\n [route.workspaceId, route.viewId, route.recordId, route.detailTab]\n .filter((part): part is string => Boolean(part))\n .map(encodeURIComponent);\n\n/** Build a stable URL for one admin state. Fragment routing is the default. */\nexport function adminRouteHref(\n current: URL,\n basePath: string,\n route: AdminRouteState,\n routing: AdminRouting = \"fragment\",\n): string {\n const next = new URL(current);\n const base = cleanBase(basePath);\n const mountPaths = new Set([base, `${base}/`, `${base}/index.html`]);\n if (!mountPaths.has(next.pathname)) next.pathname = `${base}/`;\n for (const key of [\"tab\", \"view\", \"record\", \"detail\"]) next.searchParams.delete(key);\n\n if (routing === \"fragment\") {\n next.hash = encodedParts(route).join(\"/\");\n } else if (routing === \"query\") {\n next.hash = \"\";\n next.searchParams.set(\"tab\", route.workspaceId);\n if (route.viewId) next.searchParams.set(\"view\", route.viewId);\n if (route.recordId) next.searchParams.set(\"record\", route.recordId);\n if (route.detailTab) next.searchParams.set(\"detail\", route.detailTab);\n } else {\n next.hash = \"\";\n next.pathname = `${base}/${encodeURIComponent(route.workspaceId)}`;\n if (route.viewId) next.searchParams.set(\"view\", route.viewId);\n if (route.recordId) next.searchParams.set(\"record\", route.recordId);\n if (route.detailTab) next.searchParams.set(\"detail\", route.detailTab);\n }\n return `${next.pathname}${next.search}${next.hash}`;\n}\n\n/** Backwards-compatible section helpers over the workspace router. */\nexport function adminSectionFromUrl(url: URL, basePath: string, sectionIds: readonly string[]): string {\n return adminRouteFromUrl(url, basePath, sectionIds).workspaceId;\n}\n\n/** Build a compatibility URL for a top-level admin section. */\nexport function adminSectionHref(\n current: URL,\n basePath: string,\n id: string,\n routing: AdminRouting = \"fragment\",\n): string {\n return adminRouteHref(current, basePath, { workspaceId: id }, routing);\n}\n","import { Tabs } from \"@odla-ai/ui/components\";\nimport type { Chapter } from \"../types.js\";\nimport { availabilitySection } from \"./admin-availability.js\";\nimport { billingSection } from \"./admin-billing.js\";\nimport { dashboardSection } from \"./admin-dashboard.js\";\nimport { emailSection } from \"./admin-email.js\";\nimport { collectionSection } from \"./admin-people.js\";\nimport type { AdminSectionContext, AdminWorkspace } from \"./chrome.js\";\n\nexport const adminViewContext = (\n ctx: AdminSectionContext,\n viewId: string,\n active: boolean,\n): AdminSectionContext => {\n const route = {\n workspaceId: ctx.route.workspaceId,\n viewId,\n ...(active && ctx.route.recordId ? { recordId: ctx.route.recordId } : {}),\n ...(active && ctx.route.detailTab ? { detailTab: ctx.route.detailTab } : {}),\n };\n const targetFromView = (target: Parameters<AdminSectionContext[\"navigate\"]>[0]) => {\n if (typeof target === \"string\") return target;\n if (target.workspaceId && target.workspaceId !== route.workspaceId) return target;\n if (target.viewId && target.viewId !== route.viewId) return target;\n return { ...route, ...target };\n };\n return {\n ...ctx,\n route,\n navigate: (target) => ctx.navigate(targetFromView(target)),\n href: (target) => ctx.href(targetFromView(target)),\n };\n};\n\nfunction DashboardWorkspace({ ctx }: { ctx: AdminSectionContext }) {\n const active = ctx.route.viewId === \"billing\" ? \"billing\" : \"overview\";\n const overview = dashboardSection({ id: \"overview\", label: \"Overview\" });\n const billing = billingSection();\n return (\n <Tabs\n ariaLabel=\"Dashboard views\"\n value={active}\n items={[\n {\n value: \"overview\",\n label: \"Overview\",\n href: ctx.href({ viewId: \"overview\", recordId: null, detailTab: null }),\n panel: overview.render(adminViewContext(ctx, \"overview\", active === \"overview\")),\n },\n {\n value: \"billing\",\n label: \"Billing\",\n href: ctx.href({ viewId: \"billing\", recordId: null, detailTab: null }),\n panel: billing.render(adminViewContext(ctx, \"billing\", active === \"billing\")),\n },\n ]}\n />\n );\n}\n\nfunction SettingsWorkspace({ ctx }: { ctx: AdminSectionContext }) {\n const active = ctx.route.viewId === \"email\" ? \"email\" : \"calendar\";\n const calendar = availabilitySection({ id: \"calendar\", label: \"Calendar\" });\n const email = emailSection();\n return (\n <Tabs\n ariaLabel=\"Settings views\"\n value={active}\n items={[\n {\n value: \"calendar\",\n label: \"Calendar\",\n href: ctx.href({ viewId: \"calendar\", recordId: null, detailTab: null }),\n panel: calendar.render(adminViewContext(ctx, \"calendar\", active === \"calendar\")),\n },\n {\n value: \"email\",\n label: \"Email\",\n href: ctx.href({ viewId: \"email\", recordId: null, detailTab: null }),\n panel: email.render(adminViewContext(ctx, \"email\", active === \"email\")),\n },\n ]}\n />\n );\n}\n\nfunction PeopleWorkspace({ chapter, ctx }: { chapter: Chapter; ctx: AdminSectionContext }) {\n const types = Object.entries(chapter.crm.config.types);\n const fallback = types[0]?.[0] ?? \"person\";\n const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId! : fallback;\n const networkSharing = chapter.network.targets.length > 0;\n return (\n <Tabs\n ariaLabel=\"CRM collections\"\n value={active}\n variant=\"pill\"\n items={types.map(([type, def]) => {\n const section = collectionSection({\n crm: chapter.crm,\n type,\n lifecycle: chapter.mode === \"chapter\" && type === \"person\",\n roles: chapter.auth.ladder,\n networkSharing,\n });\n return {\n value: type,\n label: def.labelPlural ?? def.label,\n href: ctx.href({ viewId: type, recordId: null, detailTab: null }),\n panel: section.render(adminViewContext(ctx, type, active === type)),\n };\n })}\n />\n );\n}\n\n/** Default follower grammar: three workspaces with nested operational views. */\nexport function defaultAdminWorkspaces(chapter: Chapter): AdminWorkspace[] {\n const people: AdminWorkspace = {\n id: \"people\",\n label: \"People\",\n render: (ctx) => <PeopleWorkspace chapter={chapter} ctx={ctx} />,\n };\n if (chapter.mode === \"hub\") return [people];\n return [\n { id: \"dashboard\", label: \"Dashboard\", render: (ctx) => <DashboardWorkspace ctx={ctx} /> },\n people,\n { id: \"settings\", label: \"Settings\", render: (ctx) => <SettingsWorkspace ctx={ctx} /> },\n ];\n}\n","// Availability section: the owner-editable booking rules from GET/PUT\n// /api/admin/scheduling, as an odla-ui form. The PUT returns field-keyed\n// validation messages, surfaced inline on each Field.\nimport { useState } from \"react\";\nimport { Button, Checkbox, Field, Input } from \"@odla-ai/ui/components\";\nimport { useAdminResource } from \"./admin-api.js\";\nimport { AdminPage, AdminNote, Panel } from \"./admin-layout.js\";\nimport type { AdminSection, AdminSectionContext } from \"./chrome.js\";\n\ninterface Scheduling {\n slotMinutes: number;\n days: number[];\n startHour: number;\n endHour: number;\n timezone: string;\n minNoticeHours: number;\n windowDays: number;\n summaryTemplate: string;\n}\nconst DAYS = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n\nfunction AvailabilityBody({ ctx }: { ctx: AdminSectionContext }) {\n const { data, loading, error, refresh } = useAdminResource<{ scheduling: Scheduling }>(ctx.getToken, \"/api/admin/scheduling\");\n const [draft, setDraft] = useState<Scheduling | null>(null);\n const [busy, setBusy] = useState(false);\n const [note, setNote] = useState<string | null>(null);\n const [errors, setErrors] = useState<Record<string, string>>({});\n\n const cfg = draft ?? data?.scheduling ?? null;\n if (loading) return <AdminNote>Loading…</AdminNote>;\n if (error || !cfg) return <AdminNote>Couldn’t load availability{error ? `: ${error}` : \"\"}.</AdminNote>;\n\n const edit = (patch: Partial<Scheduling>) => setDraft({ ...cfg, ...patch });\n const toggleDay = (d: number) => edit({ days: cfg.days.includes(d) ? cfg.days.filter((x) => x !== d) : [...cfg.days, d].sort() });\n const num = (v: string, fallback: number) => (Number.isFinite(Number(v)) ? Number(v) : fallback);\n\n const save = async () => {\n setBusy(true);\n setNote(null);\n setErrors({});\n const token = await ctx.getToken();\n try {\n const r = await fetch(\"/api/admin/scheduling\", { method: \"PUT\", headers: { authorization: `Bearer ${token ?? \"\"}`, \"content-type\": \"application/json\" }, body: JSON.stringify(cfg) });\n const body = (await r.json().catch(() => ({}))) as { error?: string; errors?: Record<string, string> };\n if (!r.ok) {\n setErrors(body.errors ?? {});\n setNote(body.error ?? `save failed (${r.status})`);\n return;\n }\n setDraft(null);\n refresh();\n setNote(\"Saved.\");\n } catch (e) {\n setNote(e instanceof Error ? e.message : String(e));\n } finally {\n setBusy(false);\n }\n };\n\n const numField = (key: keyof Scheduling, label: string) => (\n <Field label={label} error={errors[key]}>\n <Input type=\"number\" value={cfg[key] as number} onChange={(e) => edit({ [key]: num((e.target as HTMLInputElement).value, cfg[key] as number) } as Partial<Scheduling>)} />\n </Field>\n );\n\n return (\n <AdminPage>\n <Panel title=\"Booking availability\" actions={note ? <span className=\"muted\">{note}</span> : undefined}>\n <Field label=\"Days\" error={errors.days}>\n <div style={{ display: \"flex\", gap: 14, flexWrap: \"wrap\" }}>\n {DAYS.map((d, i) => (\n <Checkbox key={d} label={d} checked={cfg.days.includes(i)} onChange={() => toggleDay(i)} />\n ))}\n </div>\n </Field>\n <div style={{ display: \"grid\", gridTemplateColumns: \"repeat(auto-fit, minmax(180px, 1fr))\", gap: 14 }}>\n {numField(\"startHour\", \"Start hour (0–24)\")}\n {numField(\"endHour\", \"End hour (0–24)\")}\n {numField(\"slotMinutes\", \"Slot length (minutes)\")}\n {numField(\"minNoticeHours\", \"Minimum notice (hours)\")}\n {numField(\"windowDays\", \"Booking window (days)\")}\n <Field label=\"Timezone\" error={errors.timezone}>\n <Input value={cfg.timezone} onChange={(e) => edit({ timezone: (e.target as HTMLInputElement).value })} />\n </Field>\n </div>\n <Field label=\"Event summary template\" error={errors.summaryTemplate}>\n <Input value={cfg.summaryTemplate} onChange={(e) => edit({ summaryTemplate: (e.target as HTMLInputElement).value })} />\n </Field>\n <div><Button disabled={!draft || busy} onClick={() => void save()}>Save availability</Button></div>\n </Panel>\n </AdminPage>\n );\n}\n\n/** Options for {@link availabilitySection}. */\nexport interface AvailabilitySectionOptions {\n id?: string;\n label?: string;\n}\n\n/** Build the Availability admin section: the booking-rules editor over\n * `GET/PUT /api/admin/scheduling`, with field-keyed validation surfaced inline. */\nexport function availabilitySection(options: AvailabilitySectionOptions = {}): AdminSection {\n const { id = \"availability\", label = \"Availability\" } = options;\n return { id, label, render: (ctx) => <AvailabilityBody ctx={ctx} /> };\n}\n","// Token-bound access to the /api/admin/* routes for the console sections. Every\n// section fetches with the signed-in admin's bearer token (from ChapterAdmin's\n// getToken) — the worker gates each route with verifyUser + isAdmin, so the UI\n// carries no privilege of its own.\nimport { useCallback, useEffect, useState } from \"react\";\n\n/** Fetch a JSON `/api/admin/*` route with the admin bearer token. Throws on a\n * non-2xx (the body's `error`, else the status). */\nexport async function adminFetch<T = unknown>(\n getToken: () => Promise<string | null>,\n path: string,\n init?: RequestInit,\n): Promise<T> {\n const token = await getToken();\n const headers = new Headers(init?.headers);\n if (token) headers.set(\"authorization\", `Bearer ${token}`);\n if (init?.body) headers.set(\"content-type\", \"application/json\");\n const res = await fetch(path, { ...init, headers });\n const body = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n if (!res.ok) throw new Error(typeof body.error === \"string\" ? body.error : `request failed (${res.status})`);\n return body as T;\n}\n\n/** The state of one admin resource load. */\nexport interface AdminResource<T> {\n data: T | null;\n loading: boolean;\n error: string | null;\n /** Re-fetch (e.g. after a mutation). */\n refresh: () => void;\n}\n\n/** Load a `/api/admin/*` GET route into React state, re-fetching on `refresh()`\n * or when `path` changes. */\nexport function useAdminResource<T = unknown>(getToken: () => Promise<string | null>, path: string): AdminResource<T> {\n const [data, setData] = useState<T | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [nonce, setNonce] = useState(0);\n\n useEffect(() => {\n let live = true;\n setLoading(true);\n setError(null);\n adminFetch<T>(getToken, path)\n .then((d) => live && setData(d))\n .catch((e: unknown) => live && setError(e instanceof Error ? e.message : String(e)))\n .finally(() => live && setLoading(false));\n return () => {\n live = false;\n };\n }, [getToken, path, nonce]);\n\n const refresh = useCallback(() => setNonce((n) => n + 1), []);\n return { data, loading, error, refresh };\n}\n","// Billing section: applications joined with live Stripe subscription state from\n// GET /api/admin/billing, rendered with odla-ui StatBand + DataTable. Degrades to\n// a note when billingReady:false, and surfaces the route's `truncated` flag.\nimport { DataTable, StatBand } from \"@odla-ai/ui/components\";\nimport type { DataTableColumn, StatCell } from \"@odla-ai/ui/components\";\nimport { useAdminResource } from \"./admin-api.js\";\nimport { AdminPage, AdminNote, Panel } from \"./admin-layout.js\";\nimport type { AdminSection, AdminSectionContext } from \"./chrome.js\";\n\ninterface BillingRow {\n id: string;\n name: string;\n email: string;\n applicationStatus: string;\n subscriptionStatus: string | null;\n cancelAtPeriodEnd: boolean;\n amountCents: number;\n interval: string;\n renewalAt: number | null;\n}\ninterface BillingData {\n billingReady: boolean;\n testMode?: boolean;\n truncated?: boolean;\n rows: BillingRow[];\n summary: { activeCount: number; annualizedCents: number; renewingSoonCount: number; pastDueCount: number; canceledCount: number; refundedCount: number } | null;\n}\n\nconst money = (cents: number): string => `$${(cents / 100).toLocaleString()}`;\nconst date = (t: number | null): string => (t ? new Date(t).toLocaleDateString([], { dateStyle: \"medium\" }) : \"—\");\n\nconst COLUMNS: readonly DataTableColumn<BillingRow>[] = [\n { key: \"name\", header: \"Name\", cell: (r) => r.name, sortAs: \"string\" },\n { key: \"email\", header: \"Email\", cell: (r) => r.email },\n { key: \"applicationStatus\", header: \"Application\", cell: (r) => r.applicationStatus },\n { key: \"subscriptionStatus\", header: \"Subscription\", cell: (r) => (r.subscriptionStatus ? `${r.subscriptionStatus}${r.cancelAtPeriodEnd ? \" · cancelling\" : \"\"}` : \"—\") },\n { key: \"amountCents\", header: \"Amount\", cell: (r) => `${money(r.amountCents)}/${r.interval === \"month\" ? \"mo\" : \"yr\"}`, sortAs: \"number\", sortValue: (r) => r.amountCents },\n { key: \"renewalAt\", header: \"Renews\", cell: (r) => date(r.renewalAt), sortAs: \"number\", sortValue: (r) => r.renewalAt ?? 0 },\n];\n\nfunction BillingBody({ ctx }: { ctx: AdminSectionContext }) {\n const { data, loading, error } = useAdminResource<BillingData>(ctx.getToken, \"/api/admin/billing\");\n if (loading) return <AdminNote>Loading…</AdminNote>;\n if (error || !data) return <AdminNote>Couldn’t load billing{error ? `: ${error}` : \"\"}.</AdminNote>;\n if (!data.billingReady) return <AdminNote>Billing isn’t configured — no Stripe key is vaulted for this group.</AdminNote>;\n\n const s = data.summary;\n const stats: StatCell[] = s\n ? [\n { value: s.activeCount, label: \"Active\" },\n { value: money(s.annualizedCents), label: \"Annualized\" },\n { value: s.renewingSoonCount, label: \"Renewing ≤60d\" },\n { value: s.pastDueCount, label: \"Past due\" },\n ]\n : [];\n\n return (\n <AdminPage>\n {s ? <StatBand stats={stats} /> : null}\n <Panel title=\"Subscriptions\" actions={data.testMode ? <span className=\"badge\">Stripe test mode</span> : undefined}>\n {data.truncated ? <p className=\"badge\">Showing the first 100 subscriptions — the list is truncated.</p> : null}\n <DataTable rows={data.rows} columns={COLUMNS} rowKey={(r) => r.id} />\n </Panel>\n </AdminPage>\n );\n}\n\n/** Options for {@link billingSection}. */\nexport interface BillingSectionOptions {\n id?: string;\n label?: string;\n}\n\n/** Build the Billing admin section over `GET /api/admin/billing`. Renders a\n * \"not configured\" note when the group has no Stripe key vaulted. */\nexport function billingSection(options: BillingSectionOptions = {}): AdminSection {\n const { id = \"billing\", label = \"Billing\" } = options;\n return { id, label, render: (ctx) => <BillingBody ctx={ctx} /> };\n}\n","// Operational overview powered by the MetricWidget and StepPipeline primitives.\nimport { MetricWidget, StepPipeline } from \"@odla-ai/ui/components\";\nimport type { MetricData, PipelineStep } from \"@odla-ai/ui/components\";\nimport { useAdminResource } from \"./admin-api.js\";\nimport { AdminPage, AdminNote, Panel } from \"./admin-layout.js\";\nimport type { AdminSection, AdminSectionContext } from \"./chrome.js\";\n\ninterface DashboardData {\n applications: { total: number; last7: number; last30: number };\n applicationsSeries: MetricData;\n pipeline: Record<string, number>;\n pipelineDelta: Record<string, number>;\n calls: { upcoming: number; needsAttention: number };\n agenda: Array<{\n id: string;\n startAt: number;\n name: string;\n email: string | null;\n drift: string;\n meetUrl: string | null;\n htmlLink?: string | null;\n }>;\n timezone: string;\n revenue: {\n billingReady: boolean;\n activeCount?: number;\n annualRunRateCents?: number;\n testMode?: boolean;\n };\n revenueSeries: MetricData | null;\n membersSeries: MetricData | null;\n}\n\nconst number = (value: number): string => Math.round(value).toLocaleString();\nconst money = (cents: number): string => `$${Math.round(cents / 100).toLocaleString()}`;\nconst when = (time: number): string =>\n new Date(time).toLocaleString([], { dateStyle: \"medium\", timeStyle: \"short\" });\n\nfunction DashboardBody({ ctx }: { ctx: AdminSectionContext }) {\n const { data, loading, error } = useAdminResource<DashboardData>(\n ctx.getToken,\n \"/api/admin/dashboard\",\n );\n if (loading) return <AdminNote>Loading dashboard…</AdminNote>;\n if (error || !data) return <AdminNote>Couldn’t load the dashboard{error ? `: ${error}` : \"\"}.</AdminNote>;\n\n const pipelineSteps: PipelineStep[] = Object.entries(data.pipeline)\n .filter(([stage]) => ![\"declined\", \"refunded\"].includes(stage))\n .map(([stage, count]) => ({\n icon: <span style={{ fontSize: 22, fontWeight: 700 }}>{count}</span>,\n title: stage.replaceAll(\"_\", \" \"),\n description: data.pipelineDelta[stage]\n ? `+${data.pipelineDelta[stage]} this week`\n : \"no change\",\n }));\n const exceptions = [\"declined\", \"refunded\"]\n .filter((stage) => stage in data.pipeline)\n .map((stage) => `${stage} ${data.pipeline[stage]}`)\n .join(\" · \");\n\n return (\n <AdminPage>\n <Panel\n title={\n <>\n Upcoming calls{\" \"}\n <span className=\"muted\" style={{ fontWeight: 400 }}>· {data.timezone}</span>\n </>\n }\n actions={\n data.calls.needsAttention\n ? <span className=\"badge\">{data.calls.needsAttention} need attention</span>\n : undefined\n }\n >\n {data.agenda.length === 0 ? (\n <p className=\"muted\" style={{ margin: 0 }}>No upcoming calls.</p>\n ) : (\n <ul style={{ listStyle: \"none\", margin: 0, padding: 0, display: \"grid\", gap: 10 }}>\n {data.agenda.map((meeting) => (\n <li key={meeting.id} style={{ display: \"flex\", alignItems: \"center\", gap: 12, flexWrap: \"wrap\" }}>\n <strong style={{ minWidth: 170 }}>{when(meeting.startAt)}</strong>\n <span style={{ flex: 1 }}>{meeting.name}{meeting.email ? ` · ${meeting.email}` : \"\"}</span>\n {meeting.drift && meeting.drift !== \"none\" ? <span className=\"badge\">drift</span> : null}\n {meeting.htmlLink ? <a href={meeting.htmlLink} target=\"_blank\" rel=\"noreferrer\">Open</a> : null}\n {meeting.meetUrl ? <a href={meeting.meetUrl} target=\"_blank\" rel=\"noreferrer\">Meet</a> : null}\n </li>\n ))}\n </ul>\n )}\n </Panel>\n\n <div style={{ display: \"grid\", gridTemplateColumns: \"repeat(auto-fit, minmax(280px, 1fr))\", gap: 18 }}>\n <MetricWidget label=\"Applications\" data={data.applicationsSeries} format={number} />\n {data.membersSeries ? (\n <MetricWidget label=\"New members\" data={data.membersSeries} format={number} />\n ) : (\n <Panel title=\"New members\"><p className=\"muted\">Appears once billing is connected.</p></Panel>\n )}\n </div>\n\n {data.revenueSeries && data.revenue.billingReady ? (\n <div>\n <MetricWidget\n label=\"Revenue · annual run rate added\"\n data={data.revenueSeries}\n format={money}\n size=\"large\"\n />\n <p className=\"muted\">\n Active memberships: {data.revenue.activeCount ?? 0} · Annual run rate:{\" \"}\n {money(data.revenue.annualRunRateCents ?? 0)}\n {data.revenue.testMode ? \" · test mode\" : \"\"}\n </p>\n </div>\n ) : (\n <Panel title=\"Revenue\"><p className=\"muted\">Appears once billing is connected.</p></Panel>\n )}\n\n <Panel title=\"Pipeline\">\n <StepPipeline ariaLabel=\"Membership pipeline\" steps={pipelineSteps} />\n {exceptions ? <p className=\"muted\" style={{ margin: 0 }}>{exceptions}</p> : null}\n </Panel>\n </AdminPage>\n );\n}\n\n/** Labels and ids for a composed dashboard workspace entry. */\nexport interface DashboardSectionOptions {\n id?: string;\n label?: string;\n}\n\n/** Build the operational dashboard workspace over `/api/admin/dashboard`. */\nexport function dashboardSection(options: DashboardSectionOptions = {}): AdminSection {\n const { id = \"dashboard\", label = \"Dashboard\" } = options;\n return { id, label, render: (ctx) => <DashboardBody ctx={ctx} /> };\n}\n","// Email section: the owner-editable email config (templates + addresses) from\n// GET/PUT /api/admin/group/email, the send audit from GET /api/admin/email/log,\n// and a POST /api/admin/email/test button. Built from odla-ui form primitives.\nimport { useState } from \"react\";\nimport { Button, Checkbox, DataTable, Field, Input, Textarea } from \"@odla-ai/ui/components\";\nimport type { DataTableColumn } from \"@odla-ai/ui/components\";\nimport { adminFetch, useAdminResource } from \"./admin-api.js\";\nimport { AdminPage, AdminNote, Panel } from \"./admin-layout.js\";\nimport type { AdminSection, AdminSectionContext } from \"./chrome.js\";\n\ninterface Template { subject: string; text: string; enabled: boolean }\ninterface EmailConfig {\n emailTemplates: Record<string, Template>;\n replyTo: string;\n notificationEmail: string;\n debugEmail: string;\n commitmentText: string;\n normsText: string;\n transport: string;\n fromEmail: string | null;\n envName: string;\n}\ninterface LogRow { id: string; template: string; to: string; subject: string; transport: string; redirected: boolean; error: string | null; sentAt: number }\n\nconst LOG_COLUMNS: readonly DataTableColumn<LogRow>[] = [\n { key: \"sentAt\", header: \"Sent\", cell: (r) => new Date(r.sentAt).toLocaleString(), sortAs: \"number\", sortValue: (r) => r.sentAt },\n { key: \"template\", header: \"Template\", cell: (r) => r.template },\n { key: \"to\", header: \"To\", cell: (r) => r.to },\n { key: \"status\", header: \"Status\", cell: (r) => (r.error ? <span className=\"badge\">failed</span> : r.redirected ? <span className=\"badge\">redirected</span> : \"delivered\") },\n];\n\nfunction EmailBody({ ctx }: { ctx: AdminSectionContext }) {\n const cfg = useAdminResource<EmailConfig>(ctx.getToken, \"/api/admin/group/email\");\n const log = useAdminResource<{ sends: LogRow[] }>(ctx.getToken, \"/api/admin/email/log\");\n const [draft, setDraft] = useState<EmailConfig | null>(null);\n const [busy, setBusy] = useState<string | null>(null);\n const [note, setNote] = useState<string | null>(null);\n\n const data = draft ?? cfg.data;\n if (cfg.loading) return <AdminNote>Loading…</AdminNote>;\n if (cfg.error || !data) return <AdminNote>Couldn’t load email config{cfg.error ? `: ${cfg.error}` : \"\"}.</AdminNote>;\n\n const edit = (patch: Partial<EmailConfig>) => setDraft({ ...data, ...patch });\n const editTemplate = (key: string, patch: Partial<Template>) =>\n edit({ emailTemplates: { ...data.emailTemplates, [key]: { ...data.emailTemplates[key], ...patch } as Template } });\n\n const run = async (key: string, fn: () => Promise<void>) => {\n setBusy(key);\n setNote(null);\n try {\n await fn();\n } catch (e) {\n setNote(e instanceof Error ? e.message : String(e));\n } finally {\n setBusy(null);\n }\n };\n const save = () =>\n run(\"save\", async () => {\n await adminFetch(ctx.getToken, \"/api/admin/group/email\", { method: \"PUT\", body: JSON.stringify(data) });\n setDraft(null);\n cfg.refresh();\n setNote(\"Saved.\");\n });\n const test = (template: string) =>\n run(`test:${template}`, async () => {\n const r = await adminFetch<{ ok: boolean; to: string; redirected: boolean }>(ctx.getToken, \"/api/admin/email/test\", { method: \"POST\", body: JSON.stringify({ template }) });\n setNote(r.ok ? `Sent ${template} to ${r.to}${r.redirected ? \" (dev-redirected)\" : \"\"}.` : \"Test send did not deliver.\");\n log.refresh();\n });\n\n return (\n <AdminPage>\n <Panel\n title=\"Delivery\"\n actions={<span className=\"muted\">{data.envName} · {data.transport}{data.fromEmail ? ` · ${data.fromEmail}` : \"\"}</span>}\n >\n <Field label=\"Notification address\"><Input value={data.notificationEmail} onChange={(e) => edit({ notificationEmail: (e.target as HTMLInputElement).value })} /></Field>\n <Field label=\"Reply-to\"><Input value={data.replyTo} onChange={(e) => edit({ replyTo: (e.target as HTMLInputElement).value })} /></Field>\n <Field label=\"Debug inbox\" hint=\"Non-prod sends redirect here.\"><Input value={data.debugEmail} onChange={(e) => edit({ debugEmail: (e.target as HTMLInputElement).value })} /></Field>\n </Panel>\n\n {Object.entries(data.emailTemplates).map(([key, t]) => (\n <Panel key={key} title={key} actions={<Button variant=\"secondary\" mini disabled={busy === `test:${key}`} onClick={() => void test(key)}>Send test</Button>}>\n <Checkbox label=\"Enabled\" checked={t.enabled} onChange={(e) => editTemplate(key, { enabled: (e.target as HTMLInputElement).checked })} />\n <Field label=\"Subject\"><Input value={t.subject} onChange={(e) => editTemplate(key, { subject: (e.target as HTMLInputElement).value })} /></Field>\n <Field label=\"Body\"><Textarea prose rows={5} value={t.text} onChange={(e) => editTemplate(key, { text: (e.target as HTMLTextAreaElement).value })} /></Field>\n </Panel>\n ))}\n\n <div style={{ display: \"flex\", gap: 12, alignItems: \"center\" }}>\n <Button disabled={!draft || busy === \"save\"} onClick={() => void save()}>Save changes</Button>\n {note ? <span className=\"muted\">{note}</span> : null}\n </div>\n\n <Panel title=\"Send log\">\n <DataTable rows={log.data?.sends ?? []} columns={LOG_COLUMNS} rowKey={(r) => r.id} />\n </Panel>\n </AdminPage>\n );\n}\n\n/** Options for {@link emailSection}. */\nexport interface EmailSectionOptions {\n id?: string;\n label?: string;\n}\n\n/** Build the Email admin section: template + address editor over\n * `GET/PUT /api/admin/group/email`, the send log, and per-template test sends. */\nexport function emailSection(options: EmailSectionOptions = {}): AdminSection {\n const { id = \"email\", label = \"Email\" } = options;\n return { id, label, render: (ctx) => <EmailBody ctx={ctx} /> };\n}\n","// Config-driven CRM workspace with record-local operational tabs.\nimport { BillingCard } from \"@odla-ai/crm/ui\";\nimport {\n CrmWorkspace,\n type CrmWorkspaceRecordContext,\n type RecordPanelTab,\n} from \"@odla-ai/crm/ui\";\nimport type { Crm, CrmClient } from \"@odla-ai/crm\";\nimport type { AdminSection, AdminSectionContext } from \"./chrome.js\";\nimport { RecordActions } from \"./admin-record-actions.js\";\nimport { NetworkShareActions } from \"./admin-network.js\";\nimport { RecordActivityPanel } from \"./admin-record-activity.js\";\nimport { RecordCommsHistory, RecordCommsPanel } from \"./admin-record-comms.js\";\nimport { RecordSchedulingPanel } from \"./admin-record-scheduling.js\";\nimport { AdminPage } from \"./admin-layout.js\";\n\nconst DEFAULT_ROLES = [\"provisional\", \"member\", \"admin\"] as const;\n\nfunction PeopleBody(props: {\n crm: Crm;\n client: CrmClient;\n type: string;\n ctx: AdminSectionContext;\n roles: readonly string[];\n lifecycle: boolean;\n networkSharing: boolean;\n extendRecordTabs?: (\n tabs: readonly RecordPanelTab[],\n context: CrmWorkspaceRecordContext,\n ) => readonly RecordPanelTab[];\n}) {\n const { crm, client, type, ctx, roles, lifecycle, networkSharing, extendRecordTabs } = props;\n const def = crm.type(type);\n const recordId = ctx.route?.recordId ?? null;\n // The crm UI entry's bundled declaration repeats CrmClient's private field;\n // both imports are the same runtime class but TypeScript treats them nominally.\n const workspaceClient = client as unknown as Parameters<typeof CrmWorkspace>[0][\"client\"];\n return (\n <AdminPage>\n <CrmWorkspace\n crm={crm}\n client={workspaceClient}\n type={type}\n recordId={recordId}\n detailTab={ctx.route?.detailTab}\n defaultDetailTab=\"profile\"\n onRecordIdChange={(id) => ctx.navigate({ recordId: id, detailTab: null })}\n hrefForDetailTab={(detailTab) => ctx.href({ detailTab })}\n extendRecordTabs={(base, context): readonly RecordPanelTab[] => {\n const record = context.detail.record;\n const applicationId =\n typeof record.fields?.applicationId === \"string\"\n ? String(record.fields.applicationId)\n : null;\n const byId = new Map(base.map((tab) => [tab.id, tab]));\n const tabs: RecordPanelTab[] = [];\n const add = (id: string) => {\n const tab = byId.get(id);\n if (tab) tabs.push(tab);\n };\n add(\"stage\");\n add(\"profile\");\n if (def.facets?.email !== false) {\n tabs.push({\n id: \"comms\",\n label: \"Comms\",\n panel: <RecordCommsPanel client={client} recordId={record.id} getToken={ctx.getToken} />,\n });\n tabs.push({\n id: \"history\",\n label: \"Comms history\",\n panel: <RecordCommsHistory client={client} recordId={record.id} />,\n });\n }\n if (lifecycle) {\n tabs.push({\n id: \"scheduling\",\n label: \"Scheduling\",\n panel: <RecordSchedulingPanel getToken={ctx.getToken} applicationId={applicationId} />,\n });\n tabs.push({ id: \"billing\", label: \"Billing\", panel: <BillingCard record={record} /> });\n } else {\n add(\"billing\");\n }\n tabs.push({\n id: \"notes\",\n label: \"Notes\",\n panel: <RecordActivityPanel client={client} recordId={record.id} />,\n });\n add(\"connections\");\n if (lifecycle) {\n tabs.push({\n id: \"access\",\n label: \"Access\",\n panel: (\n <RecordActions\n getToken={ctx.getToken}\n record={record}\n roles={roles}\n onChanged={() => {\n context.refreshRecord();\n context.refreshList();\n }}\n />\n ),\n });\n }\n if (networkSharing) {\n tabs.push({\n id: \"sharing\",\n label: \"Sharing\",\n panel: <NetworkShareActions recordId={record.id} recordType={record.type} getToken={ctx.getToken} />,\n });\n }\n return extendRecordTabs?.(tabs, context) ?? tabs;\n }}\n />\n </AdminPage>\n );\n}\n\n/** Configuration for the person-collection compatibility preset. */\nexport interface PeopleSectionOptions {\n crm: Crm;\n id?: string;\n label?: string;\n type?: string;\n}\n\n/** Configuration for one CRM collection and its application-specific tabs. */\nexport interface CollectionSectionOptions {\n crm: Crm;\n type: string;\n id?: string;\n label?: string;\n lifecycle?: boolean;\n roles?: readonly string[];\n networkSharing?: boolean;\n extendRecordTabs?: (\n tabs: readonly RecordPanelTab[],\n context: CrmWorkspaceRecordContext,\n ) => readonly RecordPanelTab[];\n}\n\n/** Build one CRM collection as an admin workspace. */\nexport function collectionSection(options: CollectionSectionOptions): AdminSection {\n const { crm, type } = options;\n let fallbackLabel = type;\n try {\n fallbackLabel = crm.type(type).labelPlural ?? crm.type(type).label ?? type;\n } catch {\n // The route will surface an unknown configured type.\n }\n const {\n id = type,\n label = fallbackLabel,\n lifecycle = type === \"person\",\n roles = DEFAULT_ROLES,\n networkSharing = false,\n extendRecordTabs,\n } = options;\n return {\n id,\n label,\n render: (ctx) => (\n <PeopleBody\n crm={crm}\n client={ctx.client}\n type={type}\n ctx={ctx}\n roles={roles}\n lifecycle={lifecycle}\n networkSharing={networkSharing}\n extendRecordTabs={extendRecordTabs}\n />\n ),\n };\n}\n\n/** Person-collection preset. */\nexport function peopleSection(options: PeopleSectionOptions & {\n roles?: readonly string[];\n networkSharing?: boolean;\n extendRecordTabs?: CollectionSectionOptions[\"extendRecordTabs\"];\n}): AdminSection {\n const {\n crm,\n id = \"people\",\n label = \"People\",\n type = \"person\",\n roles,\n networkSharing,\n extendRecordTabs,\n } = options;\n return collectionSection({\n crm,\n type,\n id,\n label,\n ...(roles ? { roles } : {}),\n ...(networkSharing != null ? { networkSharing } : {}),\n ...(extendRecordTabs ? { extendRecordTabs } : {}),\n });\n}\n","// The lifecycle action panel shown beside an open person record: role change\n// (POST /api/admin/people/role), approve (POST /api/admin/applications/:id/\n// approve) and refund (POST .../refund). Each control appears only when the\n// record carries what it needs — a linked Clerk account for role, an\n// applicationId for approve/refund. Built from odla-ui Field/Select/Button.\nimport { useEffect, useState } from \"react\";\nimport { Button, Field, Select } from \"@odla-ai/ui/components\";\nimport { adminFetch } from \"./admin-api.js\";\nimport type { CrmRecord } from \"@odla-ai/crm\";\n\ninterface Access {\n role: string;\n superAdmin: boolean;\n}\n\n/** Props for {@link RecordActions}. */\nexport interface RecordActionsProps {\n getToken: () => Promise<string | null>;\n record: CrmRecord;\n /** The role ladder offered by the role selector. Default provisional→admin. */\n roles: readonly string[];\n /** Called after any action mutates state, so the caller can refresh. */\n onChanged: () => void;\n}\n\n/** The role/approve/refund controls for one person record. Renders only the\n * actions the record supports. */\nexport function RecordActions({ getToken, record, roles, onChanged }: RecordActionsProps) {\n const userId = typeof record.clerkUserId === \"string\" ? record.clerkUserId : null;\n const applicationId = typeof record.fields?.applicationId === \"string\" ? (record.fields.applicationId as string) : null;\n const [access, setAccess] = useState<Access | null>(null);\n const [busy, setBusy] = useState<string | null>(null);\n const [note, setNote] = useState<string | null>(null);\n\n useEffect(() => {\n if (!userId) {\n setAccess(null);\n return;\n }\n let live = true;\n adminFetch<Access>(getToken, `/api/admin/people/access?userId=${encodeURIComponent(userId)}`)\n .then((a) => live && setAccess(a))\n .catch(() => live && setAccess(null));\n return () => {\n live = false;\n };\n }, [getToken, userId]);\n\n const act = async (key: string, run: () => Promise<unknown>, ok: string) => {\n setBusy(key);\n setNote(null);\n try {\n await run();\n setNote(ok);\n onChanged();\n } catch (e) {\n setNote(e instanceof Error ? e.message : String(e));\n } finally {\n setBusy(null);\n }\n };\n const setRole = (role: string) =>\n act(\"role\", () => adminFetch(getToken, \"/api/admin/people/role\", { method: \"POST\", body: JSON.stringify({ userId, role }) }), `Role set to ${role}.`);\n const approve = () =>\n act(\"approve\", () => adminFetch(getToken, `/api/admin/applications/${applicationId}/approve`, { method: \"POST\" }), \"Approved.\");\n const refund = () =>\n act(\"refund\", () => adminFetch(getToken, `/api/admin/applications/${applicationId}/refund`, { method: \"POST\" }), \"Refund issued.\");\n\n if (!userId && !applicationId) return null;\n return (\n <section className=\"panel\" style={{ display: \"flex\", flexDirection: \"column\", gap: 14, marginTop: 16 }}>\n <h3 style={{ margin: 0, fontSize: 16 }}>Access & lifecycle</h3>\n {userId ? (\n <Field label=\"Role\" hint={access?.superAdmin ? \"Super-admin — managed in odla Studio.\" : undefined}>\n <Select\n value={access?.role ?? \"\"}\n disabled={busy === \"role\" || access?.superAdmin}\n options={roles.map((r) => ({ value: r, label: r }))}\n onChange={(e) => void setRole((e.target as HTMLSelectElement).value)}\n />\n </Field>\n ) : (\n <p className=\"muted\" style={{ margin: 0 }}>No linked account yet — role is set once they sign in.</p>\n )}\n {applicationId ? (\n <div style={{ display: \"flex\", gap: 8 }}>\n <Button variant=\"secondary\" mini disabled={busy === \"approve\"} onClick={() => void approve()}>Approve</Button>\n <Button variant=\"danger\" mini disabled={busy === \"refund\"} onClick={() => void refund()}>Refund</Button>\n </div>\n ) : null}\n {note ? <p className=\"muted\" style={{ margin: 0 }}>{note}</p> : null}\n </section>\n );\n}\n","// Leader-side \"share to follower\" action. It is intentionally record-local:\n// the operator opens the person/business/deal they already reviewed, chooses a\n// configured follower, and sees an explicit delivery result.\nimport { useState } from \"react\";\nimport { adminFetch, useAdminResource } from \"./admin-api.js\";\n\ninterface Target {\n id: string;\n name: string;\n url: string;\n types: string[];\n}\n\ninterface TargetResponse {\n targets: Target[];\n}\n\ninterface PushResponse {\n ok: boolean;\n results: Array<{ id: string; name: string; ok: boolean; error?: string }>;\n}\n\n/** Props for {@link NetworkShareActions}. */\nexport interface NetworkShareActionsProps {\n recordId: string;\n recordType: string;\n getToken: () => Promise<string | null>;\n}\n\n/** Render follower delivery buttons when this chapter configured network\n * targets. Targets with an explicit type allowlist hide incompatible records. */\nexport function NetworkShareActions(props: NetworkShareActionsProps) {\n const { recordId, recordType, getToken } = props;\n const targets = useAdminResource<TargetResponse>(getToken, \"/api/admin/network/targets\");\n const [busy, setBusy] = useState<string | null>(null);\n const [message, setMessage] = useState<string | null>(null);\n const compatible = (targets.data?.targets ?? []).filter((target) => target.types.includes(recordType));\n\n if (targets.loading || targets.error || compatible.length === 0) return null;\n\n const push = async (target: Target) => {\n setBusy(target.id);\n setMessage(null);\n try {\n const result = await adminFetch<PushResponse>(getToken, \"/api/admin/network/push\", {\n method: \"POST\",\n body: JSON.stringify({ recordId, targetIds: [target.id] }),\n });\n const delivery = result.results[0];\n setMessage(delivery?.ok ? `Shared with ${target.name}.` : delivery?.error ?? `Could not share with ${target.name}.`);\n } catch (err) {\n setMessage(err instanceof Error ? err.message : \"Delivery failed.\");\n } finally {\n setBusy(null);\n }\n };\n\n return (\n <section className=\"panel\" style={{ marginTop: 14, display: \"flex\", flexDirection: \"column\", gap: 10 }}>\n <div>\n <h3 style={{ margin: 0, fontSize: 16 }}>Share to a follower</h3>\n <p className=\"muted\" style={{ margin: \"4px 0 0\", fontSize: 13 }}>\n Sends the target's allowlisted fields. Its pipeline and account state remain local.\n </p>\n </div>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 8 }}>\n {compatible.map((target) => (\n <button className=\"btn secondary mini\" disabled={busy !== null} onClick={() => void push(target)} key={target.id}>\n {busy === target.id ? \"Sharing…\" : `Share with ${target.name}`}\n </button>\n ))}\n </div>\n {message ? <p role=\"status\" style={{ margin: 0, fontSize: 13 }}>{message}</p> : null}\n </section>\n );\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { ActivityFeed } from \"@odla-ai/crm/ui\";\nimport type { CrmActivity, CrmClient } from \"@odla-ai/crm\";\n\n/** Notes and follow-ups for one CRM record. */\nexport function RecordActivityPanel(props: {\n client: CrmClient;\n recordId: string;\n}) {\n const { client, recordId } = props;\n const [activities, setActivities] = useState<CrmActivity[]>([]);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const load = useCallback(async () => {\n try {\n const result = await client.listActivities(recordId, { limit: 100 });\n setActivities(result.activities);\n setError(null);\n } catch (failure) {\n setError(failure instanceof Error ? failure.message : String(failure));\n }\n }, [client, recordId]);\n useEffect(() => void load(), [load]);\n const run = async (action: () => Promise<unknown>) => {\n setBusy(true);\n try {\n await action();\n await load();\n } finally {\n setBusy(false);\n }\n };\n if (error) return <p role=\"alert\" className=\"muted\">{error}</p>;\n return (\n <ActivityFeed\n activities={activities}\n busy={busy}\n onAddNote={(body) => void run(() => client.addActivity(recordId, { kind: \"note\", body }))}\n onAddTask={(task) => void run(() => client.addActivity(recordId, { kind: \"task\", ...task }))}\n onToggleTask={(activity, done) =>\n void run(() => client.updateTask(activity.id, { status: done ? \"done\" : \"open\" }))}\n />\n );\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { Button, Field, Select } from \"@odla-ai/ui/components\";\nimport type { CrmClient } from \"@odla-ai/crm\";\nimport { useAdminResource } from \"./admin-api.js\";\n\ninterface EmailConfig {\n emailTemplates: Record<string, { enabled: boolean; subject: string }>;\n}\n\n/** Template send action for one record. */\nexport function RecordCommsPanel(props: {\n client: CrmClient;\n recordId: string;\n getToken: () => Promise<string | null>;\n}) {\n const { client, recordId, getToken } = props;\n const config = useAdminResource<EmailConfig>(getToken, \"/api/admin/group/email\");\n const templates = Object.entries(config.data?.emailTemplates ?? {}).filter(([, value]) => value.enabled);\n const [template, setTemplate] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [note, setNote] = useState<string | null>(null);\n const send = async () => {\n if (!template) return;\n setBusy(true);\n setNote(null);\n try {\n const result = await client.sendEmail(recordId, { templateId: template });\n setNote(result.sent ? \"Message sent.\" : result.reason ?? \"Message was not sent.\");\n } catch (failure) {\n setNote(failure instanceof Error ? failure.message : String(failure));\n } finally {\n setBusy(false);\n }\n };\n if (config.loading) return <p className=\"muted\">Loading templates…</p>;\n if (config.error) return <p role=\"alert\" className=\"muted\">{config.error}</p>;\n return (\n <div style={{ display: \"grid\", gap: 14, maxWidth: 560 }}>\n <Field label=\"Template\">\n <Select\n value={template}\n onChange={(event) => setTemplate(event.currentTarget.value)}\n options={[\n { value: \"\", label: \"Choose a template…\" },\n ...templates.map(([id, value]) => ({ value: id, label: value.subject || id })),\n ]}\n />\n </Field>\n <div><Button disabled={!template || busy} onClick={() => void send()}>{busy ? \"Sending…\" : \"Send\"}</Button></div>\n {note ? <p role=\"status\" className=\"muted\">{note}</p> : null}\n </div>\n );\n}\n\n/** Audited send history for one record. */\nexport function RecordCommsHistory(props: { client: CrmClient; recordId: string }) {\n const { client, recordId } = props;\n const [rows, setRows] = useState<Record<string, unknown>[]>([]);\n const [error, setError] = useState<string | null>(null);\n const load = useCallback(async () => {\n try {\n const result = await client.emailLog({ recordId, limit: 100 });\n setRows(result.log);\n setError(null);\n } catch (failure) {\n setError(failure instanceof Error ? failure.message : String(failure));\n }\n }, [client, recordId]);\n useEffect(() => void load(), [load]);\n if (error) return <p role=\"alert\" className=\"muted\">{error}</p>;\n if (rows.length === 0) return <p className=\"muted\">No messages recorded.</p>;\n return (\n <ul style={{ listStyle: \"none\", padding: 0, margin: 0, display: \"grid\", gap: 10 }}>\n {rows.map((row, index) => (\n <li className=\"panel\" key={String(row[\"id\"] ?? index)}>\n <strong>{String(row[\"templateId\"] ?? row[\"template\"] ?? \"Message\")}</strong>\n <div className=\"muted\">\n {row[\"to\"] ? String(row[\"to\"]) : \"\"}\n {row[\"sentAt\"] ? ` · ${new Date(Number(row[\"sentAt\"])).toLocaleString()}` : \"\"}\n </div>\n </li>\n ))}\n </ul>\n );\n}\n","import { useState } from \"react\";\nimport { Button } from \"@odla-ai/ui/components\";\nimport { adminFetch, useAdminResource } from \"./admin-api.js\";\n\ninterface Meeting {\n id: string;\n applicationId: string;\n startAt: number;\n status: string;\n meetUrl?: string | null;\n htmlLink?: string | null;\n}\n\n/** Meetings and reschedule/cancel actions for one application-backed record. */\nexport function RecordSchedulingPanel(props: {\n getToken: () => Promise<string | null>;\n applicationId: string | null;\n}) {\n const { getToken, applicationId } = props;\n const resource = useAdminResource<{ meetings: Meeting[]; timezone: string }>(\n getToken,\n \"/api/admin/meetings?all=1\",\n );\n const [busy, setBusy] = useState<string | null>(null);\n const [note, setNote] = useState<string | null>(null);\n const meetings = (resource.data?.meetings ?? []).filter((meeting) => meeting.applicationId === applicationId);\n const run = async (meeting: Meeting, action: \"cancel\" | \"reschedule\") => {\n let body: string | undefined;\n if (action === \"reschedule\") {\n const input = globalThis.prompt?.(\"New start time:\");\n if (!input) return;\n const startAt = Date.parse(input);\n if (!Number.isFinite(startAt)) {\n setNote(\"Couldn’t parse that time.\");\n return;\n }\n body = JSON.stringify({ startAt });\n } else if (!globalThis.confirm?.(\"Cancel this call?\")) {\n return;\n }\n setBusy(meeting.id);\n try {\n await adminFetch(getToken, `/api/admin/meetings/${meeting.id}/${action}`, { method: \"POST\", body });\n resource.refresh();\n setNote(action === \"cancel\" ? \"Call cancelled.\" : \"Call rescheduled.\");\n } catch (failure) {\n setNote(failure instanceof Error ? failure.message : String(failure));\n } finally {\n setBusy(null);\n }\n };\n if (!applicationId) return <p className=\"muted\">No application is linked to this record.</p>;\n if (resource.loading) return <p className=\"muted\">Loading meetings…</p>;\n if (resource.error) return <p role=\"alert\" className=\"muted\">{resource.error}</p>;\n if (meetings.length === 0) return <p className=\"muted\">No meetings recorded.</p>;\n return (\n <div style={{ display: \"grid\", gap: 12 }}>\n {meetings.map((meeting) => (\n <section className=\"panel\" key={meeting.id}>\n <strong>{new Date(meeting.startAt).toLocaleString()}</strong>\n <p className=\"muted\">{meeting.status} · {resource.data?.timezone}</p>\n <div style={{ display: \"flex\", gap: 8, flexWrap: \"wrap\" }}>\n {meeting.meetUrl ? <a href={meeting.meetUrl} target=\"_blank\" rel=\"noreferrer\">Join meeting</a> : null}\n {meeting.htmlLink ? <a href={meeting.htmlLink} target=\"_blank\" rel=\"noreferrer\">Open calendar</a> : null}\n {meeting.status === \"scheduled\" ? (\n <>\n <Button variant=\"secondary\" mini disabled={busy === meeting.id} onClick={() => void run(meeting, \"reschedule\")}>Reschedule</Button>\n <Button variant=\"danger\" mini disabled={busy === meeting.id} onClick={() => void run(meeting, \"cancel\")}>Cancel</Button>\n </>\n ) : null}\n </div>\n </section>\n ))}\n {note ? <p role=\"status\" className=\"muted\">{note}</p> : null}\n </div>\n );\n}\n","// Compatibility entry for the workspace-based default console.\nimport type { Chapter } from \"../types\";\nimport type { AdminSection } from \"./chrome.js\";\nimport { defaultAdminWorkspaces } from \"./admin-workspaces.js\";\n\n/** Legacy default catalog. @deprecated Use defaultAdminWorkspaces. */\nexport function defaultAdminSections(chapter: Chapter): AdminSection[] {\n return defaultAdminWorkspaces(chapter);\n}\n\nexport { defaultAdminWorkspaces };\n","// Meetings section: the reconciled agenda from GET /api/admin/meetings, with the\n// reschedule and cancel actions wired to POST /api/admin/meetings/:id/{...}.\n// Built from odla-ui .panel + Button; drift against live Google state is flagged.\nimport { useState } from \"react\";\nimport { Button } from \"@odla-ai/ui/components\";\nimport { adminFetch, useAdminResource } from \"./admin-api.js\";\nimport { AdminPage, AdminNote, Panel } from \"./admin-layout.js\";\nimport type { AdminSection, AdminSectionContext } from \"./chrome.js\";\n\ninterface MeetingRow {\n id: string;\n startAt: number;\n endAt: number;\n status: string;\n drift: string;\n meetUrl: string | null;\n applicant: { name: string; email: string; status: string } | null;\n}\n\nconst when = (t: number): string => new Date(t).toLocaleString([], { dateStyle: \"medium\", timeStyle: \"short\" });\n\nfunction MeetingsBody({ ctx }: { ctx: AdminSectionContext }) {\n const { data, loading, error, refresh } = useAdminResource<{ meetings: MeetingRow[]; timezone: string }>(ctx.getToken, \"/api/admin/meetings?all=1\");\n const [busy, setBusy] = useState<string | null>(null);\n const [note, setNote] = useState<string | null>(null);\n if (loading) return <AdminNote>Loading…</AdminNote>;\n if (error || !data) return <AdminNote>Couldn’t load meetings{error ? `: ${error}` : \"\"}.</AdminNote>;\n\n const run = async (id: string, fn: () => Promise<void>) => {\n setBusy(id);\n setNote(null);\n try {\n await fn();\n refresh();\n } catch (e) {\n setNote(e instanceof Error ? e.message : String(e));\n } finally {\n setBusy(null);\n }\n };\n const cancel = (id: string) => {\n if (!globalThis.confirm?.(\"Cancel this call? Google notifies the attendee.\")) return;\n void run(id, () => adminFetch(ctx.getToken, `/api/admin/meetings/${id}/cancel`, { method: \"POST\" }));\n };\n const reschedule = (id: string) => {\n const input = globalThis.prompt?.(\"New start time (e.g. 2026-08-01 14:00):\");\n if (!input) return;\n const startAt = Date.parse(input);\n if (!Number.isFinite(startAt)) {\n setNote(\"Couldn’t parse that time.\");\n return;\n }\n void run(id, () => adminFetch(ctx.getToken, `/api/admin/meetings/${id}/reschedule`, { method: \"POST\", body: JSON.stringify({ startAt }) }));\n };\n\n return (\n <AdminPage>\n <Panel title={<>Agenda <span className=\"muted\" style={{ fontWeight: 400 }}>· {data.timezone}</span></>} actions={note ? <span className=\"muted\">{note}</span> : undefined}>\n {data.meetings.length === 0 ? (\n <p className=\"muted\" style={{ margin: 0 }}>No meetings.</p>\n ) : (\n <ul style={{ listStyle: \"none\", margin: 0, padding: 0, display: \"flex\", flexDirection: \"column\", gap: 12 }}>\n {data.meetings.map((m) => (\n <li key={m.id} style={{ display: \"flex\", alignItems: \"center\", gap: 12, flexWrap: \"wrap\", opacity: m.status === \"cancelled\" ? 0.55 : 1 }}>\n <strong style={{ minWidth: 170 }}>{when(m.startAt)}</strong>\n <span style={{ flex: 1 }}>{m.applicant ? `${m.applicant.name} · ${m.applicant.email}` : \"(unknown)\"}</span>\n <span className=\"badge\">{m.status}</span>\n {m.drift && m.drift !== \"none\" ? <span className=\"badge\">drift: {m.drift}</span> : null}\n {m.meetUrl ? <a href={m.meetUrl} target=\"_blank\" rel=\"noreferrer\">Meet</a> : null}\n {m.status === \"scheduled\" ? (\n <>\n <Button variant=\"secondary\" mini disabled={busy === m.id} onClick={() => reschedule(m.id)}>Reschedule</Button>\n <Button variant=\"danger\" mini disabled={busy === m.id} onClick={() => cancel(m.id)}>Cancel</Button>\n </>\n ) : null}\n </li>\n ))}\n </ul>\n )}\n </Panel>\n </AdminPage>\n );\n}\n\n/** Options for {@link meetingsSection}. */\nexport interface MeetingsSectionOptions {\n id?: string;\n label?: string;\n}\n\n/** Build the Meetings admin section: the reconciled agenda over\n * `GET /api/admin/meetings`, with reschedule/cancel actions. */\nexport function meetingsSection(options: MeetingsSectionOptions = {}): AdminSection {\n const { id = \"meetings\", label = \"Meetings\" } = options;\n return { id, label, render: (ctx) => <MeetingsBody ctx={ctx} /> };\n}\n"],"mappings":"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","names":["useEffect","useState","useEffect","useState","jsx","jsxs","jsx","jsxs","useState","useEffect","jsxs","jsx","Tabs","useState","useCallback","useEffect","useState","jsx","jsxs","useState","jsx","jsxs","Fragment","jsx","jsxs","money","useState","Button","Checkbox","DataTable","Field","Input","jsx","jsxs","useState","Field","Input","Button","Checkbox","DataTable","useEffect","useState","Button","Field","jsx","jsxs","useState","useEffect","Field","Button","useState","jsx","jsxs","useState","useCallback","useEffect","useState","jsx","useCallback","useEffect","useState","Button","Field","Select","jsx","jsxs","useState","Field","Select","Button","useCallback","useEffect","useState","Button","Fragment","jsx","jsxs","useState","Button","jsx","jsx","Tabs","jsx","jsxs","useState","useEffect","useState","Button","Fragment","jsx","jsxs","when","useState","Button"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ui/slot-picker.tsx","../src/ui/datetime.ts","../src/ui/members.tsx","../src/ui/reschedule.tsx","../src/ui/join.tsx","../src/ui/payment-step.tsx"],"sourcesContent":["// SlotPicker — a pure presentational day-chips + time-grid picker, shared by the\n// join booking step and the member-area reschedule. Ported from the proven\n// reference Preact island to React; behaviour and DOM shape are unchanged.\n//\n// It holds only the active-day UI state; slot data, selection, and booking are\n// the caller's (the picker is `onPick`-driven). `classes` lets the composing\n// island supply its own CSS contract (join styles `slot-*`, reschedule\n// `msched-*`); the defaults work standalone against those class names.\nimport { useMemo, useState } from \"react\";\nimport { dayLabel, groupSlotsByDay, timeLabel } from \"./datetime.js\";\nimport type { Slot } from \"./datetime.js\";\n\n/** CSS class names for the four picker parts — overridable so one component\n * serves several differently-styled surfaces. */\nexport interface SlotPickerClasses {\n days: string;\n day: string;\n times: string;\n time: string;\n}\n\nconst DEFAULT_CLASSES: SlotPickerClasses = {\n days: \"slot-days\",\n day: \"slot-day\",\n times: \"slot-grid\",\n time: \"slot-time\",\n};\n\n/** Props for {@link SlotPicker}. Generic over the slot type so a caller's richer\n * slot object survives through `onPick`. */\nexport interface SlotPickerProps<T extends Slot = Slot> {\n /** Bookable slots, ideally already chronological. */\n slots: readonly T[];\n /** The group's scheduling timezone; all labels render in it. */\n timezone: string;\n /** The currently-selected slot's start, for the pressed state. */\n selectedStartAt?: number;\n /** Called with the full slot object when a time is chosen. */\n onPick: (slot: T) => void;\n /** Called when the active day changes (callers clear their selection). */\n onDayChange?: () => void;\n classes?: SlotPickerClasses;\n}\n\n/** A day-chips + time-grid slot picker. Presentational and `onPick`-driven: it\n * owns only the active-day selection; the caller owns slot data, the chosen\n * slot, and booking. Shared by the join booking step and the member reschedule. */\nexport function SlotPicker<T extends Slot = Slot>(props: SlotPickerProps<T>) {\n const { slots, timezone, selectedStartAt, onPick, onDayChange, classes = DEFAULT_CLASSES } = props;\n const byDay = useMemo(() => groupSlotsByDay(slots, timezone), [slots, timezone]);\n const dayKeys = [...byDay.keys()];\n const [activeDay, setActiveDay] = useState<string | undefined>(dayKeys[0]);\n\n // Keep the active day valid if the slot set changed under us (e.g. a reload\n // after a 409): fall back to the first available day.\n const day = activeDay !== undefined && byDay.has(activeDay) ? activeDay : dayKeys[0];\n const times = (day !== undefined ? byDay.get(day) : undefined) ?? [];\n\n return (\n <>\n <div className={classes.days}>\n {dayKeys.map((key) => {\n const first = byDay.get(key)?.[0];\n return (\n <button\n key={key}\n type=\"button\"\n className={classes.day}\n aria-pressed={key === day}\n onClick={() => {\n setActiveDay(key);\n onDayChange?.();\n }}\n >\n {first ? dayLabel(first.startAt, timezone) : key}\n </button>\n );\n })}\n </div>\n <div className={classes.times}>\n {times.map((s) => (\n <button\n key={s.startAt}\n type=\"button\"\n className={classes.time}\n aria-pressed={selectedStartAt === s.startAt}\n onClick={() => onPick(s)}\n >\n {timeLabel(s.startAt, timezone)}\n </button>\n ))}\n </div>\n </>\n );\n}\n","// Date/timezone formatting for the chapter member islands (join booking, member\n// area). Ported from proven production helpers. Every time renders in the\n// group's SCHEDULING timezone with an explicit abbreviation — never the viewer's\n// unlabeled local zone — so an applicant always sees the time the chapter meant.\n// Pure and framework-free, so it is unit-testable without a DOM.\n\n/** A bookable slot: a start instant in epoch milliseconds. */\nexport interface Slot {\n startAt: number;\n}\n\n/** The timezone's short abbreviation (e.g. \"PST\"); falls back to the id if the\n * runtime can't resolve it. */\nexport function tzShort(tz: string): string {\n try {\n const parts = new Intl.DateTimeFormat(undefined, { timeZone: tz, timeZoneName: \"short\" }).formatToParts(\n new Date(),\n );\n return parts.find((p) => p.type === \"timeZoneName\")?.value ?? tz;\n } catch {\n return tz;\n }\n}\n\n/** DST-safe day bucket key (ISO date in the target zone). Groups slots by the\n * calendar day a viewer in `tz` would see, not by UTC midnight. */\nexport function dayKey(ms: number, tz: string): string {\n return new Date(ms).toLocaleDateString(\"en-CA\", { timeZone: tz });\n}\n\n/** Short day label for a day chip, e.g. \"Mon, Jun 3\". */\nexport function dayLabel(ms: number, tz: string): string {\n return new Date(ms).toLocaleDateString(undefined, { timeZone: tz, weekday: \"short\", month: \"short\", day: \"numeric\" });\n}\n\n/** Time-of-day label for a slot button, e.g. \"2:30 PM\". */\nexport function timeLabel(ms: number, tz: string): string {\n return new Date(ms).toLocaleTimeString(undefined, { timeZone: tz, hour: \"numeric\", minute: \"2-digit\" });\n}\n\n/** Full, human confirmation label, e.g. \"Monday, June 3, 2:30 PM PST\". */\nexport function fullLabel(ms: number, tz: string): string {\n return new Date(ms).toLocaleString(undefined, {\n timeZone: tz,\n weekday: \"long\",\n month: \"long\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n timeZoneName: \"short\",\n });\n}\n\n/** Currency label from integer cents, e.g. 100000 → \"$1,000\". */\nexport function fmtMoney(cents: number): string {\n return \"$\" + Math.round(cents / 100).toLocaleString();\n}\n\n/** Short date label, e.g. \"Jun 3, 2026\" (used for renewal/refund copy). */\nexport function fmtDate(ms: number): string {\n return new Date(ms).toLocaleDateString(undefined, { month: \"short\", day: \"numeric\", year: \"numeric\" });\n}\n\n/** Bucket slots into an insertion-ordered `Map<dayKey, Slot[]>` for the picker.\n * Input order is preserved within each day, so a server that returns slots\n * chronologically yields chronological chips + times. */\nexport function groupSlotsByDay<T extends Slot>(slots: readonly T[], tz: string): Map<string, T[]> {\n const byDay = new Map<string, T[]>();\n for (const s of slots) {\n const k = dayKey(s.startAt, tz);\n const bucket = byDay.get(k);\n if (bucket) bucket.push(s);\n else byDay.set(k, [s]);\n }\n return byDay;\n}\n","// The member area island. Reads GET /api/me (role + the member's own\n// application, folded server-side) and renders the account header plus, for a\n// provisional member, their application card with book/reschedule; a full member\n// sees the caller-supplied `memberContent`. Ported from the reference members island to\n// React, driven by the injected `api` (no Clerk SDK dependency).\nimport { useEffect, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { Rescheduler } from \"./reschedule.js\";\nimport { fmtDate, fullLabel } from \"./datetime.js\";\nimport type { ApiFn } from \"./api.js\";\nimport type { MemberApplication } from \"../session.js\";\n\ninterface Me {\n email: string | null;\n role: string;\n application: MemberApplication | null;\n}\n\n/** Props for {@link MembersArea}. */\nexport interface MembersAreaProps {\n api: ApiFn;\n /** Sign the member out (the host owns Clerk's signOut). */\n signOut: () => void;\n /** Where the \"Admin console\" link points for admins. Default \"/admin/\". */\n adminHref?: string;\n /** Where an accountless member goes to apply. Default \"/join.html\". */\n applyHref?: string;\n /** What a full (non-provisional) member sees below the account header. */\n memberContent?: ReactNode;\n}\n\nfunction card(kicker: string, body: ReactNode): ReactNode {\n return (\n <div className=\"card\">\n <div className=\"card-label\">Your Application</div>\n <div className=\"meeting-block\">\n <div className=\"meeting-kicker\">{kicker}</div>\n {body}\n </div>\n </div>\n );\n}\n\nfunction ProvisionalCard(props: {\n api: ApiFn;\n application: MemberApplication | null;\n applyHref: string;\n onReschedule: () => void | Promise<void>;\n}): ReactNode {\n const { api, application, applyHref, onReschedule } = props;\n if (!application) {\n return card(\n \"One step remains\",\n <>\n <div className=\"meeting-note\">Your account is ready, and the application that completes it takes a few minutes.</div>\n <a className=\"apply-link\" href={applyHref}>\n Apply for membership\n </a>\n </>,\n );\n }\n if (application.status === \"refunded\") {\n return card(\"Membership refunded\", <div className=\"meeting-note\">Your fee has been refunded in full and your membership is canceled.</div>);\n }\n const membership = application.paid ? (\n <div className=\"meeting-note\">Your membership is active{application.renewalAt ? ` and renews ${fmtDate(application.renewalAt)}` : \"\"}.</div>\n ) : null;\n if (application.meetingAt) {\n return card(\n \"Your introduction call\",\n <>\n <div className=\"meeting-date\">{fullLabel(application.meetingAt, application.timezone)}</div>\n <div className=\"meeting-note\">A calendar invitation with the video call link is in your email.</div>\n {application.meetUrl ? (\n <div className=\"meeting-note\">\n <a href={application.meetUrl} target=\"_blank\" rel=\"noopener\">\n Join the video call\n </a>\n </div>\n ) : null}\n <Rescheduler api={api} applicationId={application.id} timezone={application.timezone} onRescheduled={onReschedule} />\n {membership}\n </>,\n );\n }\n return card(\n \"Book your introduction call\",\n <>\n <div className=\"meeting-note\">Your application is in. Choose a time below, and a calendar invitation will reach your email.</div>\n <Rescheduler api={api} applicationId={application.id} timezone={application.timezone} onRescheduled={onReschedule} label=\"Choose a time\" />\n {membership}\n </>,\n );\n}\n\n/** The signed-in member area. Loads /api/me on mount and renders the account\n * header plus the provisional application card or the full-member content. */\nexport function MembersArea(props: MembersAreaProps) {\n const { api, signOut, adminHref = \"/admin/\", applyHref = \"/join.html\", memberContent } = props;\n const [me, setMe] = useState<Me | null>(null);\n const [error, setError] = useState(false);\n\n const reload = async () => {\n try {\n setMe(await api<Me>(\"/api/me\"));\n } catch {\n setError(true);\n }\n };\n useEffect(() => {\n void reload();\n }, []);\n\n if (error) return <p className=\"meeting-note\">Sign in is briefly unavailable. Please refresh.</p>;\n if (!me) return <p className=\"meeting-note\">Loading…</p>;\n const role = me.role || \"provisional\";\n\n return (\n <>\n <div className=\"card\">\n <div className=\"member-row\">\n <span className=\"member-email\">{me.email}</span>\n <span className={\"role-badge \" + role}>{role}</span>\n </div>\n <div className=\"account-actions\">\n <button className=\"btn secondary mini\" onClick={signOut}>\n Sign out\n </button>\n {role === \"admin\" ? (\n <a className=\"admin-console-link\" href={adminHref}>\n Admin console\n </a>\n ) : null}\n </div>\n </div>\n {role === \"provisional\" ? (\n <ProvisionalCard api={api} application={me.application} applyHref={applyHref} onReschedule={reload} />\n ) : (\n (memberContent ?? (\n <div className=\"card\">\n <div className=\"card-label\">Welcome back.</div>\n </div>\n ))\n )}\n </>\n );\n}\n","// In-place reschedule: open a SlotPicker, rebook via /api/schedule/book (the same\n// capability the join flow uses; the application id is the credential). Ported\n// from the reference member-area Rescheduler to React, driven by the injected `api`.\nimport { useState } from \"react\";\nimport { SlotPicker } from \"./slot-picker.js\";\nimport type { Slot } from \"./datetime.js\";\nimport type { ApiFn } from \"./api.js\";\n\ninterface SlotsResponse {\n schedulingReady?: boolean;\n slots?: Slot[];\n timezone?: string;\n}\n\n/** Props for {@link Rescheduler}. */\nexport interface RescheduleProps {\n api: ApiFn;\n applicationId: string;\n timezone: string;\n /** Called after a successful (re)booking so the caller can refresh /api/me. */\n onRescheduled: () => void | Promise<void>;\n /** Link text to open the picker (e.g. \"Choose a time\" for a first booking). */\n label?: string;\n}\n\n/** A collapsed \"change your time\" link that expands into a {@link SlotPicker} and\n * rebooks on pick. Degrades to a message when scheduling is unavailable. */\nexport function Rescheduler(props: RescheduleProps) {\n const { api, applicationId, timezone, onRescheduled, label = \"Change your time\" } = props;\n const [open, setOpen] = useState(false);\n const [slots, setSlots] = useState<Slot[] | null>(null);\n const [tz, setTz] = useState(timezone);\n const [busy, setBusy] = useState(false);\n const [msg, setMsg] = useState<string | null>(null);\n\n const start = async () => {\n setOpen(true);\n setSlots(null);\n setMsg(null);\n try {\n const r = await api<SlotsResponse>(\"/api/schedule/slots\");\n if (r.schedulingReady === false) {\n setSlots([]);\n setMsg(\"Scheduling is briefly unavailable. We'll reach out by email to arrange your call.\");\n return;\n }\n setSlots(r.slots ?? []);\n if (r.timezone) setTz(r.timezone);\n } catch {\n setSlots([]);\n setMsg(\"Times are briefly unavailable. Please try again.\");\n }\n };\n\n const pick = async (slot: Slot) => {\n setBusy(true);\n setMsg(null);\n try {\n await api(\"/api/schedule/book\", { method: \"POST\", body: JSON.stringify({ applicationId, startAt: slot.startAt }) });\n setOpen(false);\n await onRescheduled();\n } catch (e) {\n setMsg(e instanceof Error ? e.message : \"That time is no longer available. Please pick another.\");\n } finally {\n setBusy(false);\n }\n };\n\n if (!open) {\n return (\n <p className=\"meeting-note\">\n <a\n href=\"#\"\n onClick={(e) => {\n e.preventDefault();\n void start();\n }}\n >\n {label}\n </a>\n </p>\n );\n }\n return (\n <div className=\"msched\">\n {slots === null ? (\n <p className=\"meeting-note\">Loading available times…</p>\n ) : slots.length === 0 ? (\n <p className=\"meeting-note\">{msg ?? \"No open times right now. Please check back soon.\"}</p>\n ) : (\n <SlotPicker\n slots={slots}\n timezone={tz}\n classes={{ days: \"msched-days\", day: \"msched-day\", times: \"msched-times\", time: \"msched-time\" }}\n onPick={(s) => void pick(s)}\n />\n )}\n {busy ? <p className=\"meeting-note\">Rescheduling…</p> : null}\n {msg && slots && slots.length > 0 ? <p className=\"meeting-note error\">{msg}</p> : null}\n <p className=\"meeting-note\">\n <a\n href=\"#\"\n onClick={(e) => {\n e.preventDefault();\n setOpen(false);\n }}\n >\n Keep my current time\n </a>\n </p>\n </div>\n );\n}\n","// The join island — the signup flow orchestrator. The SITE provides the form\n// fields (as children); this owns the flow: submit → /api/applications →\n// (paymentsReady) the Stripe PaymentStep → (schedulingReady) the SlotPicker\n// booking → confirmation. Faithful to the reference join flow, but the flow +\n// payment + booking are packaged instead of hand-rolled per site.\nimport { useEffect, useState } from \"react\";\nimport type { FormEvent, ReactNode } from \"react\";\nimport { SlotPicker } from \"./slot-picker.js\";\nimport { PaymentStep } from \"./payment-step.js\";\nimport { fullLabel } from \"./datetime.js\";\nimport type { Slot } from \"./datetime.js\";\n\n/** The public join config (the shape `GET /api/join-config` returns). */\nexport interface JoinConfig {\n id: string;\n name: string;\n paymentsReady: boolean;\n refundPolicyText?: string;\n}\n\n/** Props for {@link JoinIsland}. */\nexport interface JoinIslandProps {\n config: JoinConfig;\n /** The site's application form fields — inputs with `name` attributes; their\n * values are collected via FormData and posted to /api/applications. */\n children: ReactNode;\n /** Where the confirmation links after booking. Default \"/members/\". */\n membersHref?: string;\n}\n\ntype Step = \"form\" | \"pay\" | \"book\" | \"done\";\n\ninterface SlotsResponse {\n schedulingReady?: boolean;\n slots?: Slot[];\n timezone?: string;\n}\n\nfunction JoinBooking(props: { applicationId: string; onBooked: (b: { startAt: number; timezone: string }) => void }): ReactNode {\n const { applicationId, onBooked } = props;\n const [state, setState] = useState<{ slots: Slot[]; timezone: string } | null>(null);\n const [msg, setMsg] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n const [selected, setSelected] = useState<Slot | null>(null);\n\n const load = async () => {\n setMsg(null);\n try {\n const res = await fetch(\"/api/schedule/slots\");\n const data = (await res.json()) as SlotsResponse;\n if (data.schedulingReady === false || !data.slots?.length) {\n setState(null);\n setMsg(\"Scheduling is briefly unavailable — we'll reach out by email to arrange your call.\");\n return;\n }\n setState({ slots: data.slots, timezone: data.timezone ?? \"UTC\" });\n } catch {\n setMsg(\"Times are briefly unavailable. Please try again.\");\n }\n };\n useEffect(() => {\n void load();\n }, []);\n\n const book = async () => {\n if (!selected) return;\n setBusy(true);\n setMsg(null);\n try {\n const res = await fetch(\"/api/schedule/book\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ applicationId, startAt: selected.startAt }),\n });\n const data = (await res.json()) as { startAt?: number; error?: string; code?: string };\n if (res.status === 409 && data.code === \"calendar_slot_unavailable\") {\n setSelected(null);\n setMsg(\"That time was just taken. Here are the current openings.\");\n await load();\n return;\n }\n if (!res.ok) throw new Error(data.error ?? \"The booking could not be completed.\");\n onBooked({ startAt: data.startAt ?? selected.startAt, timezone: state?.timezone ?? \"UTC\" });\n } catch (e) {\n setMsg(e instanceof Error ? e.message : \"The booking could not be completed.\");\n } finally {\n setBusy(false);\n }\n };\n\n if (!state) return <p className=\"slots-status\">{msg ?? \"Loading available times…\"}</p>;\n return (\n <div className=\"join-book\">\n <SlotPicker\n slots={state.slots}\n timezone={state.timezone}\n selectedStartAt={selected?.startAt}\n onPick={setSelected}\n onDayChange={() => setSelected(null)}\n />\n <div className=\"slot-confirm\" hidden={!selected}>\n <button className=\"submit-btn\" disabled={busy} onClick={() => void book()}>\n {busy ? \"Booking…\" : \"Book this time\"}\n </button>\n {msg ? <p className=\"step2-note\">{msg}</p> : null}\n </div>\n </div>\n );\n}\n\n/** The signup island. Renders the site's form, then drives payment (when the\n * chapter charges) and booking (when a calendar is connected) to confirmation. */\nexport function JoinIsland(props: JoinIslandProps) {\n const { config, children, membersHref = \"/members/\" } = props;\n const [step, setStep] = useState<Step>(\"form\");\n const [applicationId, setApplicationId] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [submitting, setSubmitting] = useState(false);\n const [booked, setBooked] = useState<{ startAt: number; timezone: string } | null>(null);\n\n const submit = async (e: FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n setSubmitting(true);\n setError(null);\n try {\n const fields: Record<string, unknown> = {};\n for (const [k, v] of new FormData(e.currentTarget).entries()) fields[k] = v;\n fields.submissionId = crypto.randomUUID();\n const res = await fetch(\"/api/applications\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(fields),\n });\n const data = (await res.json()) as { id?: string; error?: string };\n if (!res.ok || !data.id) throw new Error(data.error ?? \"Your application could not be submitted.\");\n setApplicationId(data.id);\n setStep(config.paymentsReady ? \"pay\" : \"book\");\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Something went wrong. Please try again.\");\n } finally {\n setSubmitting(false);\n }\n };\n\n if (step === \"done\" && booked) {\n return (\n <div className=\"join-done card\">\n <div className=\"card-label\">You're booked</div>\n <p className=\"meeting-date\">{fullLabel(booked.startAt, booked.timezone)}</p>\n <p className=\"meeting-note\">A calendar invitation with the video call link is on its way to your email.</p>\n <a className=\"apply-link\" href={membersHref}>\n Go to your member area\n </a>\n </div>\n );\n }\n if (step === \"book\" && applicationId) {\n return (\n <JoinBooking\n applicationId={applicationId}\n onBooked={(b) => {\n setBooked(b);\n setStep(\"done\");\n }}\n />\n );\n }\n if (step === \"pay\" && applicationId) {\n return <PaymentStep applicationId={applicationId} refundPolicyText={config.refundPolicyText ?? \"\"} onPaid={() => setStep(\"book\")} />;\n }\n return (\n <form className=\"join-form\" onSubmit={(e) => void submit(e)}>\n {children}\n {error ? <p className=\"join-error\">{error}</p> : null}\n <button className=\"submit-btn\" type=\"submit\" disabled={submitting}>\n {submitting ? \"Submitting…\" : \"Submit application\"}\n </button>\n </form>\n );\n}\n","// The join flow's payment step. Ports the reference card entry into the island:\n// dynamically loads js.stripe.com (NO @stripe/react-stripe-js dep), creates a\n// subscription server-side, and mounts a Stripe Payment Element. The refund-policy\n// checkbox is the gate — checking it starts the (money-creating) subscription\n// call. Client success is advisory only; the webhook is the\n// authoritative writer of paid state (see payments.ts).\nimport { useRef, useState } from \"react\";\n\n// Minimal shapes for the dynamically-loaded js.stripe.com global.\ninterface StripeElementsApi {\n create(type: string): { mount(target: HTMLElement): void };\n}\ninterface StripeApi {\n elements(opts: { clientSecret: string }): StripeElementsApi;\n confirmPayment(opts: {\n elements: StripeElementsApi;\n confirmParams?: { return_url?: string };\n redirect?: \"if_required\";\n }): Promise<{ error?: { message?: string }; paymentIntent?: { status?: string } }>;\n}\ntype StripeFactory = (publishableKey: string) => StripeApi;\n\nlet loader: Promise<StripeFactory> | null = null;\n\n/** Load js.stripe.com once and resolve the `Stripe` global (browser only). */\nfunction loadStripe(): Promise<StripeFactory> {\n const existing = (globalThis as { Stripe?: StripeFactory }).Stripe;\n if (existing) return Promise.resolve(existing);\n if (!loader) {\n loader = new Promise<StripeFactory>((resolve, reject) => {\n const s = document.createElement(\"script\");\n s.src = \"https://js.stripe.com/v3/\";\n s.onload = () => {\n const fn = (globalThis as { Stripe?: StripeFactory }).Stripe;\n if (fn) resolve(fn);\n else reject(new Error(\"stripe.js unavailable\"));\n };\n s.onerror = () => reject(new Error(\"stripe.js failed to load\"));\n document.head.appendChild(s);\n });\n }\n return loader;\n}\n\n/** Props for {@link PaymentStep}. */\nexport interface PaymentStepProps {\n /** The application to attach the subscription to (the capability). */\n applicationId: string;\n /** Refund-policy copy the applicant must acknowledge to start payment. */\n refundPolicyText: string;\n /** Called once the payment succeeds (or is processing) — advance to booking. */\n onPaid: () => void;\n}\n\ninterface SubResponse {\n clientSecret?: string;\n publishableKey?: string | null;\n}\n\n/** The card-entry step: acknowledge the refund policy → create the subscription\n * → mount Stripe Elements → confirm. */\nexport function PaymentStep(props: PaymentStepProps) {\n const { applicationId, refundPolicyText, onPaid } = props;\n const [status, setStatus] = useState<\"idle\" | \"loading\" | \"ready\" | \"confirming\">(\"idle\");\n const [error, setError] = useState<string | null>(null);\n const mountRef = useRef<HTMLDivElement | null>(null);\n const stripeRef = useRef<StripeApi | null>(null);\n const elementsRef = useRef<StripeElementsApi | null>(null);\n\n const begin = async () => {\n setStatus(\"loading\");\n setError(null);\n try {\n const res = await fetch(\"/api/payments/subscription\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ applicationId, refundPolicyAck: true }),\n });\n const data = (await res.json()) as SubResponse;\n if (!res.ok || !data.clientSecret || !data.publishableKey) throw new Error(\"Payment could not be set up. Please try again.\");\n const stripe = (await loadStripe())(data.publishableKey);\n const elements = stripe.elements({ clientSecret: data.clientSecret });\n const element = elements.create(\"payment\");\n if (mountRef.current) element.mount(mountRef.current);\n stripeRef.current = stripe;\n elementsRef.current = elements;\n setStatus(\"ready\");\n } catch (e) {\n setStatus(\"idle\");\n setError(e instanceof Error ? e.message : \"Payment could not be set up. Please try again.\");\n }\n };\n\n const pay = async () => {\n const stripe = stripeRef.current;\n const elements = elementsRef.current;\n if (!stripe || !elements) return;\n setStatus(\"confirming\");\n setError(null);\n const returnUrl =\n typeof window !== \"undefined\" ? `${window.location.origin}${window.location.pathname}?redirect_status=succeeded` : undefined;\n const result = await stripe.confirmPayment({ elements, confirmParams: { return_url: returnUrl }, redirect: \"if_required\" });\n if (result.error) {\n setError(result.error.message ?? \"The payment could not be completed.\");\n setStatus(\"ready\");\n return;\n }\n const paid = result.paymentIntent?.status;\n if (paid === \"succeeded\" || paid === \"processing\") onPaid();\n else {\n setError(\"The payment did not complete. Please try again.\");\n setStatus(\"ready\");\n }\n };\n\n return (\n <div className=\"join-pay\">\n <label className=\"compliance-box\">\n <input\n type=\"checkbox\"\n disabled={status !== \"idle\"}\n onChange={(e) => {\n if (e.currentTarget.checked) void begin();\n }}\n />\n <span>{refundPolicyText}</span>\n </label>\n {status === \"loading\" ? <p className=\"pay-status\">Preparing secure payment…</p> : null}\n <div ref={mountRef} hidden={status === \"idle\" || status === \"loading\"} />\n {status === \"ready\" || status === \"confirming\" ? (\n <button className=\"submit-btn\" disabled={status === \"confirming\"} onClick={() => void pay()}>\n {status === \"confirming\" ? \"Processing…\" : \"Pay and continue\"}\n </button>\n ) : null}\n {error ? <p className=\"pay-error\">{error}</p> : null}\n </div>\n );\n}\n"],"mappings":"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","names":["useState","useState","jsx","jsxs","useState","Fragment","jsx","jsxs","useState","useEffect","useState","useState","jsx","jsxs","jsx","jsxs","useState","useEffect"]}
|
package/dist/index.cjs
CHANGED
|
@@ -47,6 +47,7 @@ __export(index_exports, {
|
|
|
47
47
|
createChapterIntegration: () => createChapterIntegration,
|
|
48
48
|
createClerkInvitation: () => createClerkInvitation,
|
|
49
49
|
createClerkUser: () => createClerkUser,
|
|
50
|
+
dashboardMetricData: () => dashboardMetricData,
|
|
50
51
|
defaultCrm: () => defaultCrm,
|
|
51
52
|
defineChapter: () => defineChapter,
|
|
52
53
|
emailGroupFrom: () => emailGroupFrom,
|
|
@@ -1215,6 +1216,31 @@ function bucketSeries(points, now, weeks = 12) {
|
|
|
1215
1216
|
}
|
|
1216
1217
|
return buckets;
|
|
1217
1218
|
}
|
|
1219
|
+
function periodSeries(points, now, count, periodMs) {
|
|
1220
|
+
const start = now - count * periodMs;
|
|
1221
|
+
const previousStart = start - count * periodMs;
|
|
1222
|
+
const current = Array.from({ length: count }, () => 0);
|
|
1223
|
+
const previous = Array.from({ length: count }, () => 0);
|
|
1224
|
+
for (const point of points) {
|
|
1225
|
+
if (!Number.isFinite(point.t) || !Number.isFinite(point.v)) continue;
|
|
1226
|
+
if (point.t >= start && point.t <= now) {
|
|
1227
|
+
const index = Math.min(count - 1, Math.floor((point.t - start) / periodMs));
|
|
1228
|
+
current[index] = (current[index] ?? 0) + point.v;
|
|
1229
|
+
} else if (point.t >= previousStart && point.t < start) {
|
|
1230
|
+
const index = Math.min(count - 1, Math.floor((point.t - previousStart) / periodMs));
|
|
1231
|
+
previous[index] = (previous[index] ?? 0) + point.v;
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
const labels = current.map((_, index) => new Date(start + index * periodMs).toISOString().slice(5, 10));
|
|
1235
|
+
return { labels, current, previous };
|
|
1236
|
+
}
|
|
1237
|
+
function dashboardMetricData(points, now) {
|
|
1238
|
+
const DAY = 864e5;
|
|
1239
|
+
return {
|
|
1240
|
+
wow: periodSeries(points, now, 7, DAY),
|
|
1241
|
+
mom: periodSeries(points, now, 4, 7 * DAY)
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1218
1244
|
function subAnnualCents(sub) {
|
|
1219
1245
|
const items = sub.items?.data ?? [];
|
|
1220
1246
|
let cents = 0;
|
|
@@ -1471,15 +1497,44 @@ function paletteDecls(palette) {
|
|
|
1471
1497
|
}
|
|
1472
1498
|
return decls;
|
|
1473
1499
|
}
|
|
1474
|
-
|
|
1500
|
+
var TOKEN_VARS = {
|
|
1501
|
+
background: "--ui-bg",
|
|
1502
|
+
surface: "--ui-surface",
|
|
1503
|
+
surface2: "--ui-surface-2",
|
|
1504
|
+
text: "--ui-text",
|
|
1505
|
+
textMuted: "--ui-text-muted",
|
|
1506
|
+
textFaint: "--ui-text-faint",
|
|
1507
|
+
border: "--ui-border",
|
|
1508
|
+
borderStrong: "--ui-border-strong",
|
|
1509
|
+
accent: "--ui-accent",
|
|
1510
|
+
accentStrong: "--ui-accent-strong",
|
|
1511
|
+
accentSoft: "--ui-accent-soft",
|
|
1512
|
+
onAccent: "--ui-on-accent",
|
|
1513
|
+
good: "--ui-good",
|
|
1514
|
+
warn: "--ui-warn",
|
|
1515
|
+
danger: "--ui-danger",
|
|
1516
|
+
chart1: "--ui-chart-1",
|
|
1517
|
+
chart2: "--ui-chart-2",
|
|
1518
|
+
chartPositive: "--ui-chart-pos",
|
|
1519
|
+
chartNegative: "--ui-chart-neg"
|
|
1520
|
+
};
|
|
1521
|
+
function semanticDecls(tokens) {
|
|
1522
|
+
return Object.entries(tokens ?? {}).flatMap(
|
|
1523
|
+
([key, value]) => typeof value === "string" && value.trim() ? [`${TOKEN_VARS[key]}: ${cleanValue(value)};`] : []
|
|
1524
|
+
);
|
|
1525
|
+
}
|
|
1526
|
+
function brandTokens(brand, options = {}) {
|
|
1475
1527
|
if (!brand) return "";
|
|
1476
|
-
const light = paletteDecls(brand.palette);
|
|
1528
|
+
const light = [...paletteDecls(brand.palette), ...semanticDecls(brand.tokens)];
|
|
1477
1529
|
const fonts = brand.fonts;
|
|
1478
1530
|
if (fonts?.display) light.push(`--ui-font-display: ${cleanValue(fonts.display)};`);
|
|
1479
1531
|
if (fonts?.body) light.push(`--ui-font-sans: ${cleanValue(fonts.body)};`);
|
|
1480
1532
|
if (fonts?.numeral) light.push(`--ui-font-numeral: ${cleanValue(fonts.numeral)};`);
|
|
1481
|
-
const dark = paletteDecls(brand.paletteDark);
|
|
1482
|
-
|
|
1533
|
+
const dark = [...paletteDecls(brand.paletteDark), ...semanticDecls(brand.tokensDark)];
|
|
1534
|
+
const selector = options.selector ?? ":root";
|
|
1535
|
+
const darkSelector = selector === ":root" ? ':root[data-theme="dark"]' : `${selector}[data-theme="dark"]`;
|
|
1536
|
+
const systemSelector = selector === ":root" ? ':root:not([data-theme="light"])' : `${selector}:not([data-theme="light"])`;
|
|
1537
|
+
let css = light.length ? `${selector} {
|
|
1483
1538
|
${light.join("\n ")}
|
|
1484
1539
|
}
|
|
1485
1540
|
` : "";
|
|
@@ -1487,9 +1542,9 @@ function brandTokens(brand) {
|
|
|
1487
1542
|
const block = `{
|
|
1488
1543
|
${dark.join("\n ")}
|
|
1489
1544
|
}`;
|
|
1490
|
-
css +=
|
|
1545
|
+
css += `${darkSelector} ${block}
|
|
1491
1546
|
@media (prefers-color-scheme: dark) {
|
|
1492
|
-
|
|
1547
|
+
${systemSelector} ${block}
|
|
1493
1548
|
}
|
|
1494
1549
|
`;
|
|
1495
1550
|
}
|