@odla-ai/chapter 0.48.3 → 0.50.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.
@@ -4,10 +4,10 @@ import {
4
4
  DEFAULT_CHAPTER_COPY,
5
5
  formatChapterCopy,
6
6
  useChapterCopy
7
- } from "./chunk-4HS2JPE2.js";
7
+ } from "./chunk-JXX4BFDP.js";
8
8
 
9
9
  // src/ui/admin.tsx
10
- import { useEffect as useEffect12, useMemo as useMemo3, useRef as useRef3, useState as useState22 } from "preact/hooks";
10
+ import { useEffect as useEffect12, useMemo as useMemo3, useRef as useRef3, useState as useState27 } from "preact/hooks";
11
11
  import { ClerkGate, SignedIn, SignedOut, SignIn, useClerkAuth } from "@odla-ai/auth-clerk";
12
12
  import { CrmClient } from "@odla-ai/crm";
13
13
 
@@ -458,7 +458,12 @@ function AdminShell({
458
458
  import { Tabs as Tabs3 } from "@odla-ai/ui/components";
459
459
 
460
460
  // src/ui/admin-billing.tsx
461
- import { DataTable, StatBand } from "@odla-ai/ui/components";
461
+ import { useState as useState5 } from "preact/hooks";
462
+ import { Button as Button2 } from "@odla-ai/ui/components";
463
+
464
+ // src/ui/payment-recovery-queue.tsx
465
+ import { useState as useState4 } from "preact/hooks";
466
+ import { Button } from "@odla-ai/ui/components";
462
467
 
463
468
  // src/ui/admin-api.ts
464
469
  import { useCallback as useCallback2, useEffect as useEffect3, useState as useState3 } from "preact/hooks";
@@ -496,36 +501,103 @@ function useAdminResource(getToken, path) {
496
501
  return { data, loading, error, refresh };
497
502
  }
498
503
 
499
- // src/ui/admin-billing.tsx
504
+ // src/ui/payment-recovery-queue.tsx
500
505
  import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
506
+ function PaymentRecoveryQueue(props) {
507
+ const network = props.scope === "network";
508
+ const path = network ? "/api/admin/network-commercial-read-model" : "/api/admin/payment-recovery";
509
+ const { data, loading, error, refresh } = useAdminResource(props.getToken, path);
510
+ const [busy, setBusy] = useState4("");
511
+ const [message, setMessage] = useState4("");
512
+ const recover = async (eventId) => {
513
+ setBusy(eventId);
514
+ setMessage("");
515
+ try {
516
+ const result = await adminFetch(props.getToken, path, {
517
+ method: "POST",
518
+ body: JSON.stringify({ eventId, ...network ? { command: "recover-event" } : {} })
519
+ });
520
+ setMessage(result.disposition?.startsWith("quarantine_") || result.matched === false ? "This event still needs its application or payment linkage repaired. Its evidence is saved for another retry." : "Stripe evidence verified and reconciliation retried.");
521
+ refresh();
522
+ } catch (cause) {
523
+ setMessage(cause instanceof Error ? cause.message : "Recovery could not finish. Please retry.");
524
+ } finally {
525
+ setBusy("");
526
+ }
527
+ };
528
+ const rows = network ? data?.exceptions ?? [] : data?.rows ?? [];
529
+ return /* @__PURE__ */ jsxs4(Panel, { title: "Payment events needing attention", children: [
530
+ loading ? /* @__PURE__ */ jsx4("p", { children: "Checking payment reconciliation\u2026" }) : error ? /* @__PURE__ */ jsxs4("p", { role: "alert", children: [
531
+ "Payment recovery is unavailable: ",
532
+ error
533
+ ] }) : /* @__PURE__ */ jsxs4(Fragment2, { children: [
534
+ rows.length ? /* @__PURE__ */ jsxs4("p", { role: "alert", children: [
535
+ rows.length,
536
+ " payment event",
537
+ rows.length === 1 ? " needs" : "s need",
538
+ " review."
539
+ ] }) : /* @__PURE__ */ jsx4("p", { children: "All loaded payment events are reconciled." }),
540
+ data?.truncated ? /* @__PURE__ */ jsx4("p", { role: "alert", children: "This queue is incomplete. Review the remaining events before declaring reconciliation complete." }) : null,
541
+ /* @__PURE__ */ jsx4("ul", { children: rows.map((row) => /* @__PURE__ */ jsxs4("li", { children: [
542
+ row.eventId ? /* @__PURE__ */ jsx4("code", { children: row.eventId }) : null,
543
+ " ",
544
+ /* @__PURE__ */ jsx4("span", { children: row.disposition ?? row.kind }),
545
+ " ",
546
+ row.eventId?.startsWith("evt_") ? /* @__PURE__ */ jsx4(Button, { mini: true, disabled: Boolean(busy), onClick: () => void recover(row.eventId), children: busy === row.eventId ? "Verifying\u2026" : "Verify with Stripe and retry" }) : /* @__PURE__ */ jsx4("span", { children: "Repair the missing payment linkage before retrying." })
547
+ ] }, `${row.eventId}:${row.kind}`)) })
548
+ ] }),
549
+ message ? /* @__PURE__ */ jsx4("p", { role: "status", children: message }) : null
550
+ ] });
551
+ }
552
+
553
+ // src/ui/admin-billing.tsx
554
+ import { DataTable, StatBand } from "@odla-ai/ui/components";
555
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
501
556
  var money = (cents) => cents === null ? "Unknown" : `$${(cents / 100).toLocaleString()}`;
502
557
  var date = (t) => t ? new Date(t).toLocaleDateString([], { dateStyle: "medium" }) : "\u2014";
503
- var columns = (copy) => [
558
+ var columns = (copy, cancel, busy) => [
504
559
  { key: "name", header: copy.name, cell: (r) => r.name, sortAs: "string" },
505
560
  { key: "email", header: copy.email, cell: (r) => r.email },
506
561
  { key: "applicationStatus", header: copy.application, cell: (r) => r.applicationStatus },
507
562
  { key: "subscriptionStatus", header: copy.subscription, cell: (r) => r.subscriptionStatus ? `${r.subscriptionStatus}${r.cancelAtPeriodEnd ? ` \xB7 ${copy.cancelling}` : ""}` : "\u2014" },
508
- { key: "amountCents", header: "Next-term forecast", cell: (r) => r.amountCents === null ? "Unknown" : /* @__PURE__ */ jsxs4("span", { children: [
509
- r.listAmountCents != null && r.listAmountCents !== r.amountCents ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
510
- /* @__PURE__ */ jsx4("s", { children: money(r.listAmountCents) }),
563
+ { key: "amountCents", header: "Next-term forecast", cell: (r) => r.amountCents === null ? "Unknown" : /* @__PURE__ */ jsxs5("span", { children: [
564
+ r.listAmountCents != null && r.listAmountCents !== r.amountCents ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
565
+ /* @__PURE__ */ jsx5("s", { children: money(r.listAmountCents) }),
511
566
  " "
512
567
  ] }) : null,
513
568
  money(r.amountCents),
514
569
  "/",
515
570
  r.interval === "month" ? "mo" : "yr"
516
571
  ] }), sortAs: "number", sortValue: (r) => r.amountCents ?? -1 },
572
+ { key: "cancelRenewal", header: "Renewal", cell: (row) => row.subscriptionStatus && ["active", "trialing", "past_due", "unpaid"].includes(row.subscriptionStatus) && !row.cancelAtPeriodEnd ? /* @__PURE__ */ jsx5(Button2, { mini: true, disabled: Boolean(busy), onClick: () => cancel(row.id), children: busy === row.id ? "Canceling\u2026" : "Cancel renewal" }) : row.cancelAtPeriodEnd ? "Ends after paid term" : "\u2014" },
517
573
  { key: "renewalAt", header: copy.renews, cell: (r) => date(r.renewalAt), sortAs: "number", sortValue: (r) => r.renewalAt ?? 0 }
518
574
  ];
519
575
  function BillingBody({ ctx }) {
520
576
  const copy = useChapterCopy().admin.billing;
521
- const { data, loading, error } = useAdminResource(ctx.getToken, "/api/admin/billing");
522
- if (loading) return /* @__PURE__ */ jsx4(AdminNote, { children: copy.loading });
523
- if (error || !data) return /* @__PURE__ */ jsxs4(AdminNote, { children: [
577
+ const [busy, setBusy] = useState5("");
578
+ const [note, setNote] = useState5("");
579
+ const { data, loading, error, refresh } = useAdminResource(ctx.getToken, "/api/admin/billing");
580
+ if (loading) return /* @__PURE__ */ jsx5(AdminNote, { children: copy.loading });
581
+ if (error || !data) return /* @__PURE__ */ jsxs5(AdminNote, { children: [
524
582
  copy.loadFailed,
525
583
  error ? `: ${error}` : "",
526
584
  "."
527
585
  ] });
528
- if (!data.billingReady) return /* @__PURE__ */ jsx4(AdminNote, { children: copy.notConfigured });
586
+ if (!data.billingReady) return /* @__PURE__ */ jsx5(AdminNote, { children: copy.notConfigured });
587
+ const cancel = async (id) => {
588
+ if (!globalThis.confirm?.("Cancel future renewals? Paid access continues through the current term. No refund will be issued.")) return;
589
+ setBusy(id);
590
+ setNote("");
591
+ try {
592
+ await adminFetch(ctx.getToken, `/api/admin/applications/${id}/cancel-renewal`, { method: "POST" });
593
+ setNote("Renewal canceled. Access continues through the paid term.");
594
+ refresh();
595
+ } catch (cause) {
596
+ setNote(cause instanceof Error ? cause.message : "Cancellation could not be confirmed. Please retry.");
597
+ } finally {
598
+ setBusy("");
599
+ }
600
+ };
529
601
  const s = data.summary;
530
602
  const stats = s ? [
531
603
  { value: s.activeCount, label: copy.active },
@@ -533,22 +605,24 @@ function BillingBody({ ctx }) {
533
605
  { value: s.renewingSoonCount, label: copy.renewingSoon },
534
606
  { value: s.pastDueCount, label: copy.pastDue }
535
607
  ] : [];
536
- return /* @__PURE__ */ jsxs4(AdminPage, { children: [
537
- s ? /* @__PURE__ */ jsx4(StatBand, { stats }) : null,
538
- /* @__PURE__ */ jsxs4(Panel, { title: copy.subscriptions, actions: data.testMode ? /* @__PURE__ */ jsx4("span", { className: "badge", children: copy.testMode }) : void 0, children: [
539
- data.truncated ? /* @__PURE__ */ jsx4("p", { className: "badge", children: copy.truncated }) : null,
540
- /* @__PURE__ */ jsx4(DataTable, { rows: data.rows, columns: columns(copy), rowKey: (r) => r.id })
608
+ return /* @__PURE__ */ jsxs5(AdminPage, { children: [
609
+ note ? /* @__PURE__ */ jsx5("p", { role: "status", children: note }) : null,
610
+ /* @__PURE__ */ jsx5(PaymentRecoveryQueue, { getToken: ctx.getToken }),
611
+ s ? /* @__PURE__ */ jsx5(StatBand, { stats }) : null,
612
+ /* @__PURE__ */ jsxs5(Panel, { title: copy.subscriptions, actions: data.testMode ? /* @__PURE__ */ jsx5("span", { className: "badge", children: copy.testMode }) : void 0, children: [
613
+ data.truncated ? /* @__PURE__ */ jsx5("p", { className: "badge", children: copy.truncated }) : null,
614
+ /* @__PURE__ */ jsx5(DataTable, { rows: data.rows, columns: columns(copy, (id) => void cancel(id), busy), rowKey: (r) => r.id })
541
615
  ] })
542
616
  ] });
543
617
  }
544
618
  function billingSection(options = {}) {
545
619
  const { id = "billing", label = "Billing" } = options;
546
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx4(BillingBody, { ctx }) };
620
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx5(BillingBody, { ctx }) };
547
621
  }
548
622
 
549
623
  // src/ui/admin-dashboard.tsx
550
624
  import { MetricWidget, StepPipeline } from "@odla-ai/ui/components";
551
- import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
625
+ import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
552
626
  var number = (value) => Math.round(value).toLocaleString();
553
627
  var money2 = (cents) => `$${Math.round(cents / 100).toLocaleString()}`;
554
628
  var when = (time) => new Date(time).toLocaleString([], { dateStyle: "medium", timeStyle: "short" });
@@ -558,50 +632,50 @@ function DashboardBody({ ctx }) {
558
632
  ctx.getToken,
559
633
  "/api/admin/dashboard"
560
634
  );
561
- if (loading) return /* @__PURE__ */ jsx5(AdminNote, { children: copy.loading });
562
- if (error || !data) return /* @__PURE__ */ jsxs5(AdminNote, { children: [
635
+ if (loading) return /* @__PURE__ */ jsx6(AdminNote, { children: copy.loading });
636
+ if (error || !data) return /* @__PURE__ */ jsxs6(AdminNote, { children: [
563
637
  copy.loadFailed,
564
638
  error ? `: ${error}` : "",
565
639
  "."
566
640
  ] });
567
641
  const pipelineSteps = Object.entries(data.pipeline).filter(([stage]) => !["declined", "refunded"].includes(stage)).map(([stage, count]) => ({
568
- icon: /* @__PURE__ */ jsx5("span", { style: { fontSize: 22, fontWeight: 700 }, children: count }),
642
+ icon: /* @__PURE__ */ jsx6("span", { style: { fontSize: 22, fontWeight: 700 }, children: count }),
569
643
  title: stage.replaceAll("_", " "),
570
644
  description: data.pipelineDelta[stage] ? formatChapterCopy(copy.thisWeek, { count: data.pipelineDelta[stage] }) : copy.noChange
571
645
  }));
572
646
  const exceptions = ["declined", "refunded"].filter((stage) => stage in data.pipeline).map((stage) => `${stage} ${data.pipeline[stage]}`).join(" \xB7 ");
573
- return /* @__PURE__ */ jsxs5(AdminPage, { children: [
574
- data.incomplete ? /* @__PURE__ */ jsx5(AdminNote, { children: "This dashboard snapshot is incomplete. Counts and trends below cover only the loaded records, not the full chapter." }) : null,
575
- /* @__PURE__ */ jsx5(
647
+ return /* @__PURE__ */ jsxs6(AdminPage, { children: [
648
+ data.incomplete ? /* @__PURE__ */ jsx6(AdminNote, { children: "This dashboard snapshot is incomplete. Counts and trends below cover only the loaded records, not the full chapter." }) : null,
649
+ /* @__PURE__ */ jsx6(
576
650
  Panel,
577
651
  {
578
- title: /* @__PURE__ */ jsxs5(Fragment3, { children: [
652
+ title: /* @__PURE__ */ jsxs6(Fragment4, { children: [
579
653
  copy.upcomingCalls,
580
654
  " ",
581
- /* @__PURE__ */ jsxs5("span", { className: "muted", style: { fontWeight: 400 }, children: [
655
+ /* @__PURE__ */ jsxs6("span", { className: "muted", style: { fontWeight: 400 }, children: [
582
656
  "\xB7 ",
583
657
  data.timezone
584
658
  ] })
585
659
  ] }),
586
- actions: data.calls.needsAttention ? /* @__PURE__ */ jsx5("span", { className: "badge", children: formatChapterCopy(copy.callsNeedAttention, { count: data.calls.needsAttention }) }) : void 0,
587
- children: data.agenda.length === 0 ? /* @__PURE__ */ jsx5("p", { className: "muted", style: { margin: 0 }, children: copy.noUpcomingCalls }) : /* @__PURE__ */ jsx5("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "grid", gap: 10 }, children: data.agenda.map((meeting) => /* @__PURE__ */ jsxs5("li", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }, children: [
588
- /* @__PURE__ */ jsx5("strong", { style: { minWidth: 170 }, children: when(meeting.startAt) }),
589
- /* @__PURE__ */ jsxs5("span", { style: { flex: 1 }, children: [
660
+ actions: data.calls.needsAttention ? /* @__PURE__ */ jsx6("span", { className: "badge", children: formatChapterCopy(copy.callsNeedAttention, { count: data.calls.needsAttention }) }) : void 0,
661
+ children: data.agenda.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "muted", style: { margin: 0 }, children: copy.noUpcomingCalls }) : /* @__PURE__ */ jsx6("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "grid", gap: 10 }, children: data.agenda.map((meeting) => /* @__PURE__ */ jsxs6("li", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }, children: [
662
+ /* @__PURE__ */ jsx6("strong", { style: { minWidth: 170 }, children: when(meeting.startAt) }),
663
+ /* @__PURE__ */ jsxs6("span", { style: { flex: 1 }, children: [
590
664
  meeting.name,
591
665
  meeting.email ? ` \xB7 ${meeting.email}` : ""
592
666
  ] }),
593
- meeting.drift && meeting.drift !== "none" ? /* @__PURE__ */ jsx5("span", { className: "badge", children: copy.drift }) : null,
594
- meeting.htmlLink ? /* @__PURE__ */ jsx5("a", { href: meeting.htmlLink, target: "_blank", rel: "noreferrer", children: copy.open }) : null,
595
- meeting.meetUrl ? /* @__PURE__ */ jsx5("a", { href: meeting.meetUrl, target: "_blank", rel: "noreferrer", children: copy.meet }) : null
667
+ meeting.drift && meeting.drift !== "none" ? /* @__PURE__ */ jsx6("span", { className: "badge", children: copy.drift }) : null,
668
+ meeting.htmlLink ? /* @__PURE__ */ jsx6("a", { href: meeting.htmlLink, target: "_blank", rel: "noreferrer", children: copy.open }) : null,
669
+ meeting.meetUrl ? /* @__PURE__ */ jsx6("a", { href: meeting.meetUrl, target: "_blank", rel: "noreferrer", children: copy.meet }) : null
596
670
  ] }, meeting.id)) })
597
671
  }
598
672
  ),
599
- /* @__PURE__ */ jsxs5("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(280px, 1fr))", gap: 18 }, children: [
600
- /* @__PURE__ */ jsx5(MetricWidget, { label: copy.applications, data: data.applicationsSeries, format: number }),
601
- data.membersSeries ? /* @__PURE__ */ jsx5(MetricWidget, { label: copy.newMembers, data: data.membersSeries, format: number }) : /* @__PURE__ */ jsx5(Panel, { title: copy.newMembers, children: /* @__PURE__ */ jsx5("p", { className: "muted", children: copy.newMembersUnavailable }) })
673
+ /* @__PURE__ */ jsxs6("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(280px, 1fr))", gap: 18 }, children: [
674
+ /* @__PURE__ */ jsx6(MetricWidget, { label: copy.applications, data: data.applicationsSeries, format: number }),
675
+ data.membersSeries ? /* @__PURE__ */ jsx6(MetricWidget, { label: copy.newMembers, data: data.membersSeries, format: number }) : /* @__PURE__ */ jsx6(Panel, { title: copy.newMembers, children: /* @__PURE__ */ jsx6("p", { className: "muted", children: copy.newMembersUnavailable }) })
602
676
  ] }),
603
- data.revenueSeries && data.revenue.billingReady ? /* @__PURE__ */ jsxs5("div", { children: [
604
- /* @__PURE__ */ jsx5(
677
+ data.revenueSeries && data.revenue.billingReady ? /* @__PURE__ */ jsxs6("div", { children: [
678
+ /* @__PURE__ */ jsx6(
605
679
  MetricWidget,
606
680
  {
607
681
  label: copy.revenueAdded,
@@ -610,7 +684,7 @@ function DashboardBody({ ctx }) {
610
684
  size: "large"
611
685
  }
612
686
  ),
613
- /* @__PURE__ */ jsxs5("p", { className: "muted", children: [
687
+ /* @__PURE__ */ jsxs6("p", { className: "muted", children: [
614
688
  copy.activeMemberships,
615
689
  ": ",
616
690
  data.revenue.activeCount ?? 0,
@@ -621,31 +695,229 @@ function DashboardBody({ ctx }) {
621
695
  data.revenue.annualRunRateCents == null ? "Unknown" : money2(data.revenue.annualRunRateCents),
622
696
  data.revenue.testMode ? ` \xB7 ${copy.testMode}` : ""
623
697
  ] })
624
- ] }) : /* @__PURE__ */ jsx5(Panel, { title: copy.revenue, children: /* @__PURE__ */ jsx5("p", { className: "muted", children: copy.revenueUnavailable }) }),
625
- /* @__PURE__ */ jsxs5(Panel, { title: copy.pipeline, children: [
626
- /* @__PURE__ */ jsx5(StepPipeline, { ariaLabel: copy.pipelineLabel, steps: pipelineSteps }),
627
- exceptions ? /* @__PURE__ */ jsx5("p", { className: "muted", style: { margin: 0 }, children: exceptions }) : null
698
+ ] }) : /* @__PURE__ */ jsx6(Panel, { title: copy.revenue, children: /* @__PURE__ */ jsx6("p", { className: "muted", children: copy.revenueUnavailable }) }),
699
+ /* @__PURE__ */ jsxs6(Panel, { title: copy.pipeline, children: [
700
+ /* @__PURE__ */ jsx6(StepPipeline, { ariaLabel: copy.pipelineLabel, steps: pipelineSteps }),
701
+ exceptions ? /* @__PURE__ */ jsx6("p", { className: "muted", style: { margin: 0 }, children: exceptions }) : null
628
702
  ] })
629
703
  ] });
630
704
  }
631
705
  function dashboardSection(options = {}) {
632
706
  const { id = "dashboard", label = "Dashboard" } = options;
633
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx5(DashboardBody, { ctx }) };
707
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx6(DashboardBody, { ctx }) };
634
708
  }
635
709
 
636
710
  // src/ui/admin-people-workspace.tsx
637
711
  import { BillingCard, CrmWorkspace } from "@odla-ai/crm/ui";
638
712
 
713
+ // src/ui/admin-lifecycle-adapter.ts
714
+ function applicationLifecycleAdapter(ctx, copy = DEFAULT_CHAPTER_COPY.admin.records) {
715
+ return {
716
+ transitionStage: async ({ record, to, client }) => {
717
+ const applicationId = typeof record.fields?.applicationId === "string" ? record.fields.applicationId : null;
718
+ if (!applicationId) {
719
+ const crmClient = ctx.client ?? client;
720
+ if (!crmClient) throw new Error(copy.workflowMissing);
721
+ await crmClient.setStage(record.id, to);
722
+ return;
723
+ }
724
+ const path = `/api/admin/applications/${encodeURIComponent(applicationId)}`;
725
+ if (to === "approved") {
726
+ await adminFetch(ctx.getToken, `${path}/approve`, { method: "POST" });
727
+ } else if (to === "refunded") {
728
+ await adminFetch(ctx.getToken, `${path}/refund`, { method: "POST" });
729
+ } else {
730
+ await adminFetch(ctx.getToken, path, {
731
+ method: "PATCH",
732
+ body: JSON.stringify({ status: to })
733
+ });
734
+ }
735
+ }
736
+ };
737
+ }
738
+
739
+ // src/ui/admin-named-seat.tsx
740
+ import { useState as useState6 } from "preact/hooks";
741
+ import { Button as Button3 } from "@odla-ai/ui/components";
742
+ import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
743
+ function NamedSeatRecordPanel(props) {
744
+ return props.superAdmin ? /* @__PURE__ */ jsx7(SeatPanel, { ...props }) : null;
745
+ }
746
+ function SeatPanel(props) {
747
+ const resource = useAdminResource(props.getToken, `/api/admin/applications/${encodeURIComponent(props.applicationId)}/named-seat`);
748
+ const [busy, setBusy] = useState6(false);
749
+ const [note, setNote] = useState6(null);
750
+ if (resource.loading) return /* @__PURE__ */ jsx7("p", { role: "status", children: "Loading additional seat\u2026" });
751
+ if (resource.error || !resource.data) return null;
752
+ const { data } = resource, seat = data.seat;
753
+ const money4 = new Intl.NumberFormat("en-US", { style: "currency", currency: data.currency }).format(data.amountCents / 100);
754
+ const refund = async () => {
755
+ setBusy(true);
756
+ setNote(null);
757
+ try {
758
+ const receipt = await adminFetch(
759
+ props.getToken,
760
+ `/api/admin/applications/${encodeURIComponent(props.applicationId)}/named-seat/refund`,
761
+ { method: "POST" }
762
+ );
763
+ setNote(receipt.replayed ? "This seat was already refunded." : `Refunded ${new Intl.NumberFormat("en-US", {
764
+ style: "currency",
765
+ currency: data.currency
766
+ }).format((receipt.refundedCents ?? data.amountCents) / 100)}.`);
767
+ props.onChanged?.();
768
+ resource.refresh();
769
+ } catch (failure) {
770
+ setNote(failure instanceof Error ? failure.message : "Refund could not be completed.");
771
+ } finally {
772
+ setBusy(false);
773
+ }
774
+ };
775
+ return /* @__PURE__ */ jsxs7("section", { className: "panel", "aria-label": "Additional seat", style: { display: "grid", gap: 8, marginTop: 16 }, children: [
776
+ /* @__PURE__ */ jsx7("h3", { style: { margin: 0, fontSize: 16 }, children: "Additional seat" }),
777
+ !seat ? /* @__PURE__ */ jsx7("p", { className: "muted", style: { margin: 0 }, children: "No additional seat has been purchased." }) : /* @__PURE__ */ jsxs7(Fragment5, { children: [
778
+ /* @__PURE__ */ jsxs7("p", { style: { margin: 0 }, children: [
779
+ seat.recipientName,
780
+ " \xB7 ",
781
+ seat.recipientEmail,
782
+ " \xB7 ",
783
+ seat.status.replaceAll("_", " ")
784
+ ] }),
785
+ /* @__PURE__ */ jsxs7("p", { className: "muted", style: { margin: 0 }, children: [
786
+ money4,
787
+ " paid in full. The seat waits for its recipient and is never refunded automatically."
788
+ ] }),
789
+ data.refundable ? /* @__PURE__ */ jsx7("div", { children: /* @__PURE__ */ jsx7(Button3, { variant: "danger", mini: true, disabled: busy, onClick: () => void refund(), children: busy ? "Refunding\u2026" : "Refund seat" }) }) : null
790
+ ] }),
791
+ note ? /* @__PURE__ */ jsx7("p", { className: "muted", role: "status", style: { margin: 0 }, children: note }) : null
792
+ ] });
793
+ }
794
+
795
+ // src/ui/admin-candidate-stage.tsx
796
+ import { useState as useState7 } from "preact/hooks";
797
+ import { Button as Button4, Field, Select } from "@odla-ai/ui/components";
798
+ import { Fragment as Fragment6, jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
799
+ var APPLICATION_STAGES = [
800
+ "submitted",
801
+ "paid_pending_vetting",
802
+ "call_scheduled",
803
+ "interviewed",
804
+ "approved",
805
+ "declined",
806
+ "refunded"
807
+ ];
808
+ function CandidateStagePanel(props) {
809
+ const [selected, setSelected] = useState7("");
810
+ const [busy, setBusy] = useState7(false);
811
+ const [error, setError] = useState7(null);
812
+ const options = props.stages.filter((stage) => !props.applicationStages.includes(stage.id) && stage.id !== props.current);
813
+ const label = (id) => props.stages.find((stage) => stage.id === id)?.label ?? id.replaceAll("_", " ");
814
+ if (!options.length && props.current == null) {
815
+ return /* @__PURE__ */ jsx8("p", { children: "Journey stage: Not applicable. No membership application is linked. Administrative access is separate." });
816
+ }
817
+ const target = options.some((stage) => stage.id === selected) ? selected : "";
818
+ return /* @__PURE__ */ jsxs8(Field, { label: "Stage", error, children: [
819
+ /* @__PURE__ */ jsx8("p", { children: props.current == null ? "No stage yet. Membership statuses begin when this person applies." : label(props.current) }),
820
+ options.length ? /* @__PURE__ */ jsxs8(Fragment6, { children: [
821
+ /* @__PURE__ */ jsx8(
822
+ Select,
823
+ {
824
+ "aria-label": "Move to stage",
825
+ value: target,
826
+ disabled: busy,
827
+ onChange: (event) => setSelected(event.currentTarget.value),
828
+ options: [{ value: "", label: "Move to\u2026" }, ...options.map((stage) => ({ value: stage.id, label: label(stage.id) }))]
829
+ }
830
+ ),
831
+ /* @__PURE__ */ jsx8(Button4, { mini: true, disabled: busy || !target, onClick: async () => {
832
+ setBusy(true);
833
+ setError(null);
834
+ try {
835
+ await props.onMove(target);
836
+ setSelected("");
837
+ } catch (failure) {
838
+ setError(failure instanceof Error ? failure.message : "Stage change failed");
839
+ } finally {
840
+ setBusy(false);
841
+ }
842
+ }, children: "Move" })
843
+ ] }) : /* @__PURE__ */ jsx8("p", { children: "No pre-application stages are configured for this chapter\u2019s CRM." })
844
+ ] });
845
+ }
846
+
847
+ // src/ui/admin-record-admission.tsx
848
+ import { useState as useState8 } from "preact/hooks";
849
+ import { Button as Button5, Field as Field2, Select as Select2 } from "@odla-ai/ui/components";
850
+ import { Fragment as Fragment7, jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
851
+ function RecordAdmissionPanel(props) {
852
+ const copy = useChapterCopy().admin.admission;
853
+ const resource = useAdminResource(props.getToken, "/api/admin/admission-grants");
854
+ const [decision, setDecision] = useState8("waive_interview");
855
+ const [note, setNote] = useState8("");
856
+ const [busy, setBusy] = useState8(false);
857
+ const [error, setError] = useState8(null);
858
+ if (!props.email) return /* @__PURE__ */ jsx9("p", { className: "muted", children: "This record has no email yet. Add one before setting an invitation." });
859
+ const email = props.email.trim().toLowerCase();
860
+ const grants = (resource.data?.grants ?? []).filter((grant) => grant.email.trim().toLowerCase() === email);
861
+ const effective = grants.find((grant) => grant.active && !grant.consumedAt && !grant.revokedAt && (!grant.expiresAt || grant.expiresAt > Date.now()));
862
+ const run = async (work) => {
863
+ setBusy(true);
864
+ setError(null);
865
+ try {
866
+ await work();
867
+ setNote("");
868
+ resource.refresh();
869
+ props.onChanged?.();
870
+ } catch (failure) {
871
+ setError(failure instanceof Error ? failure.message : String(failure));
872
+ } finally {
873
+ setBusy(false);
874
+ }
875
+ };
876
+ const save = () => run(() => adminFetch(props.getToken, "/api/admin/admission-grants", {
877
+ method: "POST",
878
+ body: JSON.stringify({ email: props.email, decision, ...note.trim() ? { note: note.trim() } : {} })
879
+ }));
880
+ const revoke = (grant) => run(() => adminFetch(props.getToken, `/api/admin/admission-grants/${encodeURIComponent(grant.id)}`, { method: "DELETE" }));
881
+ return /* @__PURE__ */ jsxs9("section", { "aria-label": "Invitation", style: { display: "grid", gap: 12 }, children: [
882
+ resource.loading ? /* @__PURE__ */ jsx9("p", { role: "status", children: copy.loading }) : resource.error ? /* @__PURE__ */ jsx9("p", { role: "alert", children: resource.error }) : effective ? /* @__PURE__ */ jsxs9("p", { style: { margin: 0 }, "data-testid": "effective-invitation", children: [
883
+ /* @__PURE__ */ jsx9("strong", { children: effective.decision === "waive_interview" ? copy.waive : copy.require }),
884
+ " \xB7 ",
885
+ effective.sourceScope === "local" ? copy.local : copy.parent,
886
+ effective.note ? ` \xB7 ${effective.note}` : "",
887
+ effective.sourceScope === "local" ? /* @__PURE__ */ jsxs9(Fragment7, { children: [
888
+ " ",
889
+ /* @__PURE__ */ jsx9(Button5, { variant: "secondary", mini: true, disabled: busy, onClick: () => void revoke(effective), children: copy.revoke })
890
+ ] }) : null
891
+ ] }) : /* @__PURE__ */ jsxs9("p", { className: "muted", style: { margin: 0 }, children: [
892
+ "No invitation setting for ",
893
+ email,
894
+ ". The next signup follows the chapter\u2019s ordinary interview rule."
895
+ ] }),
896
+ /* @__PURE__ */ jsx9(Field2, { label: copy.decision, children: /* @__PURE__ */ jsx9(
897
+ Select2,
898
+ {
899
+ value: decision,
900
+ disabled: busy,
901
+ onChange: (event) => setDecision(event.currentTarget.value),
902
+ options: [{ value: "waive_interview", label: copy.waive }, { value: "require_interview", label: copy.require }]
903
+ }
904
+ ) }),
905
+ /* @__PURE__ */ jsx9(Field2, { label: copy.note, children: /* @__PURE__ */ jsx9("input", { value: note, maxLength: 2e3, disabled: busy, onInput: (event) => setNote(event.currentTarget.value) }) }),
906
+ /* @__PURE__ */ jsx9("div", { children: /* @__PURE__ */ jsx9(Button5, { variant: "secondary", mini: true, disabled: busy, onClick: () => void save(), children: copy.add }) }),
907
+ error ? /* @__PURE__ */ jsx9("p", { role: "alert", children: error }) : null
908
+ ] });
909
+ }
910
+
639
911
  // src/ui/admin-application-repair.tsx
640
- import { useState as useState4 } from "preact/hooks";
641
- import { Button } from "@odla-ai/ui/components";
642
- import { jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
912
+ import { useState as useState9 } from "preact/hooks";
913
+ import { Button as Button6 } from "@odla-ai/ui/components";
914
+ import { jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
643
915
  function ApplicationLinkRepair({ recordId, getToken, onChanged }) {
644
- const [busy, setBusy] = useState4(false);
645
- const [error, setError] = useState4(null);
646
- return /* @__PURE__ */ jsxs6("section", { className: "panel", children: [
647
- /* @__PURE__ */ jsx6("p", { children: "This person is missing an application link. Repair checks for one matching chapter application; it does not change membership or profile details." }),
648
- /* @__PURE__ */ jsx6(Button, { variant: "secondary", disabled: busy, onClick: async () => {
916
+ const [busy, setBusy] = useState9(false);
917
+ const [error, setError] = useState9(null);
918
+ return /* @__PURE__ */ jsxs10("section", { className: "panel", children: [
919
+ /* @__PURE__ */ jsx10("p", { children: "This person is missing an application link. Repair checks for one matching chapter application; it does not change membership or profile details." }),
920
+ /* @__PURE__ */ jsx10(Button6, { variant: "secondary", disabled: busy, onClick: async () => {
649
921
  setBusy(true);
650
922
  setError(null);
651
923
  try {
@@ -657,34 +929,34 @@ function ApplicationLinkRepair({ recordId, getToken, onChanged }) {
657
929
  setBusy(false);
658
930
  }
659
931
  }, children: busy ? "Checking application link\u2026" : "Repair application link" }),
660
- error ? /* @__PURE__ */ jsx6("p", { role: "alert", children: error }) : null
932
+ error ? /* @__PURE__ */ jsx10("p", { role: "alert", children: error }) : null
661
933
  ] });
662
934
  }
663
935
 
664
936
  // src/ui/admin-application-stage.tsx
665
- import { useState as useState5 } from "preact/hooks";
666
- import { Button as Button2, Field, Select } from "@odla-ai/ui/components";
667
- import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
937
+ import { useState as useState10 } from "preact/hooks";
938
+ import { Button as Button7, Field as Field3, Select as Select3 } from "@odla-ai/ui/components";
939
+ import { Fragment as Fragment8, jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
668
940
  function ApplicationStagePanel(props) {
669
941
  const actions = useAdminResource(
670
942
  props.getToken,
671
943
  `/api/admin/applications/${encodeURIComponent(props.applicationId)}/actions`
672
944
  );
673
- const [selected, setSelected] = useState5("");
674
- const [busy, setBusy] = useState5(false);
675
- const [error, setError] = useState5(null);
676
- if (actions.loading) return /* @__PURE__ */ jsx7("p", { role: "status", children: "Loading available actions\u2026" });
677
- if (actions.error) return /* @__PURE__ */ jsxs7("p", { role: "alert", children: [
945
+ const [selected, setSelected] = useState10("");
946
+ const [busy, setBusy] = useState10(false);
947
+ const [error, setError] = useState10(null);
948
+ if (actions.loading) return /* @__PURE__ */ jsx11("p", { role: "status", children: "Loading available actions\u2026" });
949
+ if (actions.error) return /* @__PURE__ */ jsxs11("p", { role: "alert", children: [
678
950
  "Could not load application actions: ",
679
951
  actions.error
680
952
  ] });
681
953
  const allowed = actions.data?.allowedStages ?? [];
682
954
  const target = allowed.includes(selected) ? selected : "";
683
- return /* @__PURE__ */ jsxs7(Field, { label: "Stage", error, children: [
684
- /* @__PURE__ */ jsx7("p", { children: actions.data?.status?.replaceAll("_", " ") }),
685
- allowed.length ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
686
- /* @__PURE__ */ jsx7(
687
- Select,
955
+ return /* @__PURE__ */ jsxs11(Field3, { label: "Stage", error, children: [
956
+ /* @__PURE__ */ jsx11("p", { children: actions.data?.status?.replaceAll("_", " ") }),
957
+ allowed.length ? /* @__PURE__ */ jsxs11(Fragment8, { children: [
958
+ /* @__PURE__ */ jsx11(
959
+ Select3,
688
960
  {
689
961
  "aria-label": "Move to stage",
690
962
  value: target,
@@ -693,7 +965,7 @@ function ApplicationStagePanel(props) {
693
965
  options: [{ value: "", label: "Move to\u2026" }, ...allowed.map((value) => ({ value, label: value.replaceAll("_", " ") }))]
694
966
  }
695
967
  ),
696
- /* @__PURE__ */ jsx7(Button2, { mini: true, disabled: busy || !target, onClick: async () => {
968
+ /* @__PURE__ */ jsx11(Button7, { mini: true, disabled: busy || !target, onClick: async () => {
697
969
  setBusy(true);
698
970
  setError(null);
699
971
  try {
@@ -706,19 +978,19 @@ function ApplicationStagePanel(props) {
706
978
  actions.refresh();
707
979
  }
708
980
  }, children: "Move" })
709
- ] }) : /* @__PURE__ */ jsx7("p", { children: "No stage changes are available under this chapter\u2019s current membership policy." })
981
+ ] }) : /* @__PURE__ */ jsx11("p", { children: "No stage changes are available under this chapter\u2019s current membership policy." })
710
982
  ] });
711
983
  }
712
984
 
713
985
  // src/ui/operational-profile-form.tsx
714
- import { Button as Button3, Field as Field2, Input, Select as Select2, Textarea } from "@odla-ai/ui/components";
715
- import { useRef, useState as useState6 } from "preact/hooks";
716
- import { jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
986
+ import { Button as Button8, Field as Field4, Input, Select as Select4, Textarea } from "@odla-ai/ui/components";
987
+ import { useRef, useState as useState11 } from "preact/hooks";
988
+ import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
717
989
  var valueText = (value) => value == null ? "" : typeof value === "object" ? JSON.stringify(value) : String(value);
718
990
  function OperationalProfileForm(props) {
719
- const [draft, setDraft] = useState6(() => Object.fromEntries(props.fields.map((field) => [field.id, valueText(props.values[field.id])])));
720
- const [busy, setBusy] = useState6(false);
721
- const [error, setError] = useState6(null);
991
+ const [draft, setDraft] = useState11(() => Object.fromEntries(props.fields.map((field) => [field.id, valueText(props.values[field.id])])));
992
+ const [busy, setBusy] = useState11(false);
993
+ const [error, setError] = useState11(null);
722
994
  const pending = useRef(null);
723
995
  const changed = props.fields.filter((field) => draft[field.id] !== valueText(props.values[field.id]));
724
996
  const save = async () => {
@@ -746,20 +1018,20 @@ function OperationalProfileForm(props) {
746
1018
  setBusy(false);
747
1019
  }
748
1020
  };
749
- return /* @__PURE__ */ jsxs8("section", { style: { display: "grid", gap: 16 }, children: [
750
- props.fields.map((field) => /* @__PURE__ */ jsx8(Field2, { label: field.label, children: field.options || field.type === "boolean" ? /* @__PURE__ */ jsxs8(
751
- Select2,
1021
+ return /* @__PURE__ */ jsxs12("section", { style: { display: "grid", gap: 16 }, children: [
1022
+ props.fields.map((field) => /* @__PURE__ */ jsx12(Field4, { label: field.label, children: field.options || field.type === "boolean" ? /* @__PURE__ */ jsxs12(
1023
+ Select4,
752
1024
  {
753
1025
  "aria-label": field.label,
754
1026
  value: draft[field.id],
755
1027
  disabled: busy,
756
1028
  onChange: (event) => setDraft({ ...draft, [field.id]: event.currentTarget.value }),
757
1029
  children: [
758
- /* @__PURE__ */ jsx8("option", { value: "", children: "Not set" }),
759
- (field.options ?? ["true", "false"]).map((option) => /* @__PURE__ */ jsx8("option", { value: option, children: option }, option))
1030
+ /* @__PURE__ */ jsx12("option", { value: "", children: "Not set" }),
1031
+ (field.options ?? ["true", "false"]).map((option) => /* @__PURE__ */ jsx12("option", { value: option, children: option }, option))
760
1032
  ]
761
1033
  }
762
- ) : field.type === "json" ? /* @__PURE__ */ jsx8(
1034
+ ) : field.type === "json" ? /* @__PURE__ */ jsx12(
763
1035
  Textarea,
764
1036
  {
765
1037
  "aria-label": field.label,
@@ -767,7 +1039,7 @@ function OperationalProfileForm(props) {
767
1039
  disabled: busy,
768
1040
  onInput: (event) => setDraft({ ...draft, [field.id]: event.currentTarget.value })
769
1041
  }
770
- ) : /* @__PURE__ */ jsx8(
1042
+ ) : /* @__PURE__ */ jsx12(
771
1043
  Input,
772
1044
  {
773
1045
  "aria-label": field.label,
@@ -777,26 +1049,26 @@ function OperationalProfileForm(props) {
777
1049
  onInput: (event) => setDraft({ ...draft, [field.id]: event.currentTarget.value })
778
1050
  }
779
1051
  ) }, field.id)),
780
- error ? /* @__PURE__ */ jsx8("p", { role: "alert", children: error }) : null,
781
- /* @__PURE__ */ jsx8("div", { children: /* @__PURE__ */ jsx8(Button3, { disabled: busy || !changed.length, onClick: () => void save(), children: busy ? "Saving\u2026" : "Save profile" }) })
1052
+ error ? /* @__PURE__ */ jsx12("p", { role: "alert", children: error }) : null,
1053
+ /* @__PURE__ */ jsx12("div", { children: /* @__PURE__ */ jsx12(Button8, { disabled: busy || !changed.length, onClick: () => void save(), children: busy ? "Saving\u2026" : "Save profile" }) })
782
1054
  ] });
783
1055
  }
784
1056
 
785
1057
  // src/ui/admin-person-profile.tsx
786
- import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
1058
+ import { Fragment as Fragment9, jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
787
1059
  function ChapterPersonProfile(props) {
788
1060
  const path = `/api/admin/people/profile?${new URLSearchParams({ recordId: props.recordId })}`;
789
1061
  const resource = useAdminResource(props.getToken, path);
790
- if (resource.loading) return /* @__PURE__ */ jsx9("p", { children: "Loading profile\u2026" });
791
- if (resource.error) return /* @__PURE__ */ jsx9("p", { role: "alert", children: resource.error });
1062
+ if (resource.loading) return /* @__PURE__ */ jsx13("p", { children: "Loading profile\u2026" });
1063
+ if (resource.error) return /* @__PURE__ */ jsx13("p", { role: "alert", children: resource.error });
792
1064
  const record = resource.data?.record;
793
- if (!record?.edit) return /* @__PURE__ */ jsx9("p", { children: "Profile editing is unavailable." });
794
- return /* @__PURE__ */ jsxs9(Fragment5, { children: [
795
- /* @__PURE__ */ jsxs9("p", { children: [
1065
+ if (!record?.edit) return /* @__PURE__ */ jsx13("p", { children: "Profile editing is unavailable." });
1066
+ return /* @__PURE__ */ jsxs13(Fragment9, { children: [
1067
+ /* @__PURE__ */ jsxs13("p", { children: [
796
1068
  String(record.fields.email ?? ""),
797
1069
  " \u2014 login email changes use the verified account workflow."
798
1070
  ] }),
799
- /* @__PURE__ */ jsx9(
1071
+ /* @__PURE__ */ jsx13(
800
1072
  OperationalProfileForm,
801
1073
  {
802
1074
  fields: record.edit.fields,
@@ -813,14 +1085,14 @@ function ChapterPersonProfile(props) {
813
1085
  }
814
1086
 
815
1087
  // src/ui/admin-account-sync.tsx
816
- import { useState as useState7 } from "preact/hooks";
817
- import { Button as Button4 } from "@odla-ai/ui/components";
818
- import { jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
1088
+ import { useState as useState12 } from "preact/hooks";
1089
+ import { Button as Button9 } from "@odla-ai/ui/components";
1090
+ import { jsx as jsx14, jsxs as jsxs14 } from "preact/jsx-runtime";
819
1091
  function AccountPeopleSync({ getToken, refresh }) {
820
- const [busy, setBusy] = useState7(false);
821
- const [message, setMessage] = useState7("");
822
- return /* @__PURE__ */ jsxs10("div", { children: [
823
- /* @__PURE__ */ jsx10(Button4, { mini: true, variant: "secondary", disabled: busy, onClick: async () => {
1092
+ const [busy, setBusy] = useState12(false);
1093
+ const [message, setMessage] = useState12("");
1094
+ return /* @__PURE__ */ jsxs14("div", { children: [
1095
+ /* @__PURE__ */ jsx14(Button9, { mini: true, variant: "secondary", disabled: busy, onClick: async () => {
824
1096
  setBusy(true);
825
1097
  setMessage("");
826
1098
  let after = null, count = 0, errors = 0;
@@ -844,21 +1116,21 @@ function AccountPeopleSync({ getToken, refresh }) {
844
1116
  setBusy(false);
845
1117
  }
846
1118
  }, children: busy ? "Syncing accounts\u2026" : "Sync accounts" }),
847
- message ? /* @__PURE__ */ jsx10("p", { role: "status", children: message }) : null
1119
+ message ? /* @__PURE__ */ jsx14("p", { role: "status", children: message }) : null
848
1120
  ] });
849
1121
  }
850
1122
 
851
1123
  // src/ui/admin-record-actions.tsx
852
- import { useEffect as useEffect4, useState as useState8 } from "preact/hooks";
853
- import { Button as Button5, Field as Field3, Select as Select3 } from "@odla-ai/ui/components";
854
- import { jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
1124
+ import { useEffect as useEffect4, useState as useState13 } from "preact/hooks";
1125
+ import { Button as Button10, Field as Field5, Select as Select5 } from "@odla-ai/ui/components";
1126
+ import { jsx as jsx15, jsxs as jsxs15 } from "preact/jsx-runtime";
855
1127
  function RecordActions({ getToken, record, roles, onChanged }) {
856
1128
  const copy = useChapterCopy().admin.records;
857
1129
  const userId = typeof record.clerkUserId === "string" ? record.clerkUserId : null;
858
1130
  const applicationId = typeof record.fields?.applicationId === "string" ? record.fields.applicationId : null;
859
- const [access, setAccess] = useState8(null);
860
- const [busy, setBusy] = useState8(null);
861
- const [note, setNote] = useState8(null);
1131
+ const [access, setAccess] = useState13(null);
1132
+ const [busy, setBusy] = useState13(null);
1133
+ const [note, setNote] = useState13(null);
862
1134
  useEffect4(() => {
863
1135
  if (!userId) {
864
1136
  setAccess(null);
@@ -887,34 +1159,34 @@ function RecordActions({ getToken, record, roles, onChanged }) {
887
1159
  const approve = () => act("approve", () => adminFetch(getToken, `/api/admin/applications/${applicationId}/approve`, { method: "POST" }), copy.approved);
888
1160
  const refund = () => act("refund", () => adminFetch(getToken, `/api/admin/applications/${applicationId}/refund`, { method: "POST" }), copy.refunded);
889
1161
  if (!userId && !applicationId) return null;
890
- return /* @__PURE__ */ jsxs11("section", { className: "panel", style: { display: "flex", flexDirection: "column", gap: 14, marginTop: 16 }, children: [
891
- /* @__PURE__ */ jsx11("h3", { style: { margin: 0, fontSize: 16 }, children: copy.lifecycle }),
892
- userId ? /* @__PURE__ */ jsx11(Field3, { label: copy.role, hint: access?.superAdmin ? copy.superAdminHint : void 0, children: /* @__PURE__ */ jsx11(
893
- Select3,
1162
+ return /* @__PURE__ */ jsxs15("section", { className: "panel", style: { display: "flex", flexDirection: "column", gap: 14, marginTop: 16 }, children: [
1163
+ /* @__PURE__ */ jsx15("h3", { style: { margin: 0, fontSize: 16 }, children: copy.lifecycle }),
1164
+ userId ? /* @__PURE__ */ jsx15(Field5, { label: copy.role, hint: access?.superAdmin ? copy.superAdminHint : void 0, children: /* @__PURE__ */ jsx15(
1165
+ Select5,
894
1166
  {
895
1167
  value: access?.role ?? "",
896
1168
  disabled: busy === "role" || access?.superAdmin,
897
1169
  options: roles.map((r) => ({ value: r, label: r })),
898
1170
  onChange: (e) => void setRole(e.target.value)
899
1171
  }
900
- ) }) : /* @__PURE__ */ jsx11("p", { className: "muted", style: { margin: 0 }, children: copy.noAccount }),
901
- applicationId ? /* @__PURE__ */ jsxs11("div", { style: { display: "flex", gap: 8 }, children: [
902
- /* @__PURE__ */ jsx11(Button5, { variant: "secondary", mini: true, disabled: busy === "approve", onClick: () => void approve(), children: copy.approve }),
903
- /* @__PURE__ */ jsx11(Button5, { variant: "danger", mini: true, disabled: busy === "refund", onClick: () => void refund(), children: copy.refund })
1172
+ ) }) : /* @__PURE__ */ jsx15("p", { className: "muted", style: { margin: 0 }, children: copy.noAccount }),
1173
+ applicationId ? /* @__PURE__ */ jsxs15("div", { style: { display: "flex", gap: 8 }, children: [
1174
+ /* @__PURE__ */ jsx15(Button10, { variant: "secondary", mini: true, disabled: busy === "approve", onClick: () => void approve(), children: copy.approve }),
1175
+ /* @__PURE__ */ jsx15(Button10, { variant: "danger", mini: true, disabled: busy === "refund", onClick: () => void refund(), children: copy.refund })
904
1176
  ] }) : null,
905
- note ? /* @__PURE__ */ jsx11("p", { className: "muted", style: { margin: 0 }, children: note }) : null
1177
+ note ? /* @__PURE__ */ jsx15("p", { className: "muted", style: { margin: 0 }, children: note }) : null
906
1178
  ] });
907
1179
  }
908
1180
 
909
1181
  // src/ui/admin-network.tsx
910
- import { useState as useState9 } from "preact/hooks";
911
- import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
1182
+ import { useState as useState14 } from "preact/hooks";
1183
+ import { jsx as jsx16, jsxs as jsxs16 } from "preact/jsx-runtime";
912
1184
  function NetworkShareActions(props) {
913
1185
  const copy = useChapterCopy().admin.network;
914
1186
  const { recordId, recordType, getToken } = props;
915
1187
  const targets = useAdminResource(getToken, "/api/admin/network/targets");
916
- const [busy, setBusy] = useState9(null);
917
- const [message, setMessage] = useState9(null);
1188
+ const [busy, setBusy] = useState14(null);
1189
+ const [message, setMessage] = useState14(null);
918
1190
  const compatible = (targets.data?.targets ?? []).filter((target) => target.types.includes(recordType));
919
1191
  if (targets.loading || targets.error || compatible.length === 0) return null;
920
1192
  const push = async (target) => {
@@ -933,26 +1205,26 @@ function NetworkShareActions(props) {
933
1205
  setBusy(null);
934
1206
  }
935
1207
  };
936
- return /* @__PURE__ */ jsxs12("section", { className: "panel", style: { marginTop: 14, display: "flex", flexDirection: "column", gap: 10 }, children: [
937
- /* @__PURE__ */ jsxs12("div", { children: [
938
- /* @__PURE__ */ jsx12("h3", { style: { margin: 0, fontSize: 16 }, children: copy.title }),
939
- /* @__PURE__ */ jsx12("p", { className: "muted", style: { margin: "4px 0 0", fontSize: 13 }, children: copy.allowlistDescription })
1208
+ return /* @__PURE__ */ jsxs16("section", { className: "panel", style: { marginTop: 14, display: "flex", flexDirection: "column", gap: 10 }, children: [
1209
+ /* @__PURE__ */ jsxs16("div", { children: [
1210
+ /* @__PURE__ */ jsx16("h3", { style: { margin: 0, fontSize: 16 }, children: copy.title }),
1211
+ /* @__PURE__ */ jsx16("p", { className: "muted", style: { margin: "4px 0 0", fontSize: 13 }, children: copy.allowlistDescription })
940
1212
  ] }),
941
- /* @__PURE__ */ jsx12("div", { style: { display: "flex", flexWrap: "wrap", gap: 8 }, children: compatible.map((target) => /* @__PURE__ */ jsx12("button", { className: "btn secondary mini", disabled: busy !== null, onClick: () => void push(target), children: busy === target.id ? copy.sharing : formatChapterCopy(copy.shareWith, { target: target.name }) }, target.id)) }),
942
- message ? /* @__PURE__ */ jsx12("p", { role: "status", style: { margin: 0, fontSize: 13 }, children: message }) : null
1213
+ /* @__PURE__ */ jsx16("div", { style: { display: "flex", flexWrap: "wrap", gap: 8 }, children: compatible.map((target) => /* @__PURE__ */ jsx16("button", { className: "btn secondary mini", disabled: busy !== null, onClick: () => void push(target), children: busy === target.id ? copy.sharing : formatChapterCopy(copy.shareWith, { target: target.name }) }, target.id)) }),
1214
+ message ? /* @__PURE__ */ jsx16("p", { role: "status", style: { margin: 0, fontSize: 13 }, children: message }) : null
943
1215
  ] });
944
1216
  }
945
1217
 
946
1218
  // src/ui/admin-record-activity.tsx
947
- import { useCallback as useCallback3, useEffect as useEffect5, useState as useState10 } from "preact/hooks";
1219
+ import { useCallback as useCallback3, useEffect as useEffect5, useState as useState15 } from "preact/hooks";
948
1220
  import { ActivityFeed } from "@odla-ai/crm/ui";
949
1221
  import { parseCrmDiscussionReference as parseCrmDiscussionReference2 } from "@odla-ai/crm";
950
- import { jsx as jsx13 } from "preact/jsx-runtime";
1222
+ import { jsx as jsx17 } from "preact/jsx-runtime";
951
1223
  function RecordActivityPanel(props) {
952
1224
  const { client, recordId } = props;
953
- const [activities, setActivities] = useState10([]);
954
- const [busy, setBusy] = useState10(false);
955
- const [error, setError] = useState10(null);
1225
+ const [activities, setActivities] = useState15([]);
1226
+ const [busy, setBusy] = useState15(false);
1227
+ const [error, setError] = useState15(null);
956
1228
  const reference = typeof window === "undefined" ? null : parseCrmDiscussionReference2(new URL(window.location.href));
957
1229
  const focusedActivityId = reference?.kind === "crm:activity" && reference.recordId === recordId ? reference.activityId : void 0;
958
1230
  const load = useCallback3(async () => {
@@ -974,8 +1246,8 @@ function RecordActivityPanel(props) {
974
1246
  setBusy(false);
975
1247
  }
976
1248
  };
977
- if (error) return /* @__PURE__ */ jsx13("p", { role: "alert", className: "muted", children: error });
978
- return /* @__PURE__ */ jsx13(
1249
+ if (error) return /* @__PURE__ */ jsx17("p", { role: "alert", className: "muted", children: error });
1250
+ return /* @__PURE__ */ jsx17(
979
1251
  ActivityFeed,
980
1252
  {
981
1253
  activities,
@@ -989,17 +1261,17 @@ function RecordActivityPanel(props) {
989
1261
  }
990
1262
 
991
1263
  // src/ui/admin-record-comms.tsx
992
- import { useCallback as useCallback4, useEffect as useEffect6, useState as useState11 } from "preact/hooks";
993
- import { Button as Button6, Field as Field4, Select as Select4 } from "@odla-ai/ui/components";
994
- import { jsx as jsx14, jsxs as jsxs13 } from "preact/jsx-runtime";
1264
+ import { useCallback as useCallback4, useEffect as useEffect6, useState as useState16 } from "preact/hooks";
1265
+ import { Button as Button11, Field as Field6, Select as Select6 } from "@odla-ai/ui/components";
1266
+ import { jsx as jsx18, jsxs as jsxs17 } from "preact/jsx-runtime";
995
1267
  function RecordCommsPanel(props) {
996
1268
  const copy = useChapterCopy().admin.records;
997
1269
  const { client, recordId, getToken } = props;
998
1270
  const config = useAdminResource(getToken, "/api/admin/group/email");
999
1271
  const templates = Object.entries(config.data?.emailTemplates ?? {}).filter(([, value]) => value.enabled);
1000
- const [template, setTemplate] = useState11("");
1001
- const [busy, setBusy] = useState11(false);
1002
- const [note, setNote] = useState11(null);
1272
+ const [template, setTemplate] = useState16("");
1273
+ const [busy, setBusy] = useState16(false);
1274
+ const [note, setNote] = useState16(null);
1003
1275
  const send = async () => {
1004
1276
  if (!template) return;
1005
1277
  setBusy(true);
@@ -1013,11 +1285,11 @@ function RecordCommsPanel(props) {
1013
1285
  setBusy(false);
1014
1286
  }
1015
1287
  };
1016
- if (config.loading) return /* @__PURE__ */ jsx14("p", { className: "muted", children: copy.loadingTemplates });
1017
- if (config.error) return /* @__PURE__ */ jsx14("p", { role: "alert", className: "muted", children: config.error });
1018
- return /* @__PURE__ */ jsxs13("div", { style: { display: "grid", gap: 14, maxWidth: 560 }, children: [
1019
- /* @__PURE__ */ jsx14(Field4, { label: copy.template, children: /* @__PURE__ */ jsx14(
1020
- Select4,
1288
+ if (config.loading) return /* @__PURE__ */ jsx18("p", { className: "muted", children: copy.loadingTemplates });
1289
+ if (config.error) return /* @__PURE__ */ jsx18("p", { role: "alert", className: "muted", children: config.error });
1290
+ return /* @__PURE__ */ jsxs17("div", { style: { display: "grid", gap: 14, maxWidth: 560 }, children: [
1291
+ /* @__PURE__ */ jsx18(Field6, { label: copy.template, children: /* @__PURE__ */ jsx18(
1292
+ Select6,
1021
1293
  {
1022
1294
  value: template,
1023
1295
  onChange: (event) => setTemplate(event.currentTarget.value),
@@ -1027,15 +1299,15 @@ function RecordCommsPanel(props) {
1027
1299
  ]
1028
1300
  }
1029
1301
  ) }),
1030
- /* @__PURE__ */ jsx14("div", { children: /* @__PURE__ */ jsx14(Button6, { disabled: !template || busy, onClick: () => void send(), children: busy ? copy.sending : copy.send }) }),
1031
- note ? /* @__PURE__ */ jsx14("p", { role: "status", className: "muted", children: note }) : null
1302
+ /* @__PURE__ */ jsx18("div", { children: /* @__PURE__ */ jsx18(Button11, { disabled: !template || busy, onClick: () => void send(), children: busy ? copy.sending : copy.send }) }),
1303
+ note ? /* @__PURE__ */ jsx18("p", { role: "status", className: "muted", children: note }) : null
1032
1304
  ] });
1033
1305
  }
1034
1306
  function RecordCommsHistory(props) {
1035
1307
  const copy = useChapterCopy().admin.records;
1036
1308
  const { client, recordId } = props;
1037
- const [rows, setRows] = useState11([]);
1038
- const [error, setError] = useState11(null);
1309
+ const [rows, setRows] = useState16([]);
1310
+ const [error, setError] = useState16(null);
1039
1311
  const load = useCallback4(async () => {
1040
1312
  try {
1041
1313
  const result = await client.emailLog({ recordId, limit: 100 });
@@ -1046,11 +1318,11 @@ function RecordCommsHistory(props) {
1046
1318
  }
1047
1319
  }, [client, recordId]);
1048
1320
  useEffect6(() => void load(), [load]);
1049
- if (error) return /* @__PURE__ */ jsx14("p", { role: "alert", className: "muted", children: error });
1050
- if (rows.length === 0) return /* @__PURE__ */ jsx14("p", { className: "muted", children: copy.noMessages });
1051
- return /* @__PURE__ */ jsx14("ul", { style: { listStyle: "none", padding: 0, margin: 0, display: "grid", gap: 10 }, children: rows.map((row, index) => /* @__PURE__ */ jsxs13("li", { className: "panel", children: [
1052
- /* @__PURE__ */ jsx14("strong", { children: String(row["templateId"] ?? row["template"] ?? copy.message) }),
1053
- /* @__PURE__ */ jsxs13("div", { className: "muted", children: [
1321
+ if (error) return /* @__PURE__ */ jsx18("p", { role: "alert", className: "muted", children: error });
1322
+ if (rows.length === 0) return /* @__PURE__ */ jsx18("p", { className: "muted", children: copy.noMessages });
1323
+ return /* @__PURE__ */ jsx18("ul", { style: { listStyle: "none", padding: 0, margin: 0, display: "grid", gap: 10 }, children: rows.map((row, index) => /* @__PURE__ */ jsxs17("li", { className: "panel", children: [
1324
+ /* @__PURE__ */ jsx18("strong", { children: String(row["templateId"] ?? row["template"] ?? copy.message) }),
1325
+ /* @__PURE__ */ jsxs17("div", { className: "muted", children: [
1054
1326
  row["to"] ? String(row["to"]) : "",
1055
1327
  row["sentAt"] ? ` \xB7 ${new Date(Number(row["sentAt"])).toLocaleString()}` : ""
1056
1328
  ] })
@@ -1058,9 +1330,9 @@ function RecordCommsHistory(props) {
1058
1330
  }
1059
1331
 
1060
1332
  // src/ui/admin-record-scheduling.tsx
1061
- import { useState as useState12 } from "preact/hooks";
1062
- import { Button as Button7 } from "@odla-ai/ui/components";
1063
- import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs14 } from "preact/jsx-runtime";
1333
+ import { useState as useState17 } from "preact/hooks";
1334
+ import { Button as Button12 } from "@odla-ai/ui/components";
1335
+ import { Fragment as Fragment10, jsx as jsx19, jsxs as jsxs18 } from "preact/jsx-runtime";
1064
1336
  function RecordSchedulingPanel(props) {
1065
1337
  const copy = useChapterCopy().admin.records;
1066
1338
  const { getToken, applicationId } = props;
@@ -1068,8 +1340,8 @@ function RecordSchedulingPanel(props) {
1068
1340
  getToken,
1069
1341
  "/api/admin/meetings?all=1"
1070
1342
  );
1071
- const [busy, setBusy] = useState12(null);
1072
- const [note, setNote] = useState12(null);
1343
+ const [busy, setBusy] = useState17(null);
1344
+ const [note, setNote] = useState17(null);
1073
1345
  const meetings = (resource.data?.meetings ?? []).filter((meeting) => meeting.applicationId === applicationId);
1074
1346
  const run = async (meeting, action) => {
1075
1347
  let body;
@@ -1096,54 +1368,33 @@ function RecordSchedulingPanel(props) {
1096
1368
  setBusy(null);
1097
1369
  }
1098
1370
  };
1099
- if (!applicationId) return /* @__PURE__ */ jsx15("p", { className: "muted", children: copy.noApplication });
1100
- if (resource.loading) return /* @__PURE__ */ jsx15("p", { className: "muted", children: copy.loadingMeetings });
1101
- if (resource.error) return /* @__PURE__ */ jsx15("p", { role: "alert", className: "muted", children: resource.error });
1102
- if (meetings.length === 0) return /* @__PURE__ */ jsx15("p", { className: "muted", children: copy.noMeetings });
1103
- return /* @__PURE__ */ jsxs14("div", { style: { display: "grid", gap: 12 }, children: [
1104
- meetings.map((meeting) => /* @__PURE__ */ jsxs14("section", { className: "panel", children: [
1105
- /* @__PURE__ */ jsx15("strong", { children: new Date(meeting.startAt).toLocaleString() }),
1106
- /* @__PURE__ */ jsxs14("p", { className: "muted", children: [
1371
+ if (!applicationId) return /* @__PURE__ */ jsx19("p", { className: "muted", children: copy.noApplication });
1372
+ if (resource.loading) return /* @__PURE__ */ jsx19("p", { className: "muted", children: copy.loadingMeetings });
1373
+ if (resource.error) return /* @__PURE__ */ jsx19("p", { role: "alert", className: "muted", children: resource.error });
1374
+ if (meetings.length === 0) return /* @__PURE__ */ jsx19("p", { className: "muted", children: copy.noMeetings });
1375
+ return /* @__PURE__ */ jsxs18("div", { style: { display: "grid", gap: 12 }, children: [
1376
+ meetings.map((meeting) => /* @__PURE__ */ jsxs18("section", { className: "panel", children: [
1377
+ /* @__PURE__ */ jsx19("strong", { children: new Date(meeting.startAt).toLocaleString() }),
1378
+ /* @__PURE__ */ jsxs18("p", { className: "muted", children: [
1107
1379
  meeting.status,
1108
1380
  " \xB7 ",
1109
1381
  resource.data?.timezone
1110
1382
  ] }),
1111
- /* @__PURE__ */ jsxs14("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
1112
- meeting.meetUrl ? /* @__PURE__ */ jsx15("a", { href: meeting.meetUrl, target: "_blank", rel: "noreferrer", children: copy.joinMeeting }) : null,
1113
- meeting.htmlLink ? /* @__PURE__ */ jsx15("a", { href: meeting.htmlLink, target: "_blank", rel: "noreferrer", children: copy.openCalendar }) : null,
1114
- meeting.status === "scheduled" ? /* @__PURE__ */ jsxs14(Fragment6, { children: [
1115
- /* @__PURE__ */ jsx15(Button7, { variant: "secondary", mini: true, disabled: busy === meeting.id, onClick: () => void run(meeting, "reschedule"), children: copy.reschedule }),
1116
- /* @__PURE__ */ jsx15(Button7, { variant: "danger", mini: true, disabled: busy === meeting.id, onClick: () => void run(meeting, "cancel"), children: copy.cancel })
1383
+ /* @__PURE__ */ jsxs18("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
1384
+ meeting.meetUrl ? /* @__PURE__ */ jsx19("a", { href: meeting.meetUrl, target: "_blank", rel: "noreferrer", children: copy.joinMeeting }) : null,
1385
+ meeting.htmlLink ? /* @__PURE__ */ jsx19("a", { href: meeting.htmlLink, target: "_blank", rel: "noreferrer", children: copy.openCalendar }) : null,
1386
+ meeting.status === "scheduled" ? /* @__PURE__ */ jsxs18(Fragment10, { children: [
1387
+ /* @__PURE__ */ jsx19(Button12, { variant: "secondary", mini: true, disabled: busy === meeting.id, onClick: () => void run(meeting, "reschedule"), children: copy.reschedule }),
1388
+ /* @__PURE__ */ jsx19(Button12, { variant: "danger", mini: true, disabled: busy === meeting.id, onClick: () => void run(meeting, "cancel"), children: copy.cancel })
1117
1389
  ] }) : null
1118
1390
  ] })
1119
1391
  ] }, meeting.id)),
1120
- note ? /* @__PURE__ */ jsx15("p", { role: "status", className: "muted", children: note }) : null
1392
+ note ? /* @__PURE__ */ jsx19("p", { role: "status", className: "muted", children: note }) : null
1121
1393
  ] });
1122
1394
  }
1123
1395
 
1124
1396
  // src/ui/admin-people-workspace.tsx
1125
- import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs15 } from "preact/jsx-runtime";
1126
- function applicationLifecycleAdapter(ctx, copy = DEFAULT_CHAPTER_COPY.admin.records) {
1127
- return {
1128
- transitionStage: async ({ record, to }) => {
1129
- const applicationId = typeof record.fields?.applicationId === "string" ? record.fields.applicationId : null;
1130
- if (!applicationId) {
1131
- throw new Error(copy.workflowMissing);
1132
- }
1133
- const path = `/api/admin/applications/${encodeURIComponent(applicationId)}`;
1134
- if (to === "approved") {
1135
- await adminFetch(ctx.getToken, `${path}/approve`, { method: "POST" });
1136
- } else if (to === "refunded") {
1137
- await adminFetch(ctx.getToken, `${path}/refund`, { method: "POST" });
1138
- } else {
1139
- await adminFetch(ctx.getToken, path, {
1140
- method: "PATCH",
1141
- body: JSON.stringify({ status: to })
1142
- });
1143
- }
1144
- }
1145
- };
1146
- }
1397
+ import { Fragment as Fragment11, jsx as jsx20, jsxs as jsxs19 } from "preact/jsx-runtime";
1147
1398
  function PeopleBody(props) {
1148
1399
  const copy = useChapterCopy().admin.records;
1149
1400
  const {
@@ -1154,6 +1405,7 @@ function PeopleBody(props) {
1154
1405
  roles,
1155
1406
  lifecycle,
1156
1407
  networkSharing,
1408
+ applicationStages = APPLICATION_STAGES,
1157
1409
  collapseClosedDetail,
1158
1410
  lifecycleAdapter,
1159
1411
  requireLifecycleAdapter,
@@ -1171,7 +1423,7 @@ function PeopleBody(props) {
1171
1423
  const builtInLifecycle = lifecycle ? applicationLifecycleAdapter(ctx, copy) : void 0;
1172
1424
  const resolvedLifecycle = typeof lifecycleAdapter === "function" ? lifecycleAdapter(ctx) : lifecycleAdapter ?? builtInLifecycle;
1173
1425
  const workspaceClient = client;
1174
- return /* @__PURE__ */ jsx16(AdminPage, { children: /* @__PURE__ */ jsx16(
1426
+ return /* @__PURE__ */ jsx20(AdminPage, { children: /* @__PURE__ */ jsx20(
1175
1427
  CrmWorkspace,
1176
1428
  {
1177
1429
  crm,
@@ -1187,9 +1439,9 @@ function PeopleBody(props) {
1187
1439
  collapseClosedDetail,
1188
1440
  lifecycle: resolvedLifecycle,
1189
1441
  requireLifecycleAdapter: requireLifecycleAdapter ?? lifecycle,
1190
- renderSummary: (context) => /* @__PURE__ */ jsxs15(Fragment7, { children: [
1442
+ renderSummary: (context) => /* @__PURE__ */ jsxs19(Fragment11, { children: [
1191
1443
  renderSummary?.(context, ctx),
1192
- type === "person" ? /* @__PURE__ */ jsx16(AccountPeopleSync, { getToken: ctx.getToken, refresh: context.query.refresh }) : null
1444
+ type === "person" ? /* @__PURE__ */ jsx20(AccountPeopleSync, { getToken: ctx.getToken, refresh: context.query.refresh }) : null
1193
1445
  ] }),
1194
1446
  renderMaster: renderMaster ? (context) => renderMaster(context, ctx) : void 0,
1195
1447
  renderDetailHeader: renderDetailHeader ? (context) => renderDetailHeader(context, ctx) : void 0,
@@ -1203,7 +1455,7 @@ function PeopleBody(props) {
1203
1455
  const add = (id) => {
1204
1456
  const tab = byId.get(id);
1205
1457
  if (tab && lifecycle && type === "person" && id === "profile" && !lifecycleAdapter) {
1206
- tabs.push({ ...tab, panel: /* @__PURE__ */ jsx16(
1458
+ tabs.push({ ...tab, panel: /* @__PURE__ */ jsx20(
1207
1459
  ChapterPersonProfile,
1208
1460
  {
1209
1461
  recordId: record.id,
@@ -1218,7 +1470,7 @@ function PeopleBody(props) {
1218
1470
  return;
1219
1471
  }
1220
1472
  if (tab && lifecycle && applicationId && id === "stage" && !lifecycleAdapter) {
1221
- tabs.push({ ...tab, panel: /* @__PURE__ */ jsx16(
1473
+ tabs.push({ ...tab, panel: /* @__PURE__ */ jsx20(
1222
1474
  ApplicationStagePanel,
1223
1475
  {
1224
1476
  applicationId,
@@ -1231,8 +1483,17 @@ function PeopleBody(props) {
1231
1483
  }
1232
1484
  if (tab) tabs.push(lifecycle && !applicationId && id === "stage" ? {
1233
1485
  ...tab,
1234
- panel: record.stage == null ? /* @__PURE__ */ jsx16("p", { children: "Journey stage: Not applicable. No membership application is linked. Administrative access is separate." }) : /* @__PURE__ */ jsxs15(Fragment7, { children: [
1235
- /* @__PURE__ */ jsx16(ApplicationLinkRepair, { recordId: record.id, getToken: ctx.getToken, onChanged: () => {
1486
+ panel: record.stage == null || !applicationStages.includes(record.stage) ? /* @__PURE__ */ jsx20(
1487
+ CandidateStagePanel,
1488
+ {
1489
+ stages: def.pipeline?.stages ?? [],
1490
+ current: record.stage ?? null,
1491
+ applicationStages,
1492
+ onMove: context.moveStage
1493
+ },
1494
+ record.id + record.updatedAt
1495
+ ) : /* @__PURE__ */ jsxs19(Fragment11, { children: [
1496
+ /* @__PURE__ */ jsx20(ApplicationLinkRepair, { recordId: record.id, getToken: ctx.getToken, onChanged: () => {
1236
1497
  context.refreshRecord();
1237
1498
  context.refreshList();
1238
1499
  } }, record.id),
@@ -1246,35 +1507,60 @@ function PeopleBody(props) {
1246
1507
  tabs.push({
1247
1508
  id: "comms",
1248
1509
  label: copy.comms,
1249
- panel: /* @__PURE__ */ jsx16(RecordCommsPanel, { client, recordId: record.id, getToken: ctx.getToken })
1510
+ panel: /* @__PURE__ */ jsx20(RecordCommsPanel, { client, recordId: record.id, getToken: ctx.getToken })
1250
1511
  });
1251
1512
  tabs.push({
1252
1513
  id: "history",
1253
1514
  label: copy.commsHistory,
1254
- panel: /* @__PURE__ */ jsx16(RecordCommsHistory, { client, recordId: record.id })
1515
+ panel: /* @__PURE__ */ jsx20(RecordCommsHistory, { client, recordId: record.id })
1255
1516
  });
1256
1517
  }
1257
1518
  if (lifecycle) {
1258
1519
  tabs.push({
1259
1520
  id: "scheduling",
1260
1521
  label: copy.scheduling,
1261
- panel: /* @__PURE__ */ jsx16(RecordSchedulingPanel, { getToken: ctx.getToken, applicationId })
1522
+ panel: /* @__PURE__ */ jsx20(RecordSchedulingPanel, { getToken: ctx.getToken, applicationId })
1262
1523
  });
1263
- tabs.push({ id: "billing", label: copy.billing, panel: /* @__PURE__ */ jsx16(BillingCard, { record }) });
1524
+ tabs.push({ id: "invitation", label: copy.invitation, panel: /* @__PURE__ */ jsx20(
1525
+ RecordAdmissionPanel,
1526
+ {
1527
+ getToken: ctx.getToken,
1528
+ email: record.primaryEmail ?? (typeof record.fields?.email === "string" ? record.fields.email : null),
1529
+ onChanged: () => {
1530
+ context.refreshRecord();
1531
+ context.refreshList();
1532
+ }
1533
+ }
1534
+ ) });
1535
+ tabs.push({ id: "billing", label: copy.billing, panel: /* @__PURE__ */ jsxs19(Fragment11, { children: [
1536
+ /* @__PURE__ */ jsx20(BillingCard, { record }),
1537
+ applicationId ? /* @__PURE__ */ jsx20(
1538
+ NamedSeatRecordPanel,
1539
+ {
1540
+ getToken: ctx.getToken,
1541
+ applicationId,
1542
+ superAdmin: ctx.currentUser?.superAdmin === true,
1543
+ onChanged: () => {
1544
+ context.refreshRecord();
1545
+ context.refreshList();
1546
+ }
1547
+ }
1548
+ ) : null
1549
+ ] }) });
1264
1550
  } else {
1265
1551
  add("billing");
1266
1552
  }
1267
1553
  tabs.push({
1268
1554
  id: "notes",
1269
1555
  label: copy.notes,
1270
- panel: /* @__PURE__ */ jsx16(RecordActivityPanel, { client, recordId: record.id })
1556
+ panel: /* @__PURE__ */ jsx20(RecordActivityPanel, { client, recordId: record.id })
1271
1557
  });
1272
1558
  add("connections");
1273
1559
  if (lifecycle) {
1274
1560
  tabs.push({
1275
1561
  id: "access",
1276
1562
  label: copy.access,
1277
- panel: /* @__PURE__ */ jsx16(
1563
+ panel: /* @__PURE__ */ jsx20(
1278
1564
  RecordActions,
1279
1565
  {
1280
1566
  getToken: ctx.getToken,
@@ -1293,7 +1579,7 @@ function PeopleBody(props) {
1293
1579
  tabs.push({
1294
1580
  id: "sharing",
1295
1581
  label: copy.sharing,
1296
- panel: /* @__PURE__ */ jsx16(NetworkShareActions, { recordId: record.id, recordType: record.type, getToken: ctx.getToken })
1582
+ panel: /* @__PURE__ */ jsx20(NetworkShareActions, { recordId: record.id, recordType: record.type, getToken: ctx.getToken })
1297
1583
  });
1298
1584
  }
1299
1585
  return extendRecordTabs?.(tabs, context) ?? tabs;
@@ -1303,7 +1589,7 @@ function PeopleBody(props) {
1303
1589
  }
1304
1590
 
1305
1591
  // src/ui/admin-people.tsx
1306
- import { jsx as jsx17 } from "preact/jsx-runtime";
1592
+ import { jsx as jsx21 } from "preact/jsx-runtime";
1307
1593
  var DEFAULT_ROLES = ["provisional", "member", "admin"];
1308
1594
  function collectionSection(options) {
1309
1595
  const { crm, type } = options;
@@ -1318,6 +1604,7 @@ function collectionSection(options) {
1318
1604
  lifecycle = type === "person",
1319
1605
  roles = DEFAULT_ROLES,
1320
1606
  networkSharing = false,
1607
+ applicationStages,
1321
1608
  collapseClosedDetail = true,
1322
1609
  lifecycleAdapter,
1323
1610
  requireLifecycleAdapter,
@@ -1333,7 +1620,7 @@ function collectionSection(options) {
1333
1620
  return {
1334
1621
  id,
1335
1622
  label,
1336
- render: (ctx) => /* @__PURE__ */ jsx17(
1623
+ render: (ctx) => /* @__PURE__ */ jsx21(
1337
1624
  PeopleBody,
1338
1625
  {
1339
1626
  crm,
@@ -1343,6 +1630,7 @@ function collectionSection(options) {
1343
1630
  roles,
1344
1631
  lifecycle,
1345
1632
  networkSharing,
1633
+ applicationStages,
1346
1634
  collapseClosedDetail,
1347
1635
  lifecycleAdapter,
1348
1636
  requireLifecycleAdapter,
@@ -1402,17 +1690,17 @@ function peopleSection(options) {
1402
1690
  // src/ui/admin-network-records.tsx
1403
1691
  import {
1404
1692
  DataTable as DataTable2,
1405
- Field as Field6,
1693
+ Field as Field8,
1406
1694
  MasterDetail,
1407
1695
  Pagination,
1408
- Select as Select5
1696
+ Select as Select7
1409
1697
  } from "@odla-ai/ui/components";
1410
- import { useEffect as useEffect7, useMemo, useState as useState14 } from "preact/hooks";
1698
+ import { useEffect as useEffect7, useMemo, useState as useState19 } from "preact/hooks";
1411
1699
 
1412
1700
  // src/ui/admin-network-notes.tsx
1413
- import { Button as Button8, Field as Field5, Textarea as Textarea2 } from "@odla-ai/ui/components";
1414
- import { useState as useState13 } from "preact/hooks";
1415
- import { jsx as jsx18, jsxs as jsxs16 } from "preact/jsx-runtime";
1701
+ import { Button as Button13, Field as Field7, Textarea as Textarea2 } from "@odla-ai/ui/components";
1702
+ import { useState as useState18 } from "preact/hooks";
1703
+ import { jsx as jsx22, jsxs as jsxs20 } from "preact/jsx-runtime";
1416
1704
  function displayValue(value) {
1417
1705
  if (Array.isArray(value)) return value.join(", ");
1418
1706
  if (value && typeof value === "object") return JSON.stringify(value);
@@ -1427,9 +1715,9 @@ function PrivateNotes(props) {
1427
1715
  });
1428
1716
  const path = `/api/admin/network/notes?${query}`;
1429
1717
  const notes = useAdminResource(ctx.getToken, path);
1430
- const [body, setBody] = useState13("");
1431
- const [busy, setBusy] = useState13(false);
1432
- const [error, setError] = useState13(null);
1718
+ const [body, setBody] = useState18("");
1719
+ const [busy, setBusy] = useState18(false);
1720
+ const [error, setError] = useState18(null);
1433
1721
  const submit = async () => {
1434
1722
  const trimmed = body.trim();
1435
1723
  if (!trimmed) return;
@@ -1448,18 +1736,18 @@ function PrivateNotes(props) {
1448
1736
  setBusy(false);
1449
1737
  }
1450
1738
  };
1451
- return /* @__PURE__ */ jsxs16("section", { style: { display: "grid", gap: 12 }, children: [
1452
- /* @__PURE__ */ jsxs16("h3", { style: { margin: "8px 0 0" }, children: [
1739
+ return /* @__PURE__ */ jsxs20("section", { style: { display: "grid", gap: 12 }, children: [
1740
+ /* @__PURE__ */ jsxs20("h3", { style: { margin: "8px 0 0" }, children: [
1453
1741
  "Private to ",
1454
1742
  leaderName
1455
1743
  ] }),
1456
- /* @__PURE__ */ jsx18(
1457
- Field5,
1744
+ /* @__PURE__ */ jsx22(
1745
+ Field7,
1458
1746
  {
1459
1747
  label: "Add a note",
1460
1748
  hint: `Visible only to ${leaderName} admins. Nothing is written back to the follower.`,
1461
1749
  error,
1462
- children: /* @__PURE__ */ jsx18(
1750
+ children: /* @__PURE__ */ jsx22(
1463
1751
  Textarea2,
1464
1752
  {
1465
1753
  rows: 4,
@@ -1470,13 +1758,13 @@ function PrivateNotes(props) {
1470
1758
  )
1471
1759
  }
1472
1760
  ),
1473
- /* @__PURE__ */ jsx18("div", { children: /* @__PURE__ */ jsx18(Button8, { disabled: busy || !body.trim(), onClick: () => void submit(), children: busy ? "Saving\u2026" : "Save note" }) }),
1474
- notes.loading ? /* @__PURE__ */ jsx18("p", { className: "muted", children: "Loading notes\u2026" }) : null,
1475
- notes.error ? /* @__PURE__ */ jsx18("p", { role: "alert", children: notes.error }) : null,
1476
- !notes.loading && !notes.error && (notes.data?.notes.length ?? 0) === 0 ? /* @__PURE__ */ jsx18("p", { className: "muted", children: "No notes yet." }) : null,
1477
- (notes.data?.notes ?? []).map((note) => /* @__PURE__ */ jsxs16("article", { className: "panel", style: { padding: 14 }, children: [
1478
- /* @__PURE__ */ jsx18("p", { style: { margin: 0, whiteSpace: "pre-wrap" }, children: note.body }),
1479
- /* @__PURE__ */ jsxs16("p", { className: "muted", style: { margin: "8px 0 0", fontSize: 12 }, children: [
1761
+ /* @__PURE__ */ jsx22("div", { children: /* @__PURE__ */ jsx22(Button13, { disabled: busy || !body.trim(), onClick: () => void submit(), children: busy ? "Saving\u2026" : "Save note" }) }),
1762
+ notes.loading ? /* @__PURE__ */ jsx22("p", { className: "muted", children: "Loading notes\u2026" }) : null,
1763
+ notes.error ? /* @__PURE__ */ jsx22("p", { role: "alert", children: notes.error }) : null,
1764
+ !notes.loading && !notes.error && (notes.data?.notes.length ?? 0) === 0 ? /* @__PURE__ */ jsx22("p", { className: "muted", children: "No notes yet." }) : null,
1765
+ (notes.data?.notes ?? []).map((note) => /* @__PURE__ */ jsxs20("article", { className: "panel", style: { padding: 14 }, children: [
1766
+ /* @__PURE__ */ jsx22("p", { style: { margin: 0, whiteSpace: "pre-wrap" }, children: note.body }),
1767
+ /* @__PURE__ */ jsxs20("p", { className: "muted", style: { margin: "8px 0 0", fontSize: 12 }, children: [
1480
1768
  note.authorEmail ?? note.authorId,
1481
1769
  " \xB7 ",
1482
1770
  new Date(note.createdAt).toLocaleString()
@@ -1493,9 +1781,9 @@ function SharedNotes(props) {
1493
1781
  });
1494
1782
  const path = `/api/admin/network/shared-notes?${query}`;
1495
1783
  const notes = useAdminResource(ctx.getToken, path);
1496
- const [body, setBody] = useState13("");
1497
- const [busy, setBusy] = useState13(false);
1498
- const [error, setError] = useState13(null);
1784
+ const [body, setBody] = useState18("");
1785
+ const [busy, setBusy] = useState18(false);
1786
+ const [error, setError] = useState18(null);
1499
1787
  const submit = async () => {
1500
1788
  const trimmed = body.trim();
1501
1789
  if (!trimmed) return;
@@ -1514,18 +1802,18 @@ function SharedNotes(props) {
1514
1802
  setBusy(false);
1515
1803
  }
1516
1804
  };
1517
- return /* @__PURE__ */ jsxs16("section", { style: { display: "grid", gap: 12 }, children: [
1518
- /* @__PURE__ */ jsxs16("h3", { style: { margin: "8px 0 0" }, children: [
1805
+ return /* @__PURE__ */ jsxs20("section", { style: { display: "grid", gap: 12 }, children: [
1806
+ /* @__PURE__ */ jsxs20("h3", { style: { margin: "8px 0 0" }, children: [
1519
1807
  "Shared with ",
1520
1808
  targetName
1521
1809
  ] }),
1522
- /* @__PURE__ */ jsx18(
1523
- Field5,
1810
+ /* @__PURE__ */ jsx22(
1811
+ Field7,
1524
1812
  {
1525
1813
  label: "Add a shared note",
1526
1814
  hint: `This is written to the record's Notes feed for ${targetName} admins.`,
1527
1815
  error,
1528
- children: /* @__PURE__ */ jsx18(
1816
+ children: /* @__PURE__ */ jsx22(
1529
1817
  Textarea2,
1530
1818
  {
1531
1819
  rows: 4,
@@ -1536,13 +1824,13 @@ function SharedNotes(props) {
1536
1824
  )
1537
1825
  }
1538
1826
  ),
1539
- /* @__PURE__ */ jsx18("div", { children: /* @__PURE__ */ jsx18(Button8, { disabled: busy || !body.trim(), onClick: () => void submit(), children: busy ? "Sharing\u2026" : `Share with ${targetName}` }) }),
1540
- notes.loading ? /* @__PURE__ */ jsx18("p", { className: "muted", children: "Loading shared notes\u2026" }) : null,
1541
- notes.error ? /* @__PURE__ */ jsx18("p", { role: "alert", children: notes.error }) : null,
1542
- !notes.loading && !notes.error && (notes.data?.notes.length ?? 0) === 0 ? /* @__PURE__ */ jsx18("p", { className: "muted", children: "No shared notes yet." }) : null,
1543
- (notes.data?.notes ?? []).map((note) => /* @__PURE__ */ jsxs16("article", { className: "panel", style: { padding: 14 }, children: [
1544
- /* @__PURE__ */ jsx18("p", { style: { margin: 0, whiteSpace: "pre-wrap" }, children: note.body }),
1545
- /* @__PURE__ */ jsxs16("p", { className: "muted", style: { margin: "8px 0 0", fontSize: 12 }, children: [
1827
+ /* @__PURE__ */ jsx22("div", { children: /* @__PURE__ */ jsx22(Button13, { disabled: busy || !body.trim(), onClick: () => void submit(), children: busy ? "Sharing\u2026" : `Share with ${targetName}` }) }),
1828
+ notes.loading ? /* @__PURE__ */ jsx22("p", { className: "muted", children: "Loading shared notes\u2026" }) : null,
1829
+ notes.error ? /* @__PURE__ */ jsx22("p", { role: "alert", children: notes.error }) : null,
1830
+ !notes.loading && !notes.error && (notes.data?.notes.length ?? 0) === 0 ? /* @__PURE__ */ jsx22("p", { className: "muted", children: "No shared notes yet." }) : null,
1831
+ (notes.data?.notes ?? []).map((note) => /* @__PURE__ */ jsxs20("article", { className: "panel", style: { padding: 14 }, children: [
1832
+ /* @__PURE__ */ jsx22("p", { style: { margin: 0, whiteSpace: "pre-wrap" }, children: note.body }),
1833
+ /* @__PURE__ */ jsxs20("p", { className: "muted", style: { margin: "8px 0 0", fontSize: 12 }, children: [
1546
1834
  "Shared with ",
1547
1835
  targetName,
1548
1836
  " \xB7 ",
@@ -1553,23 +1841,23 @@ function SharedNotes(props) {
1553
1841
  }
1554
1842
  function NetworkRecordDetail(props) {
1555
1843
  const { ctx, targetId, targetName, leaderName, sharedEnabled, record } = props;
1556
- return /* @__PURE__ */ jsxs16("div", { style: { display: "grid", gap: 14 }, children: [
1557
- /* @__PURE__ */ jsxs16("header", { children: [
1558
- /* @__PURE__ */ jsx18("h2", { style: { margin: 0 }, children: record.name }),
1559
- record.stage ? /* @__PURE__ */ jsx18("span", { className: "badge", style: { marginTop: 8 }, children: record.stage.replaceAll("_", " ") }) : null
1844
+ return /* @__PURE__ */ jsxs20("div", { style: { display: "grid", gap: 14 }, children: [
1845
+ /* @__PURE__ */ jsxs20("header", { children: [
1846
+ /* @__PURE__ */ jsx22("h2", { style: { margin: 0 }, children: record.name }),
1847
+ record.stage ? /* @__PURE__ */ jsx22("span", { className: "badge", style: { marginTop: 8 }, children: record.stage.replaceAll("_", " ") }) : null
1560
1848
  ] }),
1561
- /* @__PURE__ */ jsxs16("dl", { style: { display: "grid", gridTemplateColumns: "minmax(8rem, auto) 1fr", gap: "8px 16px", margin: 0 }, children: [
1562
- Object.entries(record.fields).map(([name, value]) => /* @__PURE__ */ jsxs16("div", { style: { display: "contents" }, children: [
1563
- /* @__PURE__ */ jsx18("dt", { className: "muted", children: name.replaceAll("_", " ") }),
1564
- /* @__PURE__ */ jsx18("dd", { style: { margin: 0, overflowWrap: "anywhere" }, children: displayValue(value) })
1849
+ /* @__PURE__ */ jsxs20("dl", { style: { display: "grid", gridTemplateColumns: "minmax(8rem, auto) 1fr", gap: "8px 16px", margin: 0 }, children: [
1850
+ Object.entries(record.fields).map(([name, value]) => /* @__PURE__ */ jsxs20("div", { style: { display: "contents" }, children: [
1851
+ /* @__PURE__ */ jsx22("dt", { className: "muted", children: name.replaceAll("_", " ") }),
1852
+ /* @__PURE__ */ jsx22("dd", { style: { margin: 0, overflowWrap: "anywhere" }, children: displayValue(value) })
1565
1853
  ] }, name)),
1566
- /* @__PURE__ */ jsxs16("div", { style: { display: "contents" }, children: [
1567
- /* @__PURE__ */ jsx18("dt", { className: "muted", children: "Updated" }),
1568
- /* @__PURE__ */ jsx18("dd", { style: { margin: 0 }, children: new Date(record.updatedAt).toLocaleString() })
1854
+ /* @__PURE__ */ jsxs20("div", { style: { display: "contents" }, children: [
1855
+ /* @__PURE__ */ jsx22("dt", { className: "muted", children: "Updated" }),
1856
+ /* @__PURE__ */ jsx22("dd", { style: { margin: 0 }, children: new Date(record.updatedAt).toLocaleString() })
1569
1857
  ] })
1570
1858
  ] }),
1571
- /* @__PURE__ */ jsxs16("div", { style: { display: "grid", gap: 22 }, children: [
1572
- /* @__PURE__ */ jsx18(
1859
+ /* @__PURE__ */ jsxs20("div", { style: { display: "grid", gap: 22 }, children: [
1860
+ /* @__PURE__ */ jsx22(
1573
1861
  PrivateNotes,
1574
1862
  {
1575
1863
  ctx,
@@ -1578,7 +1866,7 @@ function NetworkRecordDetail(props) {
1578
1866
  leaderName
1579
1867
  }
1580
1868
  ),
1581
- sharedEnabled ? /* @__PURE__ */ jsx18(
1869
+ sharedEnabled ? /* @__PURE__ */ jsx22(
1582
1870
  SharedNotes,
1583
1871
  {
1584
1872
  ctx,
@@ -1592,11 +1880,11 @@ function NetworkRecordDetail(props) {
1592
1880
  }
1593
1881
 
1594
1882
  // src/ui/admin-network-records.tsx
1595
- import { jsx as jsx19, jsxs as jsxs17 } from "preact/jsx-runtime";
1883
+ import { jsx as jsx23, jsxs as jsxs21 } from "preact/jsx-runtime";
1596
1884
  function RecordsExplorer(props) {
1597
1885
  const { ctx, target, type, leaderName } = props;
1598
- const [offset, setOffset] = useState14(0);
1599
- const [search, setSearch] = useState14("");
1886
+ const [offset, setOffset] = useState19(0);
1887
+ const [search, setSearch] = useState19("");
1600
1888
  const query = new URLSearchParams({
1601
1889
  targetId: target.id,
1602
1890
  type,
@@ -1609,16 +1897,16 @@ function RecordsExplorer(props) {
1609
1897
  `/api/admin/network/records?${query}`
1610
1898
  );
1611
1899
  const selected = page.data?.records.find((record) => record.id === ctx.route.recordId);
1612
- const columns2 = useMemo(() => [
1900
+ const columns3 = useMemo(() => [
1613
1901
  {
1614
1902
  key: "name",
1615
1903
  header: "Name",
1616
- cell: (record) => /* @__PURE__ */ jsx19("a", { href: ctx.href({ recordId: record.id, detailTab: null }), children: record.name })
1904
+ cell: (record) => /* @__PURE__ */ jsx23("a", { href: ctx.href({ recordId: record.id, detailTab: null }), children: record.name })
1617
1905
  },
1618
1906
  {
1619
1907
  key: "stage",
1620
1908
  header: "Stage",
1621
- cell: (record) => record.stage ? /* @__PURE__ */ jsx19("span", { className: "badge", children: record.stage.replaceAll("_", " ") }) : "\u2014"
1909
+ cell: (record) => record.stage ? /* @__PURE__ */ jsx23("span", { className: "badge", children: record.stage.replaceAll("_", " ") }) : "\u2014"
1622
1910
  },
1623
1911
  {
1624
1912
  key: "updatedAt",
@@ -1626,7 +1914,7 @@ function RecordsExplorer(props) {
1626
1914
  cell: (record) => new Date(record.updatedAt).toLocaleDateString()
1627
1915
  }
1628
1916
  ], [ctx]);
1629
- return /* @__PURE__ */ jsx19(
1917
+ return /* @__PURE__ */ jsx23(
1630
1918
  MasterDetail,
1631
1919
  {
1632
1920
  collapseClosedDetail: true,
@@ -1634,13 +1922,13 @@ function RecordsExplorer(props) {
1634
1922
  detailLabel: "Follower record details, private notes, and shared notes",
1635
1923
  detailOpen: Boolean(selected),
1636
1924
  closeHref: ctx.href({ recordId: null, detailTab: null }),
1637
- master: /* @__PURE__ */ jsxs17("div", { style: { display: "grid", gap: 14, padding: "var(--ui-space-4)" }, children: [
1638
- /* @__PURE__ */ jsxs17("h2", { style: { margin: 0, fontSize: 18 }, children: [
1925
+ master: /* @__PURE__ */ jsxs21("div", { style: { display: "grid", gap: 14, padding: "var(--ui-space-4)" }, children: [
1926
+ /* @__PURE__ */ jsxs21("h2", { style: { margin: 0, fontSize: 18 }, children: [
1639
1927
  target.name,
1640
1928
  " \xB7 ",
1641
1929
  type.replaceAll("_", " ")
1642
1930
  ] }),
1643
- /* @__PURE__ */ jsx19(
1931
+ /* @__PURE__ */ jsx23(
1644
1932
  DataTable2,
1645
1933
  {
1646
1934
  manual: true,
@@ -1653,14 +1941,14 @@ function RecordsExplorer(props) {
1653
1941
  ctx.navigate({ recordId: null, detailTab: null });
1654
1942
  },
1655
1943
  rows: page.data?.records ?? [],
1656
- columns: columns2,
1944
+ columns: columns3,
1657
1945
  rowKey: (record) => record.id,
1658
1946
  loading: page.loading,
1659
1947
  emptyState: page.error ? `Could not load records: ${page.error}` : "No records found.",
1660
1948
  ariaLabel: `${target.name} ${type} records`
1661
1949
  }
1662
1950
  ),
1663
- /* @__PURE__ */ jsx19(
1951
+ /* @__PURE__ */ jsx23(
1664
1952
  Pagination,
1665
1953
  {
1666
1954
  offset: page.data?.offset ?? offset,
@@ -1675,7 +1963,7 @@ function RecordsExplorer(props) {
1675
1963
  }
1676
1964
  )
1677
1965
  ] }),
1678
- detail: selected ? /* @__PURE__ */ jsx19(
1966
+ detail: selected ? /* @__PURE__ */ jsx23(
1679
1967
  NetworkRecordDetail,
1680
1968
  {
1681
1969
  ctx,
@@ -1692,8 +1980,8 @@ function RecordsExplorer(props) {
1692
1980
  function NetworkRecordsWorkspace(props) {
1693
1981
  const { chapter, ctx } = props;
1694
1982
  const targets = useAdminResource(ctx.getToken, "/api/admin/network/targets");
1695
- const [targetId, setTargetId] = useState14("");
1696
- const [type, setType] = useState14("");
1983
+ const [targetId, setTargetId] = useState19("");
1984
+ const [type, setType] = useState19("");
1697
1985
  const target = targets.data?.targets.find((candidate) => candidate.id === targetId) ?? targets.data?.targets[0];
1698
1986
  useEffect7(() => {
1699
1987
  if (target && target.id !== targetId) setTargetId(target.id);
@@ -1702,17 +1990,17 @@ function NetworkRecordsWorkspace(props) {
1702
1990
  const first = target?.types[0] ?? "";
1703
1991
  if (target && !target.types.includes(type)) setType(first);
1704
1992
  }, [target, type]);
1705
- if (targets.loading) return /* @__PURE__ */ jsx19(AdminNote, { children: "Loading follower records\u2026" });
1706
- if (targets.error || !targets.data) return /* @__PURE__ */ jsxs17(AdminNote, { children: [
1993
+ if (targets.loading) return /* @__PURE__ */ jsx23(AdminNote, { children: "Loading follower records\u2026" });
1994
+ if (targets.error || !targets.data) return /* @__PURE__ */ jsxs21(AdminNote, { children: [
1707
1995
  "Could not load followers",
1708
1996
  targets.error ? `: ${targets.error}` : "",
1709
1997
  "."
1710
1998
  ] });
1711
- if (!target) return /* @__PURE__ */ jsx19(AdminPage, { children: /* @__PURE__ */ jsx19(Panel, { title: "Follower records", children: /* @__PURE__ */ jsx19("p", { className: "muted", children: "No followers are configured." }) }) });
1712
- return /* @__PURE__ */ jsxs17(AdminPage, { children: [
1713
- /* @__PURE__ */ jsxs17("div", { style: { display: "flex", gap: 12, flexWrap: "wrap", alignItems: "end" }, children: [
1714
- /* @__PURE__ */ jsx19(Field6, { label: "Chapter", style: { minWidth: 240 }, children: /* @__PURE__ */ jsx19(
1715
- Select5,
1999
+ if (!target) return /* @__PURE__ */ jsx23(AdminPage, { children: /* @__PURE__ */ jsx23(Panel, { title: "Follower records", children: /* @__PURE__ */ jsx23("p", { className: "muted", children: "No followers are configured." }) }) });
2000
+ return /* @__PURE__ */ jsxs21(AdminPage, { children: [
2001
+ /* @__PURE__ */ jsxs21("div", { style: { display: "flex", gap: 12, flexWrap: "wrap", alignItems: "end" }, children: [
2002
+ /* @__PURE__ */ jsx23(Field8, { label: "Chapter", style: { minWidth: 240 }, children: /* @__PURE__ */ jsx23(
2003
+ Select7,
1716
2004
  {
1717
2005
  value: target.id,
1718
2006
  options: targets.data.targets.map((item) => ({ value: item.id, label: item.name })),
@@ -1723,8 +2011,8 @@ function NetworkRecordsWorkspace(props) {
1723
2011
  }
1724
2012
  }
1725
2013
  ) }),
1726
- /* @__PURE__ */ jsx19(Field6, { label: "Record type", style: { minWidth: 180 }, children: /* @__PURE__ */ jsx19(
1727
- Select5,
2014
+ /* @__PURE__ */ jsx23(Field8, { label: "Record type", style: { minWidth: 180 }, children: /* @__PURE__ */ jsx23(
2015
+ Select7,
1728
2016
  {
1729
2017
  value: type,
1730
2018
  options: target.types.map((item) => ({ value: item, label: item.replaceAll("_", " ") })),
@@ -1735,7 +2023,7 @@ function NetworkRecordsWorkspace(props) {
1735
2023
  }
1736
2024
  ) })
1737
2025
  ] }),
1738
- type ? /* @__PURE__ */ jsx19(
2026
+ type ? /* @__PURE__ */ jsx23(
1739
2027
  RecordsExplorer,
1740
2028
  {
1741
2029
  ctx,
@@ -1744,7 +2032,7 @@ function NetworkRecordsWorkspace(props) {
1744
2032
  leaderName: chapter.name
1745
2033
  },
1746
2034
  `${target.id}:${type}`
1747
- ) : /* @__PURE__ */ jsx19(Panel, { children: /* @__PURE__ */ jsx19("p", { className: "muted", children: "This follower has no browsable record types configured." }) })
2035
+ ) : /* @__PURE__ */ jsx23(Panel, { children: /* @__PURE__ */ jsx23("p", { className: "muted", children: "This follower has no browsable record types configured." }) })
1748
2036
  ] });
1749
2037
  }
1750
2038
  function networkRecordsWorkspace(chapter) {
@@ -1752,63 +2040,63 @@ function networkRecordsWorkspace(chapter) {
1752
2040
  id: "network",
1753
2041
  label: chapter.copy.admin.workspaces.network,
1754
2042
  defaultViewId: "records",
1755
- render: (ctx) => /* @__PURE__ */ jsx19(NetworkRecordsWorkspace, { chapter, ctx })
2043
+ render: (ctx) => /* @__PURE__ */ jsx23(NetworkRecordsWorkspace, { chapter, ctx })
1756
2044
  };
1757
2045
  }
1758
2046
 
1759
2047
  // src/ui/admin-portfolio.tsx
1760
2048
  import { StatBand as StatBand2, StepPipeline as StepPipeline2 } from "@odla-ai/ui/components";
1761
- import { jsx as jsx20, jsxs as jsxs18 } from "preact/jsx-runtime";
2049
+ import { jsx as jsx24, jsxs as jsxs22 } from "preact/jsx-runtime";
1762
2050
  function LeaderNetworkOverview({ ctx }) {
1763
2051
  const copy = useChapterCopy().admin.network;
1764
2052
  const { data, loading, error } = useAdminResource(
1765
2053
  ctx.getToken,
1766
2054
  "/api/admin/network/rollup"
1767
2055
  );
1768
- if (loading) return /* @__PURE__ */ jsx20(AdminNote, { children: copy.loadingRollup });
1769
- if (error || !data) return /* @__PURE__ */ jsxs18(AdminNote, { children: [
2056
+ if (loading) return /* @__PURE__ */ jsx24(AdminNote, { children: copy.loadingRollup });
2057
+ if (error || !data) return /* @__PURE__ */ jsxs22(AdminNote, { children: [
1770
2058
  copy.loadRollupFailed,
1771
2059
  error ? `: ${error}` : "",
1772
2060
  "."
1773
2061
  ] });
1774
- if (data.configured === 0) return /* @__PURE__ */ jsx20(AdminPage, { children: /* @__PURE__ */ jsx20(Panel, { title: copy.overview, children: /* @__PURE__ */ jsx20("p", { className: "muted", children: copy.noFollowers }) }) });
2062
+ if (data.configured === 0) return /* @__PURE__ */ jsx24(AdminPage, { children: /* @__PURE__ */ jsx24(Panel, { title: copy.overview, children: /* @__PURE__ */ jsx24("p", { className: "muted", children: copy.noFollowers }) }) });
1775
2063
  const stats = [
1776
2064
  { value: data.configured.toLocaleString(), label: copy.configuredFollowers },
1777
2065
  { value: data.available.toLocaleString(), label: copy.reachableFollowers },
1778
2066
  { value: data.totalRecords.toLocaleString(), label: copy.recordsAcrossFollowers }
1779
2067
  ];
1780
2068
  const steps = data.types.map((type) => ({
1781
- icon: /* @__PURE__ */ jsx20("span", { style: { fontSize: 22, fontWeight: 700 }, children: type.total }),
2069
+ icon: /* @__PURE__ */ jsx24("span", { style: { fontSize: 22, fontWeight: 700 }, children: type.total }),
1782
2070
  title: type.type.replaceAll("_", " "),
1783
2071
  description: Object.entries(type.stages).filter(([, count]) => count > 0).map(([stage, count]) => `${stage.replaceAll("_", " ")} ${count}`).join(" \xB7 ") || copy.noRecordTotals
1784
2072
  }));
1785
- return /* @__PURE__ */ jsxs18(AdminPage, { children: [
1786
- /* @__PURE__ */ jsx20(StatBand2, { stats }),
1787
- /* @__PURE__ */ jsx20(Panel, { title: copy.followers, children: /* @__PURE__ */ jsx20("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "grid", gap: 10 }, children: data.targets.map((target) => /* @__PURE__ */ jsxs18("li", { style: { display: "flex", gap: 12, alignItems: "baseline", flexWrap: "wrap" }, children: [
1788
- /* @__PURE__ */ jsx20("strong", { style: { minWidth: 180 }, children: target.name }),
1789
- /* @__PURE__ */ jsx20("span", { className: "badge", children: target.transport.reachable === null ? copy.transportNotChecked : target.transport.reachable ? copy.transportReachable : copy.transportUnavailable }),
1790
- /* @__PURE__ */ jsx20("span", { className: "muted", children: target.transport.kind === "binding" ? formatChapterCopy(copy.bindingTransport, { binding: target.transport.binding ?? "" }) : copy.urlTransport }),
1791
- /* @__PURE__ */ jsx20("span", { className: "muted", children: target.configuration.activeRevision === null ? copy.noActiveConfiguration : formatChapterCopy(copy.activeConfiguration, { revision: target.configuration.activeRevision }) }),
1792
- /* @__PURE__ */ jsx20("span", { className: "muted", children: target.publicSite.available === null ? copy.publicSiteNotChecked : target.publicSite.available ? copy.publicSiteAvailable : copy.publicSiteUnavailable }),
1793
- target.error ? /* @__PURE__ */ jsx20("span", { className: "muted", children: target.error }) : null,
1794
- /* @__PURE__ */ jsx20("a", { href: target.url, target: "_blank", rel: "noreferrer", style: { marginLeft: "auto" }, children: target.url })
2073
+ return /* @__PURE__ */ jsxs22(AdminPage, { children: [
2074
+ /* @__PURE__ */ jsx24(StatBand2, { stats }),
2075
+ /* @__PURE__ */ jsx24(Panel, { title: copy.followers, children: /* @__PURE__ */ jsx24("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "grid", gap: 10 }, children: data.targets.map((target) => /* @__PURE__ */ jsxs22("li", { style: { display: "flex", gap: 12, alignItems: "baseline", flexWrap: "wrap" }, children: [
2076
+ /* @__PURE__ */ jsx24("strong", { style: { minWidth: 180 }, children: target.name }),
2077
+ /* @__PURE__ */ jsx24("span", { className: "badge", children: target.transport.reachable === null ? copy.transportNotChecked : target.transport.reachable ? copy.transportReachable : copy.transportUnavailable }),
2078
+ /* @__PURE__ */ jsx24("span", { className: "muted", children: target.transport.kind === "binding" ? formatChapterCopy(copy.bindingTransport, { binding: target.transport.binding ?? "" }) : copy.urlTransport }),
2079
+ /* @__PURE__ */ jsx24("span", { className: "muted", children: target.configuration.activeRevision === null ? copy.noActiveConfiguration : formatChapterCopy(copy.activeConfiguration, { revision: target.configuration.activeRevision }) }),
2080
+ /* @__PURE__ */ jsx24("span", { className: "muted", children: target.publicSite.available === null ? copy.publicSiteNotChecked : target.publicSite.available ? copy.publicSiteAvailable : copy.publicSiteUnavailable }),
2081
+ target.error ? /* @__PURE__ */ jsx24("span", { className: "muted", children: target.error }) : null,
2082
+ /* @__PURE__ */ jsx24("a", { href: target.url, target: "_blank", rel: "noreferrer", style: { marginLeft: "auto" }, children: target.url })
1795
2083
  ] }, target.id)) }) }),
1796
- /* @__PURE__ */ jsx20(Panel, { title: copy.recordTotals, children: steps.length ? /* @__PURE__ */ jsx20(StepPipeline2, { ariaLabel: copy.recordTotals, steps }) : /* @__PURE__ */ jsx20("p", { className: "muted", children: copy.noRecordTotals }) })
2084
+ /* @__PURE__ */ jsx24(Panel, { title: copy.recordTotals, children: steps.length ? /* @__PURE__ */ jsx24(StepPipeline2, { ariaLabel: copy.recordTotals, steps }) : /* @__PURE__ */ jsx24("p", { className: "muted", children: copy.noRecordTotals }) })
1797
2085
  ] });
1798
2086
  }
1799
2087
 
1800
2088
  // src/ui/admin-admission.tsx
1801
- import { useEffect as useEffect8, useRef as useRef2, useState as useState15 } from "preact/hooks";
1802
- import { jsx as jsx21, jsxs as jsxs19 } from "preact/jsx-runtime";
2089
+ import { useEffect as useEffect8, useRef as useRef2, useState as useState20 } from "preact/hooks";
2090
+ import { jsx as jsx25, jsxs as jsxs23 } from "preact/jsx-runtime";
1803
2091
  function AdmissionGrantsWorkspace(props) {
1804
2092
  const copy = useChapterCopy().admin.admission;
1805
2093
  const resource = useAdminResource(props.getToken, "/api/admin/admission-grants");
1806
- const [email, setEmail] = useState15("");
1807
- const [decision, setDecision] = useState15("waive_interview");
1808
- const [note, setNote] = useState15("");
1809
- const [expires, setExpires] = useState15("");
1810
- const [busy, setBusy] = useState15(false);
1811
- const [error, setError] = useState15(null);
2094
+ const [email, setEmail] = useState20("");
2095
+ const [decision, setDecision] = useState20("waive_interview");
2096
+ const [note, setNote] = useState20("");
2097
+ const [expires, setExpires] = useState20("");
2098
+ const [busy, setBusy] = useState20(false);
2099
+ const [error, setError] = useState20(null);
1812
2100
  const submit = async (event) => {
1813
2101
  event.preventDefault();
1814
2102
  setBusy(true);
@@ -1845,48 +2133,48 @@ function AdmissionGrantsWorkspace(props) {
1845
2133
  setBusy(false);
1846
2134
  }
1847
2135
  };
1848
- return /* @__PURE__ */ jsxs19(AdminPage, { children: [
1849
- /* @__PURE__ */ jsxs19(Panel, { title: copy.title, children: [
1850
- /* @__PURE__ */ jsx21("p", { className: "muted", style: { margin: 0 }, children: copy.description }),
1851
- /* @__PURE__ */ jsxs19("form", { onSubmit: (event) => void submit(event), style: { display: "grid", gap: 12, gridTemplateColumns: "minmax(220px,2fr) minmax(180px,1fr) minmax(160px,1fr)" }, children: [
1852
- /* @__PURE__ */ jsxs19("label", { children: [
2136
+ return /* @__PURE__ */ jsxs23(AdminPage, { children: [
2137
+ /* @__PURE__ */ jsxs23(Panel, { title: copy.title, children: [
2138
+ /* @__PURE__ */ jsx25("p", { className: "muted", style: { margin: 0 }, children: copy.description }),
2139
+ /* @__PURE__ */ jsxs23("form", { onSubmit: (event) => void submit(event), style: { display: "grid", gap: 12, gridTemplateColumns: "minmax(220px,2fr) minmax(180px,1fr) minmax(160px,1fr)" }, children: [
2140
+ /* @__PURE__ */ jsxs23("label", { children: [
1853
2141
  copy.email,
1854
- /* @__PURE__ */ jsx21("input", { required: true, type: "email", value: email, onInput: (event) => setEmail(event.currentTarget.value) })
2142
+ /* @__PURE__ */ jsx25("input", { required: true, type: "email", value: email, onInput: (event) => setEmail(event.currentTarget.value) })
1855
2143
  ] }),
1856
- /* @__PURE__ */ jsxs19("label", { children: [
2144
+ /* @__PURE__ */ jsxs23("label", { children: [
1857
2145
  copy.decision,
1858
- /* @__PURE__ */ jsxs19("select", { value: decision, onChange: (event) => setDecision(event.currentTarget.value), children: [
1859
- /* @__PURE__ */ jsx21("option", { value: "waive_interview", children: copy.waive }),
1860
- /* @__PURE__ */ jsx21("option", { value: "require_interview", children: copy.require })
2146
+ /* @__PURE__ */ jsxs23("select", { value: decision, onChange: (event) => setDecision(event.currentTarget.value), children: [
2147
+ /* @__PURE__ */ jsx25("option", { value: "waive_interview", children: copy.waive }),
2148
+ /* @__PURE__ */ jsx25("option", { value: "require_interview", children: copy.require })
1861
2149
  ] })
1862
2150
  ] }),
1863
- /* @__PURE__ */ jsxs19("label", { children: [
2151
+ /* @__PURE__ */ jsxs23("label", { children: [
1864
2152
  copy.expires,
1865
- /* @__PURE__ */ jsx21("input", { type: "date", value: expires, onInput: (event) => setExpires(event.currentTarget.value) })
2153
+ /* @__PURE__ */ jsx25("input", { type: "date", value: expires, onInput: (event) => setExpires(event.currentTarget.value) })
1866
2154
  ] }),
1867
- /* @__PURE__ */ jsxs19("label", { style: { gridColumn: "1 / -1" }, children: [
2155
+ /* @__PURE__ */ jsxs23("label", { style: { gridColumn: "1 / -1" }, children: [
1868
2156
  copy.note,
1869
- /* @__PURE__ */ jsx21("input", { value: note, maxLength: 2e3, onInput: (event) => setNote(event.currentTarget.value) })
2157
+ /* @__PURE__ */ jsx25("input", { value: note, maxLength: 2e3, onInput: (event) => setNote(event.currentTarget.value) })
1870
2158
  ] }),
1871
- /* @__PURE__ */ jsx21("button", { className: "btn secondary", type: "submit", disabled: busy, children: copy.add })
2159
+ /* @__PURE__ */ jsx25("button", { className: "btn secondary", type: "submit", disabled: busy, children: copy.add })
1872
2160
  ] }),
1873
- error ? /* @__PURE__ */ jsx21("p", { role: "alert", children: error }) : null
2161
+ error ? /* @__PURE__ */ jsx25("p", { role: "alert", children: error }) : null
1874
2162
  ] }),
1875
- /* @__PURE__ */ jsxs19(Panel, { title: copy.ledger, children: [
1876
- resource.loading ? /* @__PURE__ */ jsx21("p", { className: "muted", children: copy.loading }) : resource.error ? /* @__PURE__ */ jsx21("p", { role: "alert", children: resource.error }) : null,
1877
- /* @__PURE__ */ jsx21("div", { style: { display: "grid", gap: 10 }, children: (resource.data?.grants ?? []).map((grant) => {
2163
+ /* @__PURE__ */ jsxs23(Panel, { title: copy.ledger, children: [
2164
+ resource.loading ? /* @__PURE__ */ jsx25("p", { className: "muted", children: copy.loading }) : resource.error ? /* @__PURE__ */ jsx25("p", { role: "alert", children: resource.error }) : null,
2165
+ /* @__PURE__ */ jsx25("div", { style: { display: "grid", gap: 10 }, children: (resource.data?.grants ?? []).map((grant) => {
1878
2166
  const state = grant.consumedAt ? copy.consumed : grant.revokedAt || !grant.active ? copy.revoked : grant.expiresAt && grant.expiresAt <= Date.now() ? copy.expired : copy.active;
1879
- return /* @__PURE__ */ jsxs19("article", { className: "card", style: { padding: 14 }, children: [
1880
- /* @__PURE__ */ jsx21("strong", { children: grant.email }),
2167
+ return /* @__PURE__ */ jsxs23("article", { className: "card", style: { padding: 14 }, children: [
2168
+ /* @__PURE__ */ jsx25("strong", { children: grant.email }),
1881
2169
  " \xB7 ",
1882
2170
  grant.decision === "waive_interview" ? copy.waive : copy.require,
1883
- /* @__PURE__ */ jsxs19("p", { className: "muted", style: { margin: "6px 0" }, children: [
2171
+ /* @__PURE__ */ jsxs23("p", { className: "muted", style: { margin: "6px 0" }, children: [
1884
2172
  grant.sourceScope === "local" ? copy.local : copy.parent,
1885
2173
  " \xB7 ",
1886
2174
  state,
1887
2175
  grant.note ? ` \xB7 ${grant.note}` : ""
1888
2176
  ] }),
1889
- grant.sourceScope === "local" && state === copy.active ? /* @__PURE__ */ jsx21("button", { className: "btn secondary mini", disabled: busy, onClick: () => void revoke(grant), children: copy.revoke }) : null
2177
+ grant.sourceScope === "local" && state === copy.active ? /* @__PURE__ */ jsx25("button", { className: "btn secondary mini", disabled: busy, onClick: () => void revoke(grant), children: copy.revoke }) : null
1890
2178
  ] }, grant.id);
1891
2179
  }) })
1892
2180
  ] })
@@ -1897,19 +2185,19 @@ function admissionGrantsWorkspace(label = "Admission") {
1897
2185
  id: "admission",
1898
2186
  label,
1899
2187
  defaultViewId: "grants",
1900
- render: (ctx) => /* @__PURE__ */ jsx21(AdmissionGrantsWorkspace, { getToken: ctx.getToken })
2188
+ render: (ctx) => /* @__PURE__ */ jsx25(AdmissionGrantsWorkspace, { getToken: ctx.getToken })
1901
2189
  };
1902
2190
  }
1903
2191
  function LeaderAdmissionAction(props) {
1904
- return /* @__PURE__ */ jsx21(LeaderAdmissionForm, { ...props }, JSON.stringify([props.targetId, props.personId, props.sourceRecordId]));
2192
+ return /* @__PURE__ */ jsx25(LeaderAdmissionForm, { ...props }, JSON.stringify([props.targetId, props.personId, props.sourceRecordId]));
1905
2193
  }
1906
2194
  function LeaderAdmissionForm(props) {
1907
- const [decision, setDecision] = useState15("");
1908
- const [note, setNote] = useState15("");
1909
- const [loaded, setLoaded] = useState15(false);
1910
- const [busy, setBusy] = useState15(false);
1911
- const [error, setError] = useState15(null);
1912
- const [status, setStatus] = useState15(null);
2195
+ const [decision, setDecision] = useState20("");
2196
+ const [note, setNote] = useState20("");
2197
+ const [loaded, setLoaded] = useState20(false);
2198
+ const [busy, setBusy] = useState20(false);
2199
+ const [error, setError] = useState20(null);
2200
+ const [status, setStatus] = useState20(null);
1913
2201
  const attempt = useRef2(null);
1914
2202
  useEffect8(() => {
1915
2203
  let live = true;
@@ -1954,22 +2242,22 @@ function LeaderAdmissionForm(props) {
1954
2242
  setBusy(false);
1955
2243
  }
1956
2244
  };
1957
- return /* @__PURE__ */ jsxs19("div", { style: { display: "grid", gap: 8 }, children: [
1958
- /* @__PURE__ */ jsxs19("label", { children: [
2245
+ return /* @__PURE__ */ jsxs23("div", { style: { display: "grid", gap: 8 }, children: [
2246
+ /* @__PURE__ */ jsxs23("label", { children: [
1959
2247
  "Interview",
1960
- /* @__PURE__ */ jsxs19("select", { disabled: !loaded || busy, value: decision, onChange: (event) => setDecision(event.currentTarget.value), children: [
1961
- /* @__PURE__ */ jsx21("option", { value: "", children: loaded ? "Choose an invitation setting" : "Loading saved setting\u2026" }),
1962
- /* @__PURE__ */ jsx21("option", { value: "waive_interview", children: "Already completed" }),
1963
- /* @__PURE__ */ jsx21("option", { value: "require_interview", children: "Required" })
2248
+ /* @__PURE__ */ jsxs23("select", { disabled: !loaded || busy, value: decision, onChange: (event) => setDecision(event.currentTarget.value), children: [
2249
+ /* @__PURE__ */ jsx25("option", { value: "", children: loaded ? "Choose an invitation setting" : "Loading saved setting\u2026" }),
2250
+ /* @__PURE__ */ jsx25("option", { value: "waive_interview", children: "Already completed" }),
2251
+ /* @__PURE__ */ jsx25("option", { value: "require_interview", children: "Required" })
1964
2252
  ] })
1965
2253
  ] }),
1966
- /* @__PURE__ */ jsxs19("label", { children: [
2254
+ /* @__PURE__ */ jsxs23("label", { children: [
1967
2255
  "Internal note",
1968
- /* @__PURE__ */ jsx21("input", { disabled: !loaded || busy, maxLength: 2e3, value: note, onInput: (event) => setNote(event.currentTarget.value) })
2256
+ /* @__PURE__ */ jsx25("input", { disabled: !loaded || busy, maxLength: 2e3, value: note, onInput: (event) => setNote(event.currentTarget.value) })
1969
2257
  ] }),
1970
- /* @__PURE__ */ jsx21("button", { className: "btn secondary", type: "button", disabled: busy || !loaded || !decision, onClick: () => void submit(), children: busy ? "Saving\u2026" : "Save invitation setting" }),
1971
- error ? /* @__PURE__ */ jsx21("p", { role: "alert", children: error }) : null,
1972
- status ? /* @__PURE__ */ jsx21("p", { role: "status", children: status }) : null
2258
+ /* @__PURE__ */ jsx25("button", { className: "btn secondary", type: "button", disabled: busy || !loaded || !decision, onClick: () => void submit(), children: busy ? "Saving\u2026" : "Save invitation setting" }),
2259
+ error ? /* @__PURE__ */ jsx25("p", { role: "alert", children: error }) : null,
2260
+ status ? /* @__PURE__ */ jsx25("p", { role: "status", children: status }) : null
1973
2261
  ] });
1974
2262
  }
1975
2263
 
@@ -1977,19 +2265,19 @@ function LeaderAdmissionForm(props) {
1977
2265
  import { Tabs as Tabs2 } from "@odla-ai/ui/components";
1978
2266
 
1979
2267
  // src/ui/admin-availability.tsx
1980
- import { useState as useState16 } from "preact/hooks";
1981
- import { Button as Button9, Checkbox, Field as Field7, Input as Input2 } from "@odla-ai/ui/components";
1982
- import { jsx as jsx22, jsxs as jsxs20 } from "preact/jsx-runtime";
2268
+ import { useState as useState21 } from "preact/hooks";
2269
+ import { Button as Button14, Checkbox, Field as Field9, Input as Input2 } from "@odla-ai/ui/components";
2270
+ import { jsx as jsx26, jsxs as jsxs24 } from "preact/jsx-runtime";
1983
2271
  function AvailabilityBody({ ctx }) {
1984
2272
  const copy = useChapterCopy().admin.availability;
1985
2273
  const { data, loading, error, refresh } = useAdminResource(ctx.getToken, "/api/admin/scheduling");
1986
- const [draft, setDraft] = useState16(null);
1987
- const [busy, setBusy] = useState16(false);
1988
- const [note, setNote] = useState16(null);
1989
- const [errors, setErrors] = useState16({});
2274
+ const [draft, setDraft] = useState21(null);
2275
+ const [busy, setBusy] = useState21(false);
2276
+ const [note, setNote] = useState21(null);
2277
+ const [errors, setErrors] = useState21({});
1990
2278
  const cfg = draft ?? data?.scheduling ?? null;
1991
- if (loading) return /* @__PURE__ */ jsx22(AdminNote, { children: copy.loading });
1992
- if (error || !cfg) return /* @__PURE__ */ jsxs20(AdminNote, { children: [
2279
+ if (loading) return /* @__PURE__ */ jsx26(AdminNote, { children: copy.loading });
2280
+ if (error || !cfg) return /* @__PURE__ */ jsxs24(AdminNote, { children: [
1993
2281
  copy.loadFailed,
1994
2282
  error ? `: ${error}` : "",
1995
2283
  "."
@@ -2019,29 +2307,29 @@ function AvailabilityBody({ ctx }) {
2019
2307
  setBusy(false);
2020
2308
  }
2021
2309
  };
2022
- const numField = (key, label) => /* @__PURE__ */ jsx22(Field7, { label, error: errors[key], children: /* @__PURE__ */ jsx22(Input2, { type: "number", value: cfg[key], onInput: (e) => edit({ [key]: num(e.target.value, cfg[key]) }) }) });
2023
- return /* @__PURE__ */ jsx22(AdminPage, { children: /* @__PURE__ */ jsxs20(Panel, { title: copy.title, actions: note ? /* @__PURE__ */ jsx22("span", { className: "muted", children: note }) : void 0, children: [
2024
- /* @__PURE__ */ jsx22(Field7, { label: copy.days, error: errors.days, children: /* @__PURE__ */ jsx22("div", { style: { display: "flex", gap: 14, flexWrap: "wrap" }, children: copy.dayLabels.map((d, i) => /* @__PURE__ */ jsx22(Checkbox, { label: d, checked: cfg.days.includes(i), onChange: () => toggleDay(i) }, d)) }) }),
2025
- /* @__PURE__ */ jsxs20("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))", gap: 14 }, children: [
2310
+ const numField = (key, label) => /* @__PURE__ */ jsx26(Field9, { label, error: errors[key], children: /* @__PURE__ */ jsx26(Input2, { type: "number", value: cfg[key], onInput: (e) => edit({ [key]: num(e.target.value, cfg[key]) }) }) });
2311
+ return /* @__PURE__ */ jsx26(AdminPage, { children: /* @__PURE__ */ jsxs24(Panel, { title: copy.title, actions: note ? /* @__PURE__ */ jsx26("span", { className: "muted", children: note }) : void 0, children: [
2312
+ /* @__PURE__ */ jsx26(Field9, { label: copy.days, error: errors.days, children: /* @__PURE__ */ jsx26("div", { style: { display: "flex", gap: 14, flexWrap: "wrap" }, children: copy.dayLabels.map((d, i) => /* @__PURE__ */ jsx26(Checkbox, { label: d, checked: cfg.days.includes(i), onChange: () => toggleDay(i) }, d)) }) }),
2313
+ /* @__PURE__ */ jsxs24("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))", gap: 14 }, children: [
2026
2314
  numField("startHour", copy.startHour),
2027
2315
  numField("endHour", copy.endHour),
2028
2316
  numField("slotMinutes", copy.slotMinutes),
2029
2317
  numField("minNoticeHours", copy.minNoticeHours),
2030
2318
  numField("windowDays", copy.windowDays),
2031
- /* @__PURE__ */ jsx22(Field7, { label: copy.timezone, error: errors.timezone, children: /* @__PURE__ */ jsx22(Input2, { value: cfg.timezone, onInput: (e) => edit({ timezone: e.target.value }) }) })
2319
+ /* @__PURE__ */ jsx26(Field9, { label: copy.timezone, error: errors.timezone, children: /* @__PURE__ */ jsx26(Input2, { value: cfg.timezone, onInput: (e) => edit({ timezone: e.target.value }) }) })
2032
2320
  ] }),
2033
- /* @__PURE__ */ jsx22(Field7, { label: copy.summaryTemplate, error: errors.summaryTemplate, children: /* @__PURE__ */ jsx22(Input2, { value: cfg.summaryTemplate, onInput: (e) => edit({ summaryTemplate: e.target.value }) }) }),
2034
- /* @__PURE__ */ jsx22("div", { children: /* @__PURE__ */ jsx22(Button9, { disabled: !draft || busy, onClick: () => void save(), children: copy.save }) })
2321
+ /* @__PURE__ */ jsx26(Field9, { label: copy.summaryTemplate, error: errors.summaryTemplate, children: /* @__PURE__ */ jsx26(Input2, { value: cfg.summaryTemplate, onInput: (e) => edit({ summaryTemplate: e.target.value }) }) }),
2322
+ /* @__PURE__ */ jsx26("div", { children: /* @__PURE__ */ jsx26(Button14, { disabled: !draft || busy, onClick: () => void save(), children: copy.save }) })
2035
2323
  ] }) });
2036
2324
  }
2037
2325
  function availabilitySection(options = {}) {
2038
2326
  const { id = "availability", label = "Availability" } = options;
2039
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx22(AvailabilityBody, { ctx }) };
2327
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx26(AvailabilityBody, { ctx }) };
2040
2328
  }
2041
2329
 
2042
2330
  // src/ui/admin-builder-library.tsx
2043
- import { useEffect as useEffect9, useMemo as useMemo2, useState as useState17 } from "preact/hooks";
2044
- import { jsx as jsx23, jsxs as jsxs21 } from "preact/jsx-runtime";
2331
+ import { useEffect as useEffect9, useMemo as useMemo2, useState as useState22 } from "preact/hooks";
2332
+ import { jsx as jsx27, jsxs as jsxs25 } from "preact/jsx-runtime";
2045
2333
  var KINDS = ["document", "note", "link", "inspiration", "image", "file"];
2046
2334
  var KIND_LABEL = { document: "Document", note: "Note", link: "Link", inspiration: "Inspiration", image: "Image", file: "File" };
2047
2335
  var STATUS_LABEL = { draft: "Draft", published: "Published", archived: "Archived" };
@@ -2073,13 +2361,13 @@ function localResource(kind, chapterId, mode) {
2073
2361
  };
2074
2362
  }
2075
2363
  function ResourcePreview({ item }) {
2076
- return /* @__PURE__ */ jsxs21("div", { className: "card", style: { padding: 14 }, children: [
2077
- /* @__PURE__ */ jsx23("div", { className: "card-label", children: "Preview" }),
2078
- /* @__PURE__ */ jsx23("h3", { style: { margin: "6px 0" }, children: item.title || "Untitled" }),
2079
- item.summary ? /* @__PURE__ */ jsx23("p", { style: { margin: "0 0 10px" }, children: item.summary }) : null,
2080
- item.bodyMarkdown ? /* @__PURE__ */ jsx23("pre", { style: { margin: 0, whiteSpace: "pre-wrap", font: "inherit", lineHeight: 1.55 }, children: item.bodyMarkdown }) : null,
2081
- item.url ? /* @__PURE__ */ jsx23("a", { href: item.url, target: "_blank", rel: "noreferrer", children: item.url }) : null,
2082
- item.brandAsset ? /* @__PURE__ */ jsxs21("div", { style: META, children: [
2364
+ return /* @__PURE__ */ jsxs25("div", { className: "card", style: { padding: 14 }, children: [
2365
+ /* @__PURE__ */ jsx27("div", { className: "card-label", children: "Preview" }),
2366
+ /* @__PURE__ */ jsx27("h3", { style: { margin: "6px 0" }, children: item.title || "Untitled" }),
2367
+ item.summary ? /* @__PURE__ */ jsx27("p", { style: { margin: "0 0 10px" }, children: item.summary }) : null,
2368
+ item.bodyMarkdown ? /* @__PURE__ */ jsx27("pre", { style: { margin: 0, whiteSpace: "pre-wrap", font: "inherit", lineHeight: 1.55 }, children: item.bodyMarkdown }) : null,
2369
+ item.url ? /* @__PURE__ */ jsx27("a", { href: item.url, target: "_blank", rel: "noreferrer", children: item.url }) : null,
2370
+ item.brandAsset ? /* @__PURE__ */ jsxs25("div", { style: META, children: [
2083
2371
  "Brand asset \xB7 ",
2084
2372
  item.brandAsset.bookId,
2085
2373
  " / ",
@@ -2091,14 +2379,14 @@ function ResourcePreview({ item }) {
2091
2379
  function BuilderLibraryAdmin({ ctx, initialData }) {
2092
2380
  const remote = useAdminResource(ctx.getToken, "/api/admin/builder-library");
2093
2381
  const seed = initialData ?? remote.data;
2094
- const [resources, setResources] = useState17(() => [...seed?.local?.document.resources ?? []]);
2095
- const [selectedKey, setSelectedKey] = useState17(() => seed?.local?.document.resources[0]?.id ? localKey(seed.local.document.resources[0].id) : null);
2096
- const [query, setQuery] = useState17("");
2097
- const [kindFilter, setKindFilter] = useState17("all");
2098
- const [statusFilter, setStatusFilter] = useState17("all");
2099
- const [newKind, setNewKind] = useState17("document");
2100
- const [saveError, setSaveError] = useState17(null);
2101
- const [saving, setSaving] = useState17(false);
2382
+ const [resources, setResources] = useState22(() => [...seed?.local?.document.resources ?? []]);
2383
+ const [selectedKey, setSelectedKey] = useState22(() => seed?.local?.document.resources[0]?.id ? localKey(seed.local.document.resources[0].id) : null);
2384
+ const [query, setQuery] = useState22("");
2385
+ const [kindFilter, setKindFilter] = useState22("all");
2386
+ const [statusFilter, setStatusFilter] = useState22("all");
2387
+ const [newKind, setNewKind] = useState22("document");
2388
+ const [saveError, setSaveError] = useState22(null);
2389
+ const [saving, setSaving] = useState22(false);
2102
2390
  useEffect9(() => {
2103
2391
  if (!remote.data) return;
2104
2392
  const next = [...remote.data.local?.document.resources ?? []];
@@ -2115,8 +2403,8 @@ function BuilderLibraryAdmin({ ctx, initialData }) {
2115
2403
  return (!query.trim() || haystack.includes(query.toLowerCase().trim())) && (kindFilter === "all" || resource.kind === kindFilter) && (statusFilter === "all" || resource.status === statusFilter);
2116
2404
  });
2117
2405
  const selected = entries.find((entry) => entry.key === selectedKey) ?? visible[0] ?? null;
2118
- if (!data && remote.loading) return /* @__PURE__ */ jsx23(AdminPage, { children: /* @__PURE__ */ jsx23(AdminNote, { children: "Loading Builder Library\u2026" }) });
2119
- if (remote.error || !data) return /* @__PURE__ */ jsx23(AdminPage, { children: /* @__PURE__ */ jsxs21(AdminNote, { children: [
2406
+ if (!data && remote.loading) return /* @__PURE__ */ jsx27(AdminPage, { children: /* @__PURE__ */ jsx27(AdminNote, { children: "Loading Builder Library\u2026" }) });
2407
+ if (remote.error || !data) return /* @__PURE__ */ jsx27(AdminPage, { children: /* @__PURE__ */ jsxs25(AdminNote, { children: [
2120
2408
  "Builder Library could not be loaded: ",
2121
2409
  remote.error ?? "unknown error"
2122
2410
  ] }) });
@@ -2152,170 +2440,170 @@ function BuilderLibraryAdmin({ ctx, initialData }) {
2152
2440
  }
2153
2441
  };
2154
2442
  const scopeValue = selected?.resource.scope.kind === "chapter" ? `chapter:${selected.resource.scope.chapterId}` : selected?.resource.scope.kind ?? "built_not_found";
2155
- return /* @__PURE__ */ jsxs21(AdminPage, { children: [
2156
- /* @__PURE__ */ jsxs21(Panel, { title: /* @__PURE__ */ jsxs21("span", { children: [
2443
+ return /* @__PURE__ */ jsxs25(AdminPage, { children: [
2444
+ /* @__PURE__ */ jsxs25(Panel, { title: /* @__PURE__ */ jsxs25("span", { children: [
2157
2445
  "Builder Library ",
2158
- /* @__PURE__ */ jsx23("span", { className: "muted", children: "\xB7 private" })
2159
- ] }), actions: /* @__PURE__ */ jsxs21("div", { style: ROW, children: [
2160
- /* @__PURE__ */ jsx23("select", { "aria-label": "New resource type", value: newKind, onChange: (event) => setNewKind(event.currentTarget.value), children: KINDS.map((kind) => /* @__PURE__ */ jsx23("option", { value: kind, children: KIND_LABEL[kind] }, kind)) }),
2161
- /* @__PURE__ */ jsx23("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring, onClick: add, children: "Add resource" })
2446
+ /* @__PURE__ */ jsx27("span", { className: "muted", children: "\xB7 private" })
2447
+ ] }), actions: /* @__PURE__ */ jsxs25("div", { style: ROW, children: [
2448
+ /* @__PURE__ */ jsx27("select", { "aria-label": "New resource type", value: newKind, onChange: (event) => setNewKind(event.currentTarget.value), children: KINDS.map((kind) => /* @__PURE__ */ jsx27("option", { value: kind, children: KIND_LABEL[kind] }, kind)) }),
2449
+ /* @__PURE__ */ jsx27("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring, onClick: add, children: "Add resource" })
2162
2450
  ] }), children: [
2163
- /* @__PURE__ */ jsx23("p", { className: "muted", style: { margin: 0 }, children: "Documents, links, and Brand assets used by site-building agents. Nothing here appears on a member page." }),
2164
- /* @__PURE__ */ jsxs21("div", { style: ROW, children: [
2165
- /* @__PURE__ */ jsx23("input", { "aria-label": "Search resources", placeholder: "Search resources", value: query, onInput: (event) => setQuery(event.currentTarget.value), style: { flex: "1 1 220px" } }),
2166
- /* @__PURE__ */ jsxs21("select", { "aria-label": "Filter by type", value: kindFilter, onChange: (event) => setKindFilter(event.currentTarget.value), children: [
2167
- /* @__PURE__ */ jsx23("option", { value: "all", children: "All types" }),
2168
- KINDS.map((kind) => /* @__PURE__ */ jsx23("option", { value: kind, children: KIND_LABEL[kind] }, kind))
2451
+ /* @__PURE__ */ jsx27("p", { className: "muted", style: { margin: 0 }, children: "Documents, links, and Brand assets used by site-building agents. Nothing here appears on a member page." }),
2452
+ /* @__PURE__ */ jsxs25("div", { style: ROW, children: [
2453
+ /* @__PURE__ */ jsx27("input", { "aria-label": "Search resources", placeholder: "Search resources", value: query, onInput: (event) => setQuery(event.currentTarget.value), style: { flex: "1 1 220px" } }),
2454
+ /* @__PURE__ */ jsxs25("select", { "aria-label": "Filter by type", value: kindFilter, onChange: (event) => setKindFilter(event.currentTarget.value), children: [
2455
+ /* @__PURE__ */ jsx27("option", { value: "all", children: "All types" }),
2456
+ KINDS.map((kind) => /* @__PURE__ */ jsx27("option", { value: kind, children: KIND_LABEL[kind] }, kind))
2169
2457
  ] }),
2170
- /* @__PURE__ */ jsxs21("select", { "aria-label": "Filter by status", value: statusFilter, onChange: (event) => setStatusFilter(event.currentTarget.value), children: [
2171
- /* @__PURE__ */ jsx23("option", { value: "all", children: "All statuses" }),
2172
- /* @__PURE__ */ jsx23("option", { value: "draft", children: "Draft" }),
2173
- /* @__PURE__ */ jsx23("option", { value: "published", children: "Published" }),
2174
- /* @__PURE__ */ jsx23("option", { value: "archived", children: "Archived" })
2458
+ /* @__PURE__ */ jsxs25("select", { "aria-label": "Filter by status", value: statusFilter, onChange: (event) => setStatusFilter(event.currentTarget.value), children: [
2459
+ /* @__PURE__ */ jsx27("option", { value: "all", children: "All statuses" }),
2460
+ /* @__PURE__ */ jsx27("option", { value: "draft", children: "Draft" }),
2461
+ /* @__PURE__ */ jsx27("option", { value: "published", children: "Published" }),
2462
+ /* @__PURE__ */ jsx27("option", { value: "archived", children: "Archived" })
2175
2463
  ] })
2176
2464
  ] })
2177
2465
  ] }),
2178
- /* @__PURE__ */ jsxs21("div", { style: GRID, "data-builder-library-cms": true, children: [
2179
- /* @__PURE__ */ jsx23(Panel, { title: `${visible.length} resource${visible.length === 1 ? "" : "s"}`, children: /* @__PURE__ */ jsx23("div", { style: { ...STACK, maxHeight: "70vh", overflow: "auto" }, children: visible.length === 0 ? /* @__PURE__ */ jsx23("p", { className: "muted", children: "No resources match these filters." }) : visible.map((entry) => /* @__PURE__ */ jsxs21("button", { type: "button", style: { ...ITEM, ...selected?.key === entry.key ? { borderColor: "var(--ui-accent)", boxShadow: "0 0 0 1px var(--ui-accent)" } : {} }, onClick: () => setSelectedKey(entry.key), children: [
2180
- /* @__PURE__ */ jsxs21("div", { style: { ...ROW, justifyContent: "space-between" }, children: [
2181
- /* @__PURE__ */ jsx23("strong", { children: entry.resource.title }),
2182
- /* @__PURE__ */ jsx23("span", { className: "badge", children: KIND_LABEL[entry.resource.kind] })
2466
+ /* @__PURE__ */ jsxs25("div", { style: GRID, "data-builder-library-cms": true, children: [
2467
+ /* @__PURE__ */ jsx27(Panel, { title: `${visible.length} resource${visible.length === 1 ? "" : "s"}`, children: /* @__PURE__ */ jsx27("div", { style: { ...STACK, maxHeight: "70vh", overflow: "auto" }, children: visible.length === 0 ? /* @__PURE__ */ jsx27("p", { className: "muted", children: "No resources match these filters." }) : visible.map((entry) => /* @__PURE__ */ jsxs25("button", { type: "button", style: { ...ITEM, ...selected?.key === entry.key ? { borderColor: "var(--ui-accent)", boxShadow: "0 0 0 1px var(--ui-accent)" } : {} }, onClick: () => setSelectedKey(entry.key), children: [
2468
+ /* @__PURE__ */ jsxs25("div", { style: { ...ROW, justifyContent: "space-between" }, children: [
2469
+ /* @__PURE__ */ jsx27("strong", { children: entry.resource.title }),
2470
+ /* @__PURE__ */ jsx27("span", { className: "badge", children: KIND_LABEL[entry.resource.kind] })
2183
2471
  ] }),
2184
- /* @__PURE__ */ jsx23("p", { className: "muted", style: { margin: "6px 0", lineHeight: 1.4 }, children: contentSummary(entry.resource) }),
2185
- /* @__PURE__ */ jsxs21("div", { style: META, children: [
2186
- /* @__PURE__ */ jsx23("span", { children: STATUS_LABEL[entry.resource.status] }),
2187
- /* @__PURE__ */ jsx23("span", { children: "\xB7" }),
2188
- /* @__PURE__ */ jsx23("span", { children: scopeLabel(entry.resource.scope) }),
2189
- /* @__PURE__ */ jsx23("span", { children: "\xB7" }),
2190
- /* @__PURE__ */ jsx23("span", { children: entry.sourceId })
2472
+ /* @__PURE__ */ jsx27("p", { className: "muted", style: { margin: "6px 0", lineHeight: 1.4 }, children: contentSummary(entry.resource) }),
2473
+ /* @__PURE__ */ jsxs25("div", { style: META, children: [
2474
+ /* @__PURE__ */ jsx27("span", { children: STATUS_LABEL[entry.resource.status] }),
2475
+ /* @__PURE__ */ jsx27("span", { children: "\xB7" }),
2476
+ /* @__PURE__ */ jsx27("span", { children: scopeLabel(entry.resource.scope) }),
2477
+ /* @__PURE__ */ jsx27("span", { children: "\xB7" }),
2478
+ /* @__PURE__ */ jsx27("span", { children: entry.sourceId })
2191
2479
  ] })
2192
2480
  ] }, entry.key)) }) }),
2193
- /* @__PURE__ */ jsxs21(Panel, { title: selected ? selected.resource.title : "Select a resource", actions: selected?.local ? /* @__PURE__ */ jsxs21("div", { style: ROW, children: [
2194
- /* @__PURE__ */ jsx23("button", { className: "btn secondary", type: "button", disabled: saving, onClick: () => update({ status: selected.resource.status === "archived" ? "draft" : "archived" }), children: selected.resource.status === "archived" ? "Restore draft" : "Archive" }),
2195
- /* @__PURE__ */ jsx23("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring || saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save changes" })
2481
+ /* @__PURE__ */ jsxs25(Panel, { title: selected ? selected.resource.title : "Select a resource", actions: selected?.local ? /* @__PURE__ */ jsxs25("div", { style: ROW, children: [
2482
+ /* @__PURE__ */ jsx27("button", { className: "btn secondary", type: "button", disabled: saving, onClick: () => update({ status: selected.resource.status === "archived" ? "draft" : "archived" }), children: selected.resource.status === "archived" ? "Restore draft" : "Archive" }),
2483
+ /* @__PURE__ */ jsx27("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring || saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save changes" })
2196
2484
  ] }) : null, children: [
2197
- !selected ? /* @__PURE__ */ jsx23("p", { className: "muted", children: "Add a resource or choose one from the list." }) : selected.local ? /* @__PURE__ */ jsx23(LocalEditor, { selected: selected.resource, data, scopeValue, saving, update, setResources, setSelectedKey }) : /* @__PURE__ */ jsxs21("div", { style: STACK, children: [
2198
- /* @__PURE__ */ jsxs21("div", { style: META, children: [
2485
+ !selected ? /* @__PURE__ */ jsx27("p", { className: "muted", children: "Add a resource or choose one from the list." }) : selected.local ? /* @__PURE__ */ jsx27(LocalEditor, { selected: selected.resource, data, scopeValue, saving, update, setResources, setSelectedKey }) : /* @__PURE__ */ jsxs25("div", { style: STACK, children: [
2486
+ /* @__PURE__ */ jsxs25("div", { style: META, children: [
2199
2487
  "Read only \xB7 supplied by ",
2200
2488
  selected.sourceId,
2201
2489
  " \xB7 source revision ",
2202
2490
  selected.sourceRevision
2203
2491
  ] }),
2204
- /* @__PURE__ */ jsxs21("div", { children: [
2205
- /* @__PURE__ */ jsx23("span", { className: "badge", children: STATUS_LABEL[selected.resource.status] }),
2492
+ /* @__PURE__ */ jsxs25("div", { children: [
2493
+ /* @__PURE__ */ jsx27("span", { className: "badge", children: STATUS_LABEL[selected.resource.status] }),
2206
2494
  " ",
2207
- /* @__PURE__ */ jsx23("span", { className: "badge", children: scopeLabel(selected.resource.scope) })
2495
+ /* @__PURE__ */ jsx27("span", { className: "badge", children: scopeLabel(selected.resource.scope) })
2208
2496
  ] }),
2209
- /* @__PURE__ */ jsx23(ResourcePreview, { item: selected.resource }),
2210
- data.mode === "hub" && selected.resource.scope.kind === "chapter" ? /* @__PURE__ */ jsx23("button", { className: "btn secondary", type: "button", onClick: () => void promote(selected), children: "Copy to all chapters" }) : null
2497
+ /* @__PURE__ */ jsx27(ResourcePreview, { item: selected.resource }),
2498
+ data.mode === "hub" && selected.resource.scope.kind === "chapter" ? /* @__PURE__ */ jsx27("button", { className: "btn secondary", type: "button", onClick: () => void promote(selected), children: "Copy to all chapters" }) : null
2211
2499
  ] }),
2212
- saveError ? /* @__PURE__ */ jsxs21("div", { className: "notice danger", role: "alert", children: [
2213
- /* @__PURE__ */ jsx23("strong", { children: "Fix these items before saving:" }),
2214
- /* @__PURE__ */ jsx23("ul", { children: saveError.map((error) => /* @__PURE__ */ jsx23("li", { children: error }, error)) })
2500
+ saveError ? /* @__PURE__ */ jsxs25("div", { className: "notice danger", role: "alert", children: [
2501
+ /* @__PURE__ */ jsx27("strong", { children: "Fix these items before saving:" }),
2502
+ /* @__PURE__ */ jsx27("ul", { children: saveError.map((error) => /* @__PURE__ */ jsx27("li", { children: error }, error)) })
2215
2503
  ] }) : null
2216
2504
  ] })
2217
2505
  ] })
2218
2506
  ] });
2219
2507
  }
2220
2508
  function LocalEditor({ selected, data, scopeValue, update, setResources, setSelectedKey }) {
2221
- return /* @__PURE__ */ jsxs21("div", { style: STACK, children: [
2222
- /* @__PURE__ */ jsxs21("div", { style: META, children: [
2509
+ return /* @__PURE__ */ jsxs25("div", { style: STACK, children: [
2510
+ /* @__PURE__ */ jsxs25("div", { style: META, children: [
2223
2511
  "Local \xB7 resource revision ",
2224
2512
  selected.revision,
2225
2513
  " \xB7 library revision ",
2226
2514
  data.local?.revision ?? 0
2227
2515
  ] }),
2228
- /* @__PURE__ */ jsxs21("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }, children: [
2229
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2230
- /* @__PURE__ */ jsx23("span", { children: "Title" }),
2231
- /* @__PURE__ */ jsx23("input", { value: selected.title, onInput: (event) => update({ title: event.currentTarget.value }) })
2516
+ /* @__PURE__ */ jsxs25("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }, children: [
2517
+ /* @__PURE__ */ jsxs25("label", { className: "field", children: [
2518
+ /* @__PURE__ */ jsx27("span", { children: "Title" }),
2519
+ /* @__PURE__ */ jsx27("input", { value: selected.title, onInput: (event) => update({ title: event.currentTarget.value }) })
2232
2520
  ] }),
2233
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2234
- /* @__PURE__ */ jsx23("span", { children: "ID" }),
2235
- /* @__PURE__ */ jsx23("input", { value: selected.id, onInput: (event) => {
2521
+ /* @__PURE__ */ jsxs25("label", { className: "field", children: [
2522
+ /* @__PURE__ */ jsx27("span", { children: "ID" }),
2523
+ /* @__PURE__ */ jsx27("input", { value: selected.id, onInput: (event) => {
2236
2524
  const id = cleanId(event.currentTarget.value);
2237
2525
  setResources((items) => items.map((item) => item.id === selected.id ? { ...item, id } : item));
2238
2526
  setSelectedKey(localKey(id));
2239
2527
  } })
2240
2528
  ] }),
2241
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2242
- /* @__PURE__ */ jsx23("span", { children: "Type" }),
2243
- /* @__PURE__ */ jsx23("select", { value: selected.kind, onChange: (event) => {
2529
+ /* @__PURE__ */ jsxs25("label", { className: "field", children: [
2530
+ /* @__PURE__ */ jsx27("span", { children: "Type" }),
2531
+ /* @__PURE__ */ jsx27("select", { value: selected.kind, onChange: (event) => {
2244
2532
  const kind = event.currentTarget.value;
2245
2533
  update({ kind, bodyMarkdown: kind === "document" || kind === "note" ? selected.bodyMarkdown ?? "Start writing\u2026" : void 0, url: kind === "link" || kind === "inspiration" ? selected.url ?? "https://example.com" : void 0, brandAsset: kind === "image" || kind === "file" ? selected.brandAsset ?? { bookId: "brand-book", assetId: "replace-me" } : void 0 });
2246
- }, children: KINDS.map((kind) => /* @__PURE__ */ jsx23("option", { value: kind, children: KIND_LABEL[kind] }, kind)) })
2534
+ }, children: KINDS.map((kind) => /* @__PURE__ */ jsx27("option", { value: kind, children: KIND_LABEL[kind] }, kind)) })
2247
2535
  ] }),
2248
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2249
- /* @__PURE__ */ jsx23("span", { children: "Status" }),
2250
- /* @__PURE__ */ jsxs21("select", { value: selected.status, onChange: (event) => update({ status: event.currentTarget.value }), children: [
2251
- /* @__PURE__ */ jsx23("option", { value: "draft", children: "Draft" }),
2252
- /* @__PURE__ */ jsx23("option", { value: "published", children: "Published" }),
2253
- /* @__PURE__ */ jsx23("option", { value: "archived", children: "Archived" })
2536
+ /* @__PURE__ */ jsxs25("label", { className: "field", children: [
2537
+ /* @__PURE__ */ jsx27("span", { children: "Status" }),
2538
+ /* @__PURE__ */ jsxs25("select", { value: selected.status, onChange: (event) => update({ status: event.currentTarget.value }), children: [
2539
+ /* @__PURE__ */ jsx27("option", { value: "draft", children: "Draft" }),
2540
+ /* @__PURE__ */ jsx27("option", { value: "published", children: "Published" }),
2541
+ /* @__PURE__ */ jsx27("option", { value: "archived", children: "Archived" })
2254
2542
  ] })
2255
2543
  ] }),
2256
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2257
- /* @__PURE__ */ jsx23("span", { children: "Visible to" }),
2258
- /* @__PURE__ */ jsxs21("select", { value: scopeValue, onChange: (event) => {
2544
+ /* @__PURE__ */ jsxs25("label", { className: "field", children: [
2545
+ /* @__PURE__ */ jsx27("span", { children: "Visible to" }),
2546
+ /* @__PURE__ */ jsxs25("select", { value: scopeValue, onChange: (event) => {
2259
2547
  const value = event.currentTarget.value;
2260
2548
  update({ scope: value === "global" ? { kind: "global" } : value === "built_not_found" ? { kind: "built_not_found" } : { kind: "chapter", chapterId: value.slice("chapter:".length) } });
2261
2549
  }, children: [
2262
- data.mode === "hub" ? /* @__PURE__ */ jsx23("option", { value: "built_not_found", children: "Built Not Found only" }) : null,
2263
- data.mode === "hub" ? /* @__PURE__ */ jsx23("option", { value: "global", children: "All chapters" }) : null,
2264
- data.chapterTargets.map(({ chapterId }) => /* @__PURE__ */ jsxs21("option", { value: `chapter:${chapterId}`, children: [
2550
+ data.mode === "hub" ? /* @__PURE__ */ jsx27("option", { value: "built_not_found", children: "Built Not Found only" }) : null,
2551
+ data.mode === "hub" ? /* @__PURE__ */ jsx27("option", { value: "global", children: "All chapters" }) : null,
2552
+ data.chapterTargets.map(({ chapterId }) => /* @__PURE__ */ jsxs25("option", { value: `chapter:${chapterId}`, children: [
2265
2553
  "Only ",
2266
2554
  chapterId
2267
2555
  ] }, chapterId))
2268
2556
  ] })
2269
2557
  ] }),
2270
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2271
- /* @__PURE__ */ jsx23("span", { children: "Tags" }),
2272
- /* @__PURE__ */ jsx23("input", { value: selected.tags.join(", "), placeholder: "brand, membership", onInput: (event) => update({ tags: event.currentTarget.value.split(",").map((tag) => tag.trim()).filter(Boolean) }) })
2558
+ /* @__PURE__ */ jsxs25("label", { className: "field", children: [
2559
+ /* @__PURE__ */ jsx27("span", { children: "Tags" }),
2560
+ /* @__PURE__ */ jsx27("input", { value: selected.tags.join(", "), placeholder: "brand, membership", onInput: (event) => update({ tags: event.currentTarget.value.split(",").map((tag) => tag.trim()).filter(Boolean) }) })
2273
2561
  ] })
2274
2562
  ] }),
2275
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2276
- /* @__PURE__ */ jsx23("span", { children: "Summary" }),
2277
- /* @__PURE__ */ jsx23("textarea", { rows: 2, value: selected.summary ?? "", onInput: (event) => update({ summary: event.currentTarget.value || void 0 }) })
2563
+ /* @__PURE__ */ jsxs25("label", { className: "field", children: [
2564
+ /* @__PURE__ */ jsx27("span", { children: "Summary" }),
2565
+ /* @__PURE__ */ jsx27("textarea", { rows: 2, value: selected.summary ?? "", onInput: (event) => update({ summary: event.currentTarget.value || void 0 }) })
2278
2566
  ] }),
2279
- selected.kind === "document" || selected.kind === "note" ? /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2280
- /* @__PURE__ */ jsx23("span", { children: "Markdown" }),
2281
- /* @__PURE__ */ jsx23("textarea", { rows: 12, value: selected.bodyMarkdown ?? "", onInput: (event) => update({ bodyMarkdown: event.currentTarget.value }) })
2567
+ selected.kind === "document" || selected.kind === "note" ? /* @__PURE__ */ jsxs25("label", { className: "field", children: [
2568
+ /* @__PURE__ */ jsx27("span", { children: "Markdown" }),
2569
+ /* @__PURE__ */ jsx27("textarea", { rows: 12, value: selected.bodyMarkdown ?? "", onInput: (event) => update({ bodyMarkdown: event.currentTarget.value }) })
2282
2570
  ] }) : null,
2283
- selected.kind === "link" || selected.kind === "inspiration" ? /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2284
- /* @__PURE__ */ jsx23("span", { children: "HTTPS URL" }),
2285
- /* @__PURE__ */ jsx23("input", { type: "url", value: selected.url ?? "", onInput: (event) => update({ url: event.currentTarget.value }) })
2571
+ selected.kind === "link" || selected.kind === "inspiration" ? /* @__PURE__ */ jsxs25("label", { className: "field", children: [
2572
+ /* @__PURE__ */ jsx27("span", { children: "HTTPS URL" }),
2573
+ /* @__PURE__ */ jsx27("input", { type: "url", value: selected.url ?? "", onInput: (event) => update({ url: event.currentTarget.value }) })
2286
2574
  ] }) : null,
2287
- selected.kind === "image" || selected.kind === "file" ? /* @__PURE__ */ jsxs21("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }, children: [
2288
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2289
- /* @__PURE__ */ jsx23("span", { children: "Brand book ID" }),
2290
- /* @__PURE__ */ jsx23("input", { value: selected.brandAsset?.bookId ?? "", onInput: (event) => update({ brandAsset: { bookId: event.currentTarget.value, assetId: selected.brandAsset?.assetId ?? "", ...selected.brandAsset?.filename ? { filename: selected.brandAsset.filename } : {} } }) })
2575
+ selected.kind === "image" || selected.kind === "file" ? /* @__PURE__ */ jsxs25("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }, children: [
2576
+ /* @__PURE__ */ jsxs25("label", { className: "field", children: [
2577
+ /* @__PURE__ */ jsx27("span", { children: "Brand book ID" }),
2578
+ /* @__PURE__ */ jsx27("input", { value: selected.brandAsset?.bookId ?? "", onInput: (event) => update({ brandAsset: { bookId: event.currentTarget.value, assetId: selected.brandAsset?.assetId ?? "", ...selected.brandAsset?.filename ? { filename: selected.brandAsset.filename } : {} } }) })
2291
2579
  ] }),
2292
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2293
- /* @__PURE__ */ jsx23("span", { children: "Asset ID" }),
2294
- /* @__PURE__ */ jsx23("input", { value: selected.brandAsset?.assetId ?? "", onInput: (event) => update({ brandAsset: { bookId: selected.brandAsset?.bookId ?? "", assetId: event.currentTarget.value, ...selected.brandAsset?.filename ? { filename: selected.brandAsset.filename } : {} } }) })
2580
+ /* @__PURE__ */ jsxs25("label", { className: "field", children: [
2581
+ /* @__PURE__ */ jsx27("span", { children: "Asset ID" }),
2582
+ /* @__PURE__ */ jsx27("input", { value: selected.brandAsset?.assetId ?? "", onInput: (event) => update({ brandAsset: { bookId: selected.brandAsset?.bookId ?? "", assetId: event.currentTarget.value, ...selected.brandAsset?.filename ? { filename: selected.brandAsset.filename } : {} } }) })
2295
2583
  ] }),
2296
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2297
- /* @__PURE__ */ jsx23("span", { children: "Filename (optional)" }),
2298
- /* @__PURE__ */ jsx23("input", { value: selected.brandAsset?.filename ?? "", onInput: (event) => update({ brandAsset: { bookId: selected.brandAsset?.bookId ?? "", assetId: selected.brandAsset?.assetId ?? "", ...event.currentTarget.value ? { filename: event.currentTarget.value } : {} } }) })
2584
+ /* @__PURE__ */ jsxs25("label", { className: "field", children: [
2585
+ /* @__PURE__ */ jsx27("span", { children: "Filename (optional)" }),
2586
+ /* @__PURE__ */ jsx27("input", { value: selected.brandAsset?.filename ?? "", onInput: (event) => update({ brandAsset: { bookId: selected.brandAsset?.bookId ?? "", assetId: selected.brandAsset?.assetId ?? "", ...event.currentTarget.value ? { filename: event.currentTarget.value } : {} } }) })
2299
2587
  ] })
2300
2588
  ] }) : null,
2301
- /* @__PURE__ */ jsx23(ResourcePreview, { item: selected })
2589
+ /* @__PURE__ */ jsx27(ResourcePreview, { item: selected })
2302
2590
  ] });
2303
2591
  }
2304
2592
  function builderLibrarySection() {
2305
- return { id: "builder-library", label: "Builder Library", render: (ctx) => /* @__PURE__ */ jsx23(BuilderLibraryAdmin, { ctx }) };
2593
+ return { id: "builder-library", label: "Builder Library", render: (ctx) => /* @__PURE__ */ jsx27(BuilderLibraryAdmin, { ctx }) };
2306
2594
  }
2307
2595
 
2308
2596
  // src/ui/admin-email.tsx
2309
- import { useState as useState19 } from "preact/hooks";
2310
- import { Button as Button11, Checkbox as Checkbox2, DataTable as DataTable3, Field as Field9, Input as Input4, Textarea as Textarea4 } from "@odla-ai/ui/components";
2597
+ import { useState as useState24 } from "preact/hooks";
2598
+ import { Button as Button16, Checkbox as Checkbox2, DataTable as DataTable3, Field as Field11, Input as Input4, Textarea as Textarea4 } from "@odla-ai/ui/components";
2311
2599
 
2312
2600
  // src/ui/admin-email-resolution.tsx
2313
- import { useState as useState18 } from "preact/hooks";
2314
- import { Button as Button10, Field as Field8, Input as Input3, Textarea as Textarea3 } from "@odla-ai/ui/components";
2315
- import { jsx as jsx24, jsxs as jsxs22 } from "preact/jsx-runtime";
2601
+ import { useState as useState23 } from "preact/hooks";
2602
+ import { Button as Button15, Field as Field10, Input as Input3, Textarea as Textarea3 } from "@odla-ai/ui/components";
2603
+ import { jsx as jsx28, jsxs as jsxs26 } from "preact/jsx-runtime";
2316
2604
  function EmailDeliveryResolution({ row, ctx, onResolved }) {
2317
- const [open, setOpen] = useState18(false), [reason, setReason] = useState18(""), [messageId, setMessageId] = useState18("");
2318
- const [busy, setBusy] = useState18(false), [note, setNote] = useState18("");
2605
+ const [open, setOpen] = useState23(false), [reason, setReason] = useState23(""), [messageId, setMessageId] = useState23("");
2606
+ const [busy, setBusy] = useState23(false), [note, setNote] = useState23("");
2319
2607
  if (!["sending", "uncertain"].includes(row.deliveryState ?? "") || !row.deliveryAttempt) return null;
2320
2608
  const resolve2 = async (decision) => {
2321
2609
  setBusy(true);
@@ -2339,45 +2627,45 @@ function EmailDeliveryResolution({ row, ctx, onResolved }) {
2339
2627
  setBusy(false);
2340
2628
  }
2341
2629
  };
2342
- if (!open) return /* @__PURE__ */ jsx24(Button10, { mini: true, variant: "secondary", onClick: () => setOpen(true), children: "Review delivery" });
2343
- return /* @__PURE__ */ jsxs22("div", { children: [
2344
- /* @__PURE__ */ jsxs22("p", { children: [
2630
+ if (!open) return /* @__PURE__ */ jsx28(Button15, { mini: true, variant: "secondary", onClick: () => setOpen(true), children: "Review delivery" });
2631
+ return /* @__PURE__ */ jsxs26("div", { children: [
2632
+ /* @__PURE__ */ jsxs26("p", { children: [
2345
2633
  "Attempt ",
2346
2634
  row.deliveryAttempt,
2347
2635
  ": ",
2348
2636
  row.subject,
2349
2637
  ". Check provider evidence, not just whether the message is in an inbox. This action does not send mail."
2350
2638
  ] }),
2351
- /* @__PURE__ */ jsx24(Field8, { label: "Provider evidence", children: /* @__PURE__ */ jsx24(Textarea3, { value: reason, onInput: (e) => setReason(e.target.value) }) }),
2352
- /* @__PURE__ */ jsx24(Field8, { label: "Provider message ID (optional)", children: /* @__PURE__ */ jsx24(Input3, { value: messageId, onInput: (e) => setMessageId(e.target.value) }) }),
2353
- /* @__PURE__ */ jsx24(Button10, { mini: true, disabled: busy || reason.trim().length < 10, onClick: () => void resolve2("confirmed_delivered"), children: "Confirm delivered" }),
2354
- /* @__PURE__ */ jsx24(Button10, { mini: true, variant: "secondary", disabled: busy || reason.trim().length < 10, onClick: () => void resolve2("confirmed_not_delivered"), children: "Confirm not delivered" }),
2355
- /* @__PURE__ */ jsx24(Button10, { mini: true, variant: "secondary", disabled: busy, onClick: () => setOpen(false), children: "Cancel" }),
2356
- note ? /* @__PURE__ */ jsx24("p", { role: "alert", children: note }) : null
2639
+ /* @__PURE__ */ jsx28(Field10, { label: "Provider evidence", children: /* @__PURE__ */ jsx28(Textarea3, { value: reason, onInput: (e) => setReason(e.target.value) }) }),
2640
+ /* @__PURE__ */ jsx28(Field10, { label: "Provider message ID (optional)", children: /* @__PURE__ */ jsx28(Input3, { value: messageId, onInput: (e) => setMessageId(e.target.value) }) }),
2641
+ /* @__PURE__ */ jsx28(Button15, { mini: true, disabled: busy || reason.trim().length < 10, onClick: () => void resolve2("confirmed_delivered"), children: "Confirm delivered" }),
2642
+ /* @__PURE__ */ jsx28(Button15, { mini: true, variant: "secondary", disabled: busy || reason.trim().length < 10, onClick: () => void resolve2("confirmed_not_delivered"), children: "Confirm not delivered" }),
2643
+ /* @__PURE__ */ jsx28(Button15, { mini: true, variant: "secondary", disabled: busy, onClick: () => setOpen(false), children: "Cancel" }),
2644
+ note ? /* @__PURE__ */ jsx28("p", { role: "alert", children: note }) : null
2357
2645
  ] });
2358
2646
  }
2359
2647
 
2360
2648
  // src/ui/admin-email.tsx
2361
- import { jsx as jsx25, jsxs as jsxs23 } from "preact/jsx-runtime";
2649
+ import { jsx as jsx29, jsxs as jsxs27 } from "preact/jsx-runtime";
2362
2650
  var logColumns = (copy, ctx, refresh) => [
2363
2651
  { key: "sentAt", header: copy.sentColumn, cell: (r) => new Date(r.sentAt).toLocaleString(), sortAs: "number", sortValue: (r) => r.sentAt },
2364
2652
  { key: "template", header: copy.templateColumn, cell: (r) => r.template },
2365
2653
  { key: "to", header: copy.toColumn, cell: (r) => r.to },
2366
- { key: "status", header: copy.statusColumn, cell: (r) => /* @__PURE__ */ jsxs23("div", { children: [
2367
- r.deliveryState && r.deliveryState !== "sent" ? /* @__PURE__ */ jsx25("span", { className: "badge", children: r.deliveryState === "retry_ready" ? "Original workflow may retry" : r.deliveryState === "sending" ? "Sending \u2014 unconfirmed" : "Delivery uncertain" }) : r.error ? /* @__PURE__ */ jsx25("span", { className: "badge", children: copy.failed }) : r.transport === "log-only" ? "Logged only \u2014 not sent" : r.redirected ? /* @__PURE__ */ jsx25("span", { className: "badge", children: copy.redirected }) : copy.delivered,
2368
- /* @__PURE__ */ jsx25(EmailDeliveryResolution, { row: r, ctx, onResolved: refresh })
2654
+ { key: "status", header: copy.statusColumn, cell: (r) => /* @__PURE__ */ jsxs27("div", { children: [
2655
+ r.deliveryState && r.deliveryState !== "sent" ? /* @__PURE__ */ jsx29("span", { className: "badge", children: r.deliveryState === "retry_ready" ? "Original workflow may retry" : r.deliveryState === "sending" ? "Sending \u2014 unconfirmed" : "Delivery uncertain" }) : r.error ? /* @__PURE__ */ jsx29("span", { className: "badge", children: copy.failed }) : r.transport === "log-only" ? "Logged only \u2014 not sent" : r.redirected ? /* @__PURE__ */ jsx29("span", { className: "badge", children: copy.redirected }) : copy.delivered,
2656
+ /* @__PURE__ */ jsx29(EmailDeliveryResolution, { row: r, ctx, onResolved: refresh })
2369
2657
  ] }) }
2370
2658
  ];
2371
2659
  function EmailBody({ ctx }) {
2372
2660
  const copy = useChapterCopy().admin.email;
2373
2661
  const cfg = useAdminResource(ctx.getToken, "/api/admin/group/email");
2374
2662
  const log = useAdminResource(ctx.getToken, "/api/admin/email/log");
2375
- const [draft, setDraft] = useState19(null);
2376
- const [busy, setBusy] = useState19(null);
2377
- const [note, setNote] = useState19(null);
2663
+ const [draft, setDraft] = useState24(null);
2664
+ const [busy, setBusy] = useState24(null);
2665
+ const [note, setNote] = useState24(null);
2378
2666
  const data = draft ?? cfg.data;
2379
- if (cfg.loading) return /* @__PURE__ */ jsx25(AdminNote, { children: copy.loading });
2380
- if (cfg.error || !data) return /* @__PURE__ */ jsxs23(AdminNote, { children: [
2667
+ if (cfg.loading) return /* @__PURE__ */ jsx29(AdminNote, { children: copy.loading });
2668
+ if (cfg.error || !data) return /* @__PURE__ */ jsxs27(AdminNote, { children: [
2381
2669
  copy.loadFailed,
2382
2670
  cfg.error ? `: ${cfg.error}` : "",
2383
2671
  "."
@@ -2410,44 +2698,44 @@ function EmailBody({ ctx }) {
2410
2698
  }) : copy.testFailed);
2411
2699
  log.refresh();
2412
2700
  });
2413
- return /* @__PURE__ */ jsxs23(AdminPage, { children: [
2414
- /* @__PURE__ */ jsxs23(
2701
+ return /* @__PURE__ */ jsxs27(AdminPage, { children: [
2702
+ /* @__PURE__ */ jsxs27(
2415
2703
  Panel,
2416
2704
  {
2417
2705
  title: copy.delivery,
2418
- actions: /* @__PURE__ */ jsxs23("span", { className: "muted", children: [
2706
+ actions: /* @__PURE__ */ jsxs27("span", { className: "muted", children: [
2419
2707
  data.envName,
2420
2708
  " \xB7 ",
2421
2709
  data.transport,
2422
2710
  data.fromEmail ? ` \xB7 ${data.fromEmail}` : ""
2423
2711
  ] }),
2424
2712
  children: [
2425
- /* @__PURE__ */ jsx25(Field9, { label: copy.notificationAddress, children: /* @__PURE__ */ jsx25(Input4, { value: data.notificationEmail, onInput: (e) => edit({ notificationEmail: e.target.value }) }) }),
2426
- /* @__PURE__ */ jsx25(Field9, { label: copy.replyTo, children: /* @__PURE__ */ jsx25(Input4, { value: data.replyTo, onInput: (e) => edit({ replyTo: e.target.value }) }) }),
2427
- /* @__PURE__ */ jsx25(Field9, { label: copy.debugInbox, hint: copy.debugInboxHint, children: /* @__PURE__ */ jsx25(Input4, { value: data.debugEmail, onInput: (e) => edit({ debugEmail: e.target.value }) }) })
2713
+ /* @__PURE__ */ jsx29(Field11, { label: copy.notificationAddress, children: /* @__PURE__ */ jsx29(Input4, { value: data.notificationEmail, onInput: (e) => edit({ notificationEmail: e.target.value }) }) }),
2714
+ /* @__PURE__ */ jsx29(Field11, { label: copy.replyTo, children: /* @__PURE__ */ jsx29(Input4, { value: data.replyTo, onInput: (e) => edit({ replyTo: e.target.value }) }) }),
2715
+ /* @__PURE__ */ jsx29(Field11, { label: copy.debugInbox, hint: copy.debugInboxHint, children: /* @__PURE__ */ jsx29(Input4, { value: data.debugEmail, onInput: (e) => edit({ debugEmail: e.target.value }) }) })
2428
2716
  ]
2429
2717
  }
2430
2718
  ),
2431
- Object.entries(data.emailTemplates).map(([key, t]) => /* @__PURE__ */ jsxs23(Panel, { title: key, actions: /* @__PURE__ */ jsx25(Button11, { variant: "secondary", mini: true, disabled: busy === `test:${key}`, onClick: () => void test(key), children: copy.sendTest }), children: [
2432
- /* @__PURE__ */ jsx25(Checkbox2, { label: copy.enabled, checked: t.enabled, onChange: (e) => editTemplate(key, { enabled: e.target.checked }) }),
2433
- /* @__PURE__ */ jsx25(Field9, { label: copy.subject, children: /* @__PURE__ */ jsx25(Input4, { value: t.subject, onInput: (e) => editTemplate(key, { subject: e.target.value }) }) }),
2434
- /* @__PURE__ */ jsx25(Field9, { label: copy.body, children: /* @__PURE__ */ jsx25(Textarea4, { prose: true, rows: 5, value: t.text, onInput: (e) => editTemplate(key, { text: e.target.value }) }) })
2719
+ Object.entries(data.emailTemplates).map(([key, t]) => /* @__PURE__ */ jsxs27(Panel, { title: key, actions: /* @__PURE__ */ jsx29(Button16, { variant: "secondary", mini: true, disabled: busy === `test:${key}`, onClick: () => void test(key), children: copy.sendTest }), children: [
2720
+ /* @__PURE__ */ jsx29(Checkbox2, { label: copy.enabled, checked: t.enabled, onChange: (e) => editTemplate(key, { enabled: e.target.checked }) }),
2721
+ /* @__PURE__ */ jsx29(Field11, { label: copy.subject, children: /* @__PURE__ */ jsx29(Input4, { value: t.subject, onInput: (e) => editTemplate(key, { subject: e.target.value }) }) }),
2722
+ /* @__PURE__ */ jsx29(Field11, { label: copy.body, children: /* @__PURE__ */ jsx29(Textarea4, { prose: true, rows: 5, value: t.text, onInput: (e) => editTemplate(key, { text: e.target.value }) }) })
2435
2723
  ] }, key)),
2436
- /* @__PURE__ */ jsxs23("div", { style: { display: "flex", gap: 12, alignItems: "center" }, children: [
2437
- /* @__PURE__ */ jsx25(Button11, { disabled: !draft || busy === "save", onClick: () => void save(), children: copy.save }),
2438
- note ? /* @__PURE__ */ jsx25("span", { className: "muted", children: note }) : null
2724
+ /* @__PURE__ */ jsxs27("div", { style: { display: "flex", gap: 12, alignItems: "center" }, children: [
2725
+ /* @__PURE__ */ jsx29(Button16, { disabled: !draft || busy === "save", onClick: () => void save(), children: copy.save }),
2726
+ note ? /* @__PURE__ */ jsx29("span", { className: "muted", children: note }) : null
2439
2727
  ] }),
2440
- /* @__PURE__ */ jsx25(Panel, { title: copy.sendLog, children: /* @__PURE__ */ jsx25(DataTable3, { rows: log.data?.sends ?? [], columns: logColumns(copy, ctx, log.refresh), rowKey: (r) => r.id }) })
2728
+ /* @__PURE__ */ jsx29(Panel, { title: copy.sendLog, children: /* @__PURE__ */ jsx29(DataTable3, { rows: log.data?.sends ?? [], columns: logColumns(copy, ctx, log.refresh), rowKey: (r) => r.id }) })
2441
2729
  ] });
2442
2730
  }
2443
2731
  function emailSection(options = {}) {
2444
2732
  const { id = "email", label = "Email" } = options;
2445
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx25(EmailBody, { ctx }) };
2733
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx29(EmailBody, { ctx }) };
2446
2734
  }
2447
2735
 
2448
2736
  // src/ui/admin-member-content.tsx
2449
- import { useEffect as useEffect10, useState as useState20 } from "preact/hooks";
2450
- import { jsx as jsx26, jsxs as jsxs24 } from "preact/jsx-runtime";
2737
+ import { useEffect as useEffect10, useState as useState25 } from "preact/hooks";
2738
+ import { jsx as jsx30, jsxs as jsxs28 } from "preact/jsx-runtime";
2451
2739
  var emptyDraft = () => ({ pages: [], upsellOverrides: [] });
2452
2740
  function accessLabel(page) {
2453
2741
  return page.audience.kind === "all-members" ? "All members" : `Tiers: ${page.audience.tierIds.join(", ")}`;
@@ -2457,17 +2745,17 @@ function MemberContentAdmin({
2457
2745
  initialData
2458
2746
  }) {
2459
2747
  const resource = useAdminResource(ctx.getToken, "/api/admin/member-content");
2460
- const [draft, setDraft] = useState20(JSON.stringify(initialData?.chapter?.document ?? emptyDraft(), null, 2));
2461
- const [saveError, setSaveError] = useState20(null);
2462
- const [saving, setSaving] = useState20(false);
2748
+ const [draft, setDraft] = useState25(JSON.stringify(initialData?.chapter?.document ?? emptyDraft(), null, 2));
2749
+ const [saveError, setSaveError] = useState25(null);
2750
+ const [saving, setSaving] = useState25(false);
2463
2751
  useEffect10(() => {
2464
2752
  if (!resource.data) return;
2465
2753
  setDraft(JSON.stringify(resource.data.chapter?.document ?? emptyDraft(), null, 2));
2466
2754
  }, [resource.data]);
2467
2755
  const loaded = initialData ?? resource.data;
2468
- if (!loaded && resource.loading) return /* @__PURE__ */ jsx26(AdminPage, { children: /* @__PURE__ */ jsx26(AdminNote, { children: "Loading member content\u2026" }) });
2756
+ if (!loaded && resource.loading) return /* @__PURE__ */ jsx30(AdminPage, { children: /* @__PURE__ */ jsx30(AdminNote, { children: "Loading member content\u2026" }) });
2469
2757
  if (resource.error || !loaded) {
2470
- return /* @__PURE__ */ jsx26(AdminPage, { children: /* @__PURE__ */ jsxs24(AdminNote, { children: [
2758
+ return /* @__PURE__ */ jsx30(AdminPage, { children: /* @__PURE__ */ jsxs28(AdminNote, { children: [
2471
2759
  "Member content could not be loaded: ",
2472
2760
  resource.error ?? "unknown error"
2473
2761
  ] }) });
@@ -2498,35 +2786,35 @@ function MemberContentAdmin({
2498
2786
  setSaving(false);
2499
2787
  }
2500
2788
  };
2501
- return /* @__PURE__ */ jsxs24(AdminPage, { children: [
2502
- /* @__PURE__ */ jsxs24(Panel, { children: [
2503
- /* @__PURE__ */ jsx26("div", { className: "card-label", children: "Member content" }),
2504
- /* @__PURE__ */ jsx26("h2", { children: "One catalog, two clear owners" }),
2505
- /* @__PURE__ */ jsx26("p", { children: "Parent pages are inherited and read-only here. Chapter pages and delegated upsells are edited in the local document. Access uses exact tier IDs; no tier order is assumed." }),
2506
- /* @__PURE__ */ jsxs24("div", { className: "stat-band", children: [
2507
- /* @__PURE__ */ jsxs24("div", { children: [
2508
- /* @__PURE__ */ jsx26("strong", { children: inherited.length }),
2509
- /* @__PURE__ */ jsx26("span", { children: "Inherited pages" })
2789
+ return /* @__PURE__ */ jsxs28(AdminPage, { children: [
2790
+ /* @__PURE__ */ jsxs28(Panel, { children: [
2791
+ /* @__PURE__ */ jsx30("div", { className: "card-label", children: "Member content" }),
2792
+ /* @__PURE__ */ jsx30("h2", { children: "One catalog, two clear owners" }),
2793
+ /* @__PURE__ */ jsx30("p", { children: "Parent pages are inherited and read-only here. Chapter pages and delegated upsells are edited in the local document. Access uses exact tier IDs; no tier order is assumed." }),
2794
+ /* @__PURE__ */ jsxs28("div", { className: "stat-band", children: [
2795
+ /* @__PURE__ */ jsxs28("div", { children: [
2796
+ /* @__PURE__ */ jsx30("strong", { children: inherited.length }),
2797
+ /* @__PURE__ */ jsx30("span", { children: "Inherited pages" })
2510
2798
  ] }),
2511
- /* @__PURE__ */ jsxs24("div", { children: [
2512
- /* @__PURE__ */ jsx26("strong", { children: local.length }),
2513
- /* @__PURE__ */ jsx26("span", { children: "Chapter pages" })
2799
+ /* @__PURE__ */ jsxs28("div", { children: [
2800
+ /* @__PURE__ */ jsx30("strong", { children: local.length }),
2801
+ /* @__PURE__ */ jsx30("span", { children: "Chapter pages" })
2514
2802
  ] }),
2515
- /* @__PURE__ */ jsxs24("div", { children: [
2516
- /* @__PURE__ */ jsx26("strong", { children: data.tiers.length }),
2517
- /* @__PURE__ */ jsx26("span", { children: "Declared tiers" })
2803
+ /* @__PURE__ */ jsxs28("div", { children: [
2804
+ /* @__PURE__ */ jsx30("strong", { children: data.tiers.length }),
2805
+ /* @__PURE__ */ jsx30("span", { children: "Declared tiers" })
2518
2806
  ] })
2519
2807
  ] })
2520
2808
  ] }),
2521
- /* @__PURE__ */ jsxs24(Panel, { children: [
2522
- /* @__PURE__ */ jsx26("div", { className: "card-label", children: "Inherited \xB7 read only" }),
2523
- /* @__PURE__ */ jsxs24("h2", { children: [
2809
+ /* @__PURE__ */ jsxs28(Panel, { children: [
2810
+ /* @__PURE__ */ jsx30("div", { className: "card-label", children: "Inherited \xB7 read only" }),
2811
+ /* @__PURE__ */ jsxs28("h2", { children: [
2524
2812
  "Parent pages ",
2525
2813
  data.parent ? `\xB7 revision ${data.parent.revision}` : ""
2526
2814
  ] }),
2527
- inherited.length === 0 ? /* @__PURE__ */ jsx26(AdminNote, { children: "No Parent pages have been delivered." }) : /* @__PURE__ */ jsx26("div", { className: "data-list", "data-member-content-inherited": true, children: inherited.map((page) => /* @__PURE__ */ jsxs24("article", { className: "card", children: [
2528
- /* @__PURE__ */ jsx26("strong", { children: page.title }),
2529
- /* @__PURE__ */ jsxs24("div", { className: "meeting-note", children: [
2815
+ inherited.length === 0 ? /* @__PURE__ */ jsx30(AdminNote, { children: "No Parent pages have been delivered." }) : /* @__PURE__ */ jsx30("div", { className: "data-list", "data-member-content-inherited": true, children: inherited.map((page) => /* @__PURE__ */ jsxs28("article", { className: "card", children: [
2816
+ /* @__PURE__ */ jsx30("strong", { children: page.title }),
2817
+ /* @__PURE__ */ jsxs28("div", { className: "meeting-note", children: [
2530
2818
  "/",
2531
2819
  page.slug,
2532
2820
  " \xB7 ",
@@ -2534,22 +2822,22 @@ function MemberContentAdmin({
2534
2822
  " \xB7 ",
2535
2823
  accessLabel(page)
2536
2824
  ] }),
2537
- /* @__PURE__ */ jsxs24("div", { className: "meeting-note", children: [
2825
+ /* @__PURE__ */ jsxs28("div", { className: "meeting-note", children: [
2538
2826
  "Upsell: ",
2539
2827
  page.upsell ? `${page.upsell.owner} controlled` : "none"
2540
2828
  ] })
2541
2829
  ] }, page.id)) })
2542
2830
  ] }),
2543
- /* @__PURE__ */ jsxs24(Panel, { children: [
2544
- /* @__PURE__ */ jsx26("div", { className: "card-label", children: "Chapter \xB7 editable" }),
2545
- /* @__PURE__ */ jsxs24("h2", { children: [
2831
+ /* @__PURE__ */ jsxs28(Panel, { children: [
2832
+ /* @__PURE__ */ jsx30("div", { className: "card-label", children: "Chapter \xB7 editable" }),
2833
+ /* @__PURE__ */ jsxs28("h2", { children: [
2546
2834
  "Local document \xB7 revision ",
2547
2835
  data.chapter?.revision ?? 0
2548
2836
  ] }),
2549
- /* @__PURE__ */ jsx26("p", { className: "meeting-note", children: "Use the published MemberContentDocument fields. The server supplies schemaVersion, revision, timestamp, and chapter source; unknown fields and undeclared tiers are rejected." }),
2550
- /* @__PURE__ */ jsxs24("label", { className: "field", children: [
2551
- /* @__PURE__ */ jsx26("span", { children: "Pages and delegated upsells (JSON)" }),
2552
- /* @__PURE__ */ jsx26(
2837
+ /* @__PURE__ */ jsx30("p", { className: "meeting-note", children: "Use the published MemberContentDocument fields. The server supplies schemaVersion, revision, timestamp, and chapter source; unknown fields and undeclared tiers are rejected." }),
2838
+ /* @__PURE__ */ jsxs28("label", { className: "field", children: [
2839
+ /* @__PURE__ */ jsx30("span", { children: "Pages and delegated upsells (JSON)" }),
2840
+ /* @__PURE__ */ jsx30(
2553
2841
  "textarea",
2554
2842
  {
2555
2843
  rows: 24,
@@ -2560,12 +2848,12 @@ function MemberContentAdmin({
2560
2848
  }
2561
2849
  )
2562
2850
  ] }),
2563
- saveError ? /* @__PURE__ */ jsxs24("div", { className: "notice danger", role: "alert", children: [
2564
- /* @__PURE__ */ jsx26("strong", { children: "Fix these items before saving:" }),
2565
- /* @__PURE__ */ jsx26("ul", { children: saveError.map((error) => /* @__PURE__ */ jsx26("li", { children: error }, error)) })
2851
+ saveError ? /* @__PURE__ */ jsxs28("div", { className: "notice danger", role: "alert", children: [
2852
+ /* @__PURE__ */ jsx30("strong", { children: "Fix these items before saving:" }),
2853
+ /* @__PURE__ */ jsx30("ul", { children: saveError.map((error) => /* @__PURE__ */ jsx30("li", { children: error }, error)) })
2566
2854
  ] }) : null,
2567
- /* @__PURE__ */ jsx26("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring || saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save chapter content" }),
2568
- !data.localAuthoring ? /* @__PURE__ */ jsx26(AdminNote, { children: "Local authoring is disabled in the checked-in Chapter config." }) : null
2855
+ /* @__PURE__ */ jsx30("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring || saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save chapter content" }),
2856
+ !data.localAuthoring ? /* @__PURE__ */ jsx30(AdminNote, { children: "Local authoring is disabled in the checked-in Chapter config." }) : null
2569
2857
  ] })
2570
2858
  ] });
2571
2859
  }
@@ -2573,12 +2861,12 @@ function memberContentSection() {
2573
2861
  return {
2574
2862
  id: "member-content",
2575
2863
  label: "Member content",
2576
- render: (ctx) => /* @__PURE__ */ jsx26(MemberContentAdmin, { ctx })
2864
+ render: (ctx) => /* @__PURE__ */ jsx30(MemberContentAdmin, { ctx })
2577
2865
  };
2578
2866
  }
2579
2867
 
2580
2868
  // src/ui/admin-settings-workspace.tsx
2581
- import { jsx as jsx27 } from "preact/jsx-runtime";
2869
+ import { jsx as jsx31 } from "preact/jsx-runtime";
2582
2870
  var viewContext = (ctx, viewId, active) => {
2583
2871
  const route = { workspaceId: ctx.route.workspaceId, viewId, ...active && ctx.route.recordId ? { recordId: ctx.route.recordId } : {}, ...active && ctx.route.detailTab ? { detailTab: ctx.route.detailTab } : {} };
2584
2872
  const targetFromView = (target) => {
@@ -2596,7 +2884,7 @@ function SettingsWorkspace({ chapter, ctx }) {
2596
2884
  const email = emailSection({ label: copy.workspaces.email });
2597
2885
  const content = memberContentSection();
2598
2886
  const library = builderLibrarySection();
2599
- return /* @__PURE__ */ jsx27(Tabs2, { ariaLabel: copy.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
2887
+ return /* @__PURE__ */ jsx31(Tabs2, { ariaLabel: copy.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
2600
2888
  { value: "calendar", label: copy.workspaces.calendar, href: ctx.href({ viewId: "calendar", recordId: null, detailTab: null }), panel: calendar.render(viewContext(ctx, "calendar", active === "calendar")) },
2601
2889
  { value: "email", label: copy.workspaces.email, href: ctx.href({ viewId: "email", recordId: null, detailTab: null }), panel: email.render(viewContext(ctx, "email", active === "email")) },
2602
2890
  ...chapter.memberContent ? [{ value: "member-content", label: "Member content", href: ctx.href({ viewId: "member-content", recordId: null, detailTab: null }), panel: content.render(viewContext(ctx, "member-content", active === "member-content")) }] : [],
@@ -2607,14 +2895,14 @@ function LeaderSettingsWorkspace({ chapter, ctx }) {
2607
2895
  const email = emailSection({ label: chapter.copy.admin.workspaces.email });
2608
2896
  const library = builderLibrarySection();
2609
2897
  const active = ctx.route.viewId === "builder-library" && chapter.builderLibrary ? "builder-library" : "email";
2610
- return /* @__PURE__ */ jsx27(Tabs2, { ariaLabel: chapter.copy.admin.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
2898
+ return /* @__PURE__ */ jsx31(Tabs2, { ariaLabel: chapter.copy.admin.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
2611
2899
  { value: "email", label: chapter.copy.admin.workspaces.email, href: ctx.href({ viewId: "email", recordId: null, detailTab: null }), panel: email.render(viewContext(ctx, "email", active === "email")) },
2612
2900
  ...chapter.builderLibrary ? [{ value: "builder-library", label: "Builder Library", href: ctx.href({ viewId: "builder-library", recordId: null, detailTab: null }), panel: library.render(viewContext(ctx, "builder-library", active === "builder-library")) }] : []
2613
2901
  ] });
2614
2902
  }
2615
2903
 
2616
2904
  // src/ui/admin-workspaces.tsx
2617
- import { jsx as jsx28 } from "preact/jsx-runtime";
2905
+ import { jsx as jsx32 } from "preact/jsx-runtime";
2618
2906
  var adminViewContext = (ctx, viewId, active) => {
2619
2907
  const route = {
2620
2908
  workspaceId: ctx.route.workspaceId,
@@ -2640,7 +2928,7 @@ function DashboardWorkspace({ chapter, ctx }) {
2640
2928
  const active = ctx.route.viewId === "billing" ? "billing" : "overview";
2641
2929
  const overview = dashboardSection({ id: "overview", label: copy.workspaces.overview });
2642
2930
  const billing = billingSection({ label: copy.workspaces.billing });
2643
- return /* @__PURE__ */ jsx28(
2931
+ return /* @__PURE__ */ jsx32(
2644
2932
  Tabs3,
2645
2933
  {
2646
2934
  ariaLabel: copy.workspaces.dashboardViewsLabel,
@@ -2668,7 +2956,7 @@ function PeopleWorkspace({ chapter, ctx }) {
2668
2956
  const fallback = types[0]?.[0] ?? "person";
2669
2957
  const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
2670
2958
  const networkSharing = chapter.network.targets.length > 0;
2671
- return /* @__PURE__ */ jsx28(
2959
+ return /* @__PURE__ */ jsx32(
2672
2960
  Tabs3,
2673
2961
  {
2674
2962
  ariaLabel: chapter.copy.admin.workspaces.collectionsLabel,
@@ -2681,7 +2969,8 @@ function PeopleWorkspace({ chapter, ctx }) {
2681
2969
  type,
2682
2970
  lifecycle: chapter.mode === "chapter" && type === "person",
2683
2971
  roles: chapter.auth.ladder,
2684
- networkSharing
2972
+ networkSharing,
2973
+ applicationStages: chapter.pipeline.stages
2685
2974
  });
2686
2975
  return {
2687
2976
  value: type,
@@ -2698,8 +2987,8 @@ function PortfolioWorkspace({ chapter, ctx }) {
2698
2987
  const types = Object.entries(chapter.crm.config.types).filter(([, def]) => def.workspace === "portfolio");
2699
2988
  const fallback = types[0]?.[0] ?? "";
2700
2989
  const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
2701
- if (!active) return /* @__PURE__ */ jsx28(LeaderNetworkOverview, { ctx });
2702
- return /* @__PURE__ */ jsx28(
2990
+ if (!active) return /* @__PURE__ */ jsx32(LeaderNetworkOverview, { ctx });
2991
+ return /* @__PURE__ */ jsx32(
2703
2992
  Tabs3,
2704
2993
  {
2705
2994
  ariaLabel: copy.workspaces.portfolioViewsLabel,
@@ -2723,7 +3012,7 @@ function PortfolioWorkspace({ chapter, ctx }) {
2723
3012
  );
2724
3013
  }
2725
3014
  function LeaderDashboardWorkspace({ chapter, ctx }) {
2726
- return /* @__PURE__ */ jsx28(
3015
+ return /* @__PURE__ */ jsx32(
2727
3016
  Tabs3,
2728
3017
  {
2729
3018
  ariaLabel: chapter.copy.admin.workspaces.dashboardViewsLabel,
@@ -2733,7 +3022,7 @@ function LeaderDashboardWorkspace({ chapter, ctx }) {
2733
3022
  value: "overview",
2734
3023
  label: chapter.copy.admin.workspaces.overview,
2735
3024
  href: ctx.href({ viewId: "overview", recordId: null, detailTab: null }),
2736
- panel: /* @__PURE__ */ jsx28(LeaderNetworkOverview, { ctx: adminViewContext(ctx, "overview", true) })
3025
+ panel: /* @__PURE__ */ jsx32(LeaderNetworkOverview, { ctx: adminViewContext(ctx, "overview", true) })
2737
3026
  }]
2738
3027
  }
2739
3028
  );
@@ -2744,7 +3033,7 @@ function defaultAdminWorkspaces(chapter) {
2744
3033
  id: "people",
2745
3034
  label: copy.workspaces.people,
2746
3035
  defaultViewId: Object.keys(chapter.crm.config.types)[0] ?? "person",
2747
- render: (ctx) => /* @__PURE__ */ jsx28(PeopleWorkspace, { chapter, ctx })
3036
+ render: (ctx) => /* @__PURE__ */ jsx32(PeopleWorkspace, { chapter, ctx })
2748
3037
  };
2749
3038
  if (chapter.mode === "hub" && chapter.network.targets.length === 0) return [people];
2750
3039
  if (chapter.mode === "hub") {
@@ -2754,7 +3043,7 @@ function defaultAdminWorkspaces(chapter) {
2754
3043
  id: "dashboard",
2755
3044
  label: copy.workspaces.dashboard,
2756
3045
  defaultViewId: "overview",
2757
- render: (ctx) => /* @__PURE__ */ jsx28(LeaderDashboardWorkspace, { chapter, ctx })
3046
+ render: (ctx) => /* @__PURE__ */ jsx32(LeaderDashboardWorkspace, { chapter, ctx })
2758
3047
  },
2759
3048
  networkRecordsWorkspace(chapter),
2760
3049
  people,
@@ -2762,13 +3051,13 @@ function defaultAdminWorkspaces(chapter) {
2762
3051
  id: "portfolio",
2763
3052
  label: copy.workspaces.portfolio,
2764
3053
  defaultViewId: portfolioTypes[0]?.[0],
2765
- render: (ctx) => /* @__PURE__ */ jsx28(PortfolioWorkspace, { chapter, ctx })
3054
+ render: (ctx) => /* @__PURE__ */ jsx32(PortfolioWorkspace, { chapter, ctx })
2766
3055
  },
2767
3056
  {
2768
3057
  id: "settings",
2769
3058
  label: copy.workspaces.settings,
2770
3059
  defaultViewId: "email",
2771
- render: (ctx) => /* @__PURE__ */ jsx28(LeaderSettingsWorkspace, { chapter, ctx })
3060
+ render: (ctx) => /* @__PURE__ */ jsx32(LeaderSettingsWorkspace, { chapter, ctx })
2772
3061
  }
2773
3062
  ];
2774
3063
  }
@@ -2777,7 +3066,7 @@ function defaultAdminWorkspaces(chapter) {
2777
3066
  id: "dashboard",
2778
3067
  label: copy.workspaces.dashboard,
2779
3068
  defaultViewId: "overview",
2780
- render: (ctx) => /* @__PURE__ */ jsx28(DashboardWorkspace, { chapter, ctx })
3069
+ render: (ctx) => /* @__PURE__ */ jsx32(DashboardWorkspace, { chapter, ctx })
2781
3070
  },
2782
3071
  people,
2783
3072
  admissionGrantsWorkspace(copy.workspaces.admission),
@@ -2785,17 +3074,17 @@ function defaultAdminWorkspaces(chapter) {
2785
3074
  id: "settings",
2786
3075
  label: copy.workspaces.settings,
2787
3076
  defaultViewId: "calendar",
2788
- render: (ctx) => /* @__PURE__ */ jsx28(SettingsWorkspace, { chapter, ctx })
3077
+ render: (ctx) => /* @__PURE__ */ jsx32(SettingsWorkspace, { chapter, ctx })
2789
3078
  }
2790
3079
  ];
2791
3080
  }
2792
3081
 
2793
3082
  // src/ui/admin-frame.tsx
2794
3083
  import { ThemeScope as ThemeScope2 } from "@odla-ai/ui/components";
2795
- import { jsx as jsx29, jsxs as jsxs25 } from "preact/jsx-runtime";
3084
+ import { jsx as jsx33, jsxs as jsxs29 } from "preact/jsx-runtime";
2796
3085
  function AdminTheme(props) {
2797
3086
  const brand = props.chapter?.brand;
2798
- return /* @__PURE__ */ jsx29(ChapterCopyProvider, { copy: props.chapter?.copy, children: /* @__PURE__ */ jsxs25(
3087
+ return /* @__PURE__ */ jsx33(ChapterCopyProvider, { copy: props.chapter?.copy, children: /* @__PURE__ */ jsxs29(
2799
3088
  ThemeScope2,
2800
3089
  {
2801
3090
  ref: props.scopeRef,
@@ -2804,7 +3093,7 @@ function AdminTheme(props) {
2804
3093
  accent: brand?.accent,
2805
3094
  colorScheme: brand?.colorScheme ?? "light",
2806
3095
  children: [
2807
- /* @__PURE__ */ jsx29(BrandStyle, { brand, selector: "[data-chapter-admin]" }),
3096
+ /* @__PURE__ */ jsx33(BrandStyle, { brand, selector: "[data-chapter-admin]" }),
2808
3097
  props.children
2809
3098
  ]
2810
3099
  }
@@ -2824,10 +3113,10 @@ function signInRedirect(basePath, workspaces) {
2824
3113
  }
2825
3114
 
2826
3115
  // src/ui/admin-appearance.ts
2827
- import { useEffect as useEffect11, useState as useState21 } from "preact/hooks";
3116
+ import { useEffect as useEffect11, useState as useState26 } from "preact/hooks";
2828
3117
  import { clerkAppearanceFromTokens } from "@odla-ai/auth-clerk";
2829
3118
  function useScopedClerkAppearance(scope) {
2830
- const [appearance, setAppearance] = useState21();
3119
+ const [appearance, setAppearance] = useState26();
2831
3120
  useEffect11(() => {
2832
3121
  setAppearance(clerkAppearanceFromTokens(scope.current ?? void 0));
2833
3122
  }, [scope]);
@@ -2859,7 +3148,7 @@ async function loadChapterAdminUser(adapter, apiBase, getToken) {
2859
3148
  }
2860
3149
 
2861
3150
  // src/ui/admin.tsx
2862
- import { jsx as jsx30, jsxs as jsxs26 } from "preact/jsx-runtime";
3151
+ import { jsx as jsx34, jsxs as jsxs30 } from "preact/jsx-runtime";
2863
3152
  function Authed(props) {
2864
3153
  const copy = useChapterCopy().admin;
2865
3154
  const {
@@ -2887,7 +3176,7 @@ function Authed(props) {
2887
3176
  }),
2888
3177
  [getToken, crmBasePath]
2889
3178
  );
2890
- const [state, setState] = useState22({ status: "checking" });
3179
+ const [state, setState] = useState27({ status: "checking" });
2891
3180
  useEffect12(() => {
2892
3181
  let live = true;
2893
3182
  void (async () => {
@@ -2907,17 +3196,17 @@ function Authed(props) {
2907
3196
  live = false;
2908
3197
  };
2909
3198
  }, [getToken, apiBase, auth]);
2910
- if (state.status === "checking") return /* @__PURE__ */ jsx30(Gate, { brand, children: /* @__PURE__ */ jsx30("p", { style: S.muted, children: copy.auth.checking }) });
3199
+ if (state.status === "checking") return /* @__PURE__ */ jsx34(Gate, { brand, children: /* @__PURE__ */ jsx34("p", { style: S.muted, children: copy.auth.checking }) });
2911
3200
  if (state.status === "denied") {
2912
- return /* @__PURE__ */ jsx30(Gate, { brand, children: /* @__PURE__ */ jsxs26("div", { className: "card", style: S.card, children: [
2913
- /* @__PURE__ */ jsx30("h2", { style: { marginTop: 0 }, children: copy.auth.notAuthorized }),
2914
- /* @__PURE__ */ jsx30("p", { style: S.muted, children: formatChapterCopy(copy.auth.accountNotAuthorized, {
3201
+ return /* @__PURE__ */ jsx34(Gate, { brand, children: /* @__PURE__ */ jsxs30("div", { className: "card", style: S.card, children: [
3202
+ /* @__PURE__ */ jsx34("h2", { style: { marginTop: 0 }, children: copy.auth.notAuthorized }),
3203
+ /* @__PURE__ */ jsx34("p", { style: S.muted, children: formatChapterCopy(copy.auth.accountNotAuthorized, {
2915
3204
  account: state.email ?? copy.auth.thisAccount
2916
3205
  }) }),
2917
- /* @__PURE__ */ jsx30("button", { className: "btn secondary", onClick: () => signOut(), children: copy.auth.signOut })
3206
+ /* @__PURE__ */ jsx34("button", { className: "btn secondary", onClick: () => signOut(), children: copy.auth.signOut })
2918
3207
  ] }) });
2919
3208
  }
2920
- return /* @__PURE__ */ jsx30(
3209
+ return /* @__PURE__ */ jsx34(
2921
3210
  AdminShell,
2922
3211
  {
2923
3212
  workspaces,
@@ -2959,7 +3248,7 @@ function ChapterAdmin(props) {
2959
3248
  const chrome = props.chrome ?? "embedded";
2960
3249
  const auth = props.auth ?? DEFAULT_ADMIN_AUTH;
2961
3250
  const redirect = signInRedirect(basePath, workspaces);
2962
- const [publishableKey, setPublishableKey] = useState22(void 0);
3251
+ const [publishableKey, setPublishableKey] = useState27(void 0);
2963
3252
  const scopeRef = useRef3(null);
2964
3253
  const appearance = useScopedClerkAppearance(scopeRef);
2965
3254
  useEffect12(() => {
@@ -2971,23 +3260,23 @@ function ChapterAdmin(props) {
2971
3260
  }, [apiBase, auth]);
2972
3261
  let content;
2973
3262
  if (publishableKey === void 0 || publishableKey && !appearance) {
2974
- content = /* @__PURE__ */ jsx30(Gate, { brand, children: /* @__PURE__ */ jsx30("p", { style: S.muted, children: copy.admin.auth.loading }) });
3263
+ content = /* @__PURE__ */ jsx34(Gate, { brand, children: /* @__PURE__ */ jsx34("p", { style: S.muted, children: copy.admin.auth.loading }) });
2975
3264
  } else if (!publishableKey) {
2976
- content = /* @__PURE__ */ jsx30(Gate, { brand, children: /* @__PURE__ */ jsxs26("div", { className: "card", style: S.card, children: [
2977
- /* @__PURE__ */ jsx30("h2", { style: { marginTop: 0 }, children: copy.admin.auth.signInNotConfigured }),
2978
- /* @__PURE__ */ jsx30("p", { style: S.muted, children: copy.admin.auth.missingPublishableKey })
3265
+ content = /* @__PURE__ */ jsx34(Gate, { brand, children: /* @__PURE__ */ jsxs30("div", { className: "card", style: S.card, children: [
3266
+ /* @__PURE__ */ jsx34("h2", { style: { marginTop: 0 }, children: copy.admin.auth.signInNotConfigured }),
3267
+ /* @__PURE__ */ jsx34("p", { style: S.muted, children: copy.admin.auth.missingPublishableKey })
2979
3268
  ] }) });
2980
3269
  } else if (workspaces.length === 0) {
2981
- content = /* @__PURE__ */ jsx30(Gate, { brand, children: /* @__PURE__ */ jsx30("p", { style: S.muted, children: copy.admin.auth.noWorkspaces }) });
3270
+ content = /* @__PURE__ */ jsx34(Gate, { brand, children: /* @__PURE__ */ jsx34("p", { style: S.muted, children: copy.admin.auth.noWorkspaces }) });
2982
3271
  } else {
2983
- content = /* @__PURE__ */ jsxs26(
3272
+ content = /* @__PURE__ */ jsxs30(
2984
3273
  ClerkGate,
2985
3274
  {
2986
3275
  publishableKey,
2987
3276
  appearance,
2988
3277
  afterSignOutUrl: "/",
2989
3278
  children: [
2990
- /* @__PURE__ */ jsx30(SignedOut, { children: /* @__PURE__ */ jsx30(Gate, { brand, tagline: copy.admin.auth.signInTagline, children: /* @__PURE__ */ jsx30(
3279
+ /* @__PURE__ */ jsx34(SignedOut, { children: /* @__PURE__ */ jsx34(Gate, { brand, tagline: copy.admin.auth.signInTagline, children: /* @__PURE__ */ jsx34(
2991
3280
  SignIn,
2992
3281
  {
2993
3282
  routing: "hash",
@@ -2995,7 +3284,7 @@ function ChapterAdmin(props) {
2995
3284
  signUpForceRedirectUrl: redirect
2996
3285
  }
2997
3286
  ) }) }),
2998
- /* @__PURE__ */ jsx30(SignedIn, { children: /* @__PURE__ */ jsx30(
3287
+ /* @__PURE__ */ jsx34(SignedIn, { children: /* @__PURE__ */ jsx34(
2999
3288
  Authed,
3000
3289
  {
3001
3290
  workspaces,
@@ -3016,7 +3305,7 @@ function ChapterAdmin(props) {
3016
3305
  }
3017
3306
  );
3018
3307
  }
3019
- return /* @__PURE__ */ jsx30(AdminTheme, { chapter: props.chapter, scopeRef, children: content });
3308
+ return /* @__PURE__ */ jsx34(AdminTheme, { chapter: props.chapter, scopeRef, children: content });
3020
3309
  }
3021
3310
 
3022
3311
  // src/ui/admin-defaults.ts
@@ -3025,17 +3314,17 @@ function defaultAdminSections(chapter) {
3025
3314
  }
3026
3315
 
3027
3316
  // src/ui/admin-meetings.tsx
3028
- import { useState as useState23 } from "preact/hooks";
3029
- import { Button as Button12 } from "@odla-ai/ui/components";
3030
- import { Fragment as Fragment8, jsx as jsx31, jsxs as jsxs27 } from "preact/jsx-runtime";
3317
+ import { useState as useState28 } from "preact/hooks";
3318
+ import { Button as Button17 } from "@odla-ai/ui/components";
3319
+ import { Fragment as Fragment12, jsx as jsx35, jsxs as jsxs31 } from "preact/jsx-runtime";
3031
3320
  var when2 = (t) => new Date(t).toLocaleString([], { dateStyle: "medium", timeStyle: "short" });
3032
3321
  function MeetingsBody({ ctx }) {
3033
3322
  const copy = useChapterCopy().admin.meetings;
3034
3323
  const { data, loading, error, refresh } = useAdminResource(ctx.getToken, "/api/admin/meetings?all=1");
3035
- const [busy, setBusy] = useState23(null);
3036
- const [note, setNote] = useState23(null);
3037
- if (loading) return /* @__PURE__ */ jsx31(AdminNote, { children: copy.loading });
3038
- if (error || !data) return /* @__PURE__ */ jsxs27(AdminNote, { children: [
3324
+ const [busy, setBusy] = useState28(null);
3325
+ const [note, setNote] = useState28(null);
3326
+ if (loading) return /* @__PURE__ */ jsx35(AdminNote, { children: copy.loading });
3327
+ if (error || !data) return /* @__PURE__ */ jsxs31(AdminNote, { children: [
3039
3328
  copy.loadFailed,
3040
3329
  error ? `: ${error}` : "",
3041
3330
  "."
@@ -3066,43 +3355,43 @@ function MeetingsBody({ ctx }) {
3066
3355
  }
3067
3356
  void run(id, () => adminFetch(ctx.getToken, `/api/admin/meetings/${id}/reschedule`, { method: "POST", body: JSON.stringify({ startAt }) }));
3068
3357
  };
3069
- return /* @__PURE__ */ jsx31(AdminPage, { children: /* @__PURE__ */ jsx31(Panel, { title: /* @__PURE__ */ jsxs27(Fragment8, { children: [
3358
+ return /* @__PURE__ */ jsx35(AdminPage, { children: /* @__PURE__ */ jsx35(Panel, { title: /* @__PURE__ */ jsxs31(Fragment12, { children: [
3070
3359
  copy.agenda,
3071
3360
  " ",
3072
- /* @__PURE__ */ jsxs27("span", { className: "muted", style: { fontWeight: 400 }, children: [
3361
+ /* @__PURE__ */ jsxs31("span", { className: "muted", style: { fontWeight: 400 }, children: [
3073
3362
  "\xB7 ",
3074
3363
  data.timezone
3075
3364
  ] })
3076
- ] }), actions: note ? /* @__PURE__ */ jsx31("span", { className: "muted", children: note }) : void 0, children: data.meetings.length === 0 ? /* @__PURE__ */ jsx31("p", { className: "muted", style: { margin: 0 }, children: copy.empty }) : /* @__PURE__ */ jsx31("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 12 }, children: data.meetings.map((m) => /* @__PURE__ */ jsxs27("li", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap", opacity: m.status === "cancelled" ? 0.55 : 1 }, children: [
3077
- /* @__PURE__ */ jsx31("strong", { style: { minWidth: 170 }, children: when2(m.startAt) }),
3078
- /* @__PURE__ */ jsx31("span", { style: { flex: 1 }, children: m.applicant ? `${m.applicant.name} \xB7 ${m.applicant.email}` : copy.unknown }),
3079
- /* @__PURE__ */ jsx31("span", { className: "badge", children: m.status }),
3080
- m.drift && m.drift !== "none" ? /* @__PURE__ */ jsxs27("span", { className: "badge", children: [
3365
+ ] }), actions: note ? /* @__PURE__ */ jsx35("span", { className: "muted", children: note }) : void 0, children: data.meetings.length === 0 ? /* @__PURE__ */ jsx35("p", { className: "muted", style: { margin: 0 }, children: copy.empty }) : /* @__PURE__ */ jsx35("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 12 }, children: data.meetings.map((m) => /* @__PURE__ */ jsxs31("li", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap", opacity: m.status === "cancelled" ? 0.55 : 1 }, children: [
3366
+ /* @__PURE__ */ jsx35("strong", { style: { minWidth: 170 }, children: when2(m.startAt) }),
3367
+ /* @__PURE__ */ jsx35("span", { style: { flex: 1 }, children: m.applicant ? `${m.applicant.name} \xB7 ${m.applicant.email}` : copy.unknown }),
3368
+ /* @__PURE__ */ jsx35("span", { className: "badge", children: m.status }),
3369
+ m.drift && m.drift !== "none" ? /* @__PURE__ */ jsxs31("span", { className: "badge", children: [
3081
3370
  copy.drift,
3082
3371
  ": ",
3083
3372
  m.drift
3084
3373
  ] }) : null,
3085
- m.meetUrl ? /* @__PURE__ */ jsx31("a", { href: m.meetUrl, target: "_blank", rel: "noreferrer", children: copy.meet }) : null,
3086
- m.status === "scheduled" ? /* @__PURE__ */ jsxs27(Fragment8, { children: [
3087
- /* @__PURE__ */ jsx31(Button12, { variant: "secondary", mini: true, disabled: busy === m.id, onClick: () => reschedule(m.id), children: copy.reschedule }),
3088
- /* @__PURE__ */ jsx31(Button12, { variant: "danger", mini: true, disabled: busy === m.id, onClick: () => cancel(m.id), children: copy.cancel })
3374
+ m.meetUrl ? /* @__PURE__ */ jsx35("a", { href: m.meetUrl, target: "_blank", rel: "noreferrer", children: copy.meet }) : null,
3375
+ m.status === "scheduled" ? /* @__PURE__ */ jsxs31(Fragment12, { children: [
3376
+ /* @__PURE__ */ jsx35(Button17, { variant: "secondary", mini: true, disabled: busy === m.id, onClick: () => reschedule(m.id), children: copy.reschedule }),
3377
+ /* @__PURE__ */ jsx35(Button17, { variant: "danger", mini: true, disabled: busy === m.id, onClick: () => cancel(m.id), children: copy.cancel })
3089
3378
  ] }) : null
3090
3379
  ] }, m.id)) }) }) });
3091
3380
  }
3092
3381
  function meetingsSection(options = {}) {
3093
3382
  const { id = "meetings", label = "Meetings" } = options;
3094
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx31(MeetingsBody, { ctx }) };
3383
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx35(MeetingsBody, { ctx }) };
3095
3384
  }
3096
3385
 
3097
3386
  // src/ui/admin-network-record-editor.tsx
3098
- import { Button as Button13, Field as Field10, Select as Select6 } from "@odla-ai/ui/components";
3099
- import { useRef as useRef4, useState as useState24 } from "preact/hooks";
3100
- import { Fragment as Fragment9, jsx as jsx32, jsxs as jsxs28 } from "preact/jsx-runtime";
3387
+ import { Button as Button18, Field as Field12, Select as Select8 } from "@odla-ai/ui/components";
3388
+ import { useRef as useRef4, useState as useState29 } from "preact/hooks";
3389
+ import { Fragment as Fragment13, jsx as jsx36, jsxs as jsxs32 } from "preact/jsx-runtime";
3101
3390
  function NetworkRecordEditor(props) {
3102
3391
  const { ctx, record } = props;
3103
- const [stage, setStage] = useState24("");
3104
- const [busy, setBusy] = useState24(false);
3105
- const [error, setError] = useState24(null);
3392
+ const [stage, setStage] = useState29("");
3393
+ const [busy, setBusy] = useState29(false);
3394
+ const [error, setError] = useState29(null);
3106
3395
  const attempt = useRef4(null);
3107
3396
  const pending = record.edit?.pendingAction;
3108
3397
  const superAdmin = ctx.currentUser?.superAdmin === true;
@@ -3135,11 +3424,11 @@ function NetworkRecordEditor(props) {
3135
3424
  setBusy(false);
3136
3425
  }
3137
3426
  };
3138
- return /* @__PURE__ */ jsxs28("div", { style: { display: "grid", gap: 24 }, children: [
3139
- superAdmin && record.edit ? /* @__PURE__ */ jsxs28(Fragment9, { children: [
3140
- /* @__PURE__ */ jsxs28("section", { children: [
3141
- /* @__PURE__ */ jsx32("h3", { children: "Chapter profile" }),
3142
- /* @__PURE__ */ jsx32(
3427
+ return /* @__PURE__ */ jsxs32("div", { style: { display: "grid", gap: 24 }, children: [
3428
+ superAdmin && record.edit ? /* @__PURE__ */ jsxs32(Fragment13, { children: [
3429
+ /* @__PURE__ */ jsxs32("section", { children: [
3430
+ /* @__PURE__ */ jsx36("h3", { children: "Chapter profile" }),
3431
+ /* @__PURE__ */ jsx36(
3143
3432
  OperationalProfileForm,
3144
3433
  {
3145
3434
  fields: record.edit.fields,
@@ -3149,27 +3438,27 @@ function NetworkRecordEditor(props) {
3149
3438
  `${record.id}:${record.revision}`
3150
3439
  )
3151
3440
  ] }),
3152
- /* @__PURE__ */ jsxs28("section", { style: { display: "grid", gap: 12 }, children: [
3153
- /* @__PURE__ */ jsx32("h3", { children: "Membership actions" }),
3154
- pending ? /* @__PURE__ */ jsxs28("p", { children: [
3441
+ /* @__PURE__ */ jsxs32("section", { style: { display: "grid", gap: 12 }, children: [
3442
+ /* @__PURE__ */ jsx36("h3", { children: "Membership actions" }),
3443
+ pending ? /* @__PURE__ */ jsxs32("p", { children: [
3155
3444
  "An application action is pending: ",
3156
3445
  pending.stage.replaceAll("_", " "),
3157
3446
  ". ",
3158
3447
  ownPending ? "Retry reconciles the same operation." : "The original operator must reconcile it."
3159
- ] }) : record.edit.allowedStages.length ? /* @__PURE__ */ jsx32(Field10, { label: "Action", children: /* @__PURE__ */ jsxs28(Select6, { "aria-label": "Action", value: stage, disabled: busy, onChange: (event) => setStage(event.currentTarget.value), children: [
3160
- /* @__PURE__ */ jsx32("option", { value: "", children: "Choose an action" }),
3161
- record.edit.allowedStages.map((action) => /* @__PURE__ */ jsx32("option", { value: action.id, children: action.label }, action.id))
3162
- ] }) }) : /* @__PURE__ */ jsx32("p", { children: "No membership action is currently allowed." }),
3163
- pending || record.edit.allowedStages.length ? /* @__PURE__ */ jsx32("div", { children: /* @__PURE__ */ jsx32(Button13, { disabled: busy || !ownPending || !pending && !stage, onClick: () => void move(), children: busy ? "Applying\u2026" : pending ? "Retry pending action" : "Apply action" }) }) : null,
3164
- error ? /* @__PURE__ */ jsx32("p", { role: "alert", children: error }) : null
3448
+ ] }) : record.edit.allowedStages.length ? /* @__PURE__ */ jsx36(Field12, { label: "Action", children: /* @__PURE__ */ jsxs32(Select8, { "aria-label": "Action", value: stage, disabled: busy, onChange: (event) => setStage(event.currentTarget.value), children: [
3449
+ /* @__PURE__ */ jsx36("option", { value: "", children: "Choose an action" }),
3450
+ record.edit.allowedStages.map((action) => /* @__PURE__ */ jsx36("option", { value: action.id, children: action.label }, action.id))
3451
+ ] }) }) : /* @__PURE__ */ jsx36("p", { children: "No membership action is currently allowed." }),
3452
+ pending || record.edit.allowedStages.length ? /* @__PURE__ */ jsx36("div", { children: /* @__PURE__ */ jsx36(Button18, { disabled: busy || !ownPending || !pending && !stage, onClick: () => void move(), children: busy ? "Applying\u2026" : pending ? "Retry pending action" : "Apply action" }) }) : null,
3453
+ error ? /* @__PURE__ */ jsx36("p", { role: "alert", children: error }) : null
3165
3454
  ] })
3166
3455
  ] }) : null,
3167
- superAdmin && props.admissionGrants ? /* @__PURE__ */ jsxs28("section", { children: [
3168
- /* @__PURE__ */ jsx32("h3", { children: "Next invitation" }),
3169
- /* @__PURE__ */ jsx32("p", { children: "This setting applies to the next eligible signup; it does not replace approval of an existing application." }),
3170
- /* @__PURE__ */ jsx32(LeaderAdmissionAction, { getToken: ctx.getToken, targetId: props.targetId, sourceRecordId: record.id })
3456
+ superAdmin && props.admissionGrants ? /* @__PURE__ */ jsxs32("section", { children: [
3457
+ /* @__PURE__ */ jsx36("h3", { children: "Next invitation" }),
3458
+ /* @__PURE__ */ jsx36("p", { children: "This setting applies to the next eligible signup; it does not replace approval of an existing application." }),
3459
+ /* @__PURE__ */ jsx36(LeaderAdmissionAction, { getToken: ctx.getToken, targetId: props.targetId, sourceRecordId: record.id })
3171
3460
  ] }) : null,
3172
- /* @__PURE__ */ jsx32(
3461
+ /* @__PURE__ */ jsx36(
3173
3462
  NetworkRecordDetail,
3174
3463
  {
3175
3464
  ctx,
@@ -3183,6 +3472,57 @@ function NetworkRecordEditor(props) {
3183
3472
  ] });
3184
3473
  }
3185
3474
 
3475
+ // src/ui/network-seat-billing.tsx
3476
+ import { useState as useState30 } from "preact/hooks";
3477
+ import { Button as Button19, DataTable as DataTable4 } from "@odla-ai/ui/components";
3478
+ import { jsx as jsx37, jsxs as jsxs33 } from "preact/jsx-runtime";
3479
+ var money3 = (row, cents) => row.currency ? new Intl.NumberFormat("en-US", {
3480
+ style: "currency",
3481
+ currency: row.currency
3482
+ }).format(cents / 100) : "Unknown";
3483
+ var columns2 = (refund, busy) => [
3484
+ { key: "seatId", header: "Seat", cell: (row) => /* @__PURE__ */ jsx37("code", { children: row.seatId }) },
3485
+ { key: "sourceKey", header: "Chapter / runtime", cell: (row) => row.sourceKey },
3486
+ { key: "status", header: "Payment", cell: (row) => row.status ?? "Unknown" },
3487
+ { key: "amountReceivedCents", header: "Collected", cell: (row) => money3(row, row.amountReceivedCents) },
3488
+ { key: "refundedCents", header: "Refunded", cell: (row) => money3(row, row.refundedCents) },
3489
+ { key: "membershipId", header: "Primary membership", cell: (row) => /* @__PURE__ */ jsx37("code", { children: row.membershipId }) },
3490
+ { key: "paymentIntentId", header: "Stripe payment", cell: (row) => /* @__PURE__ */ jsx37("code", { children: row.paymentIntentId }) },
3491
+ { key: "subscriptionItemId", header: "Renewal item", cell: (row) => row.subscriptionItemId ? /* @__PURE__ */ jsx37("code", { children: row.subscriptionItemId }) : "Awaiting provider linkage" },
3492
+ { key: "currentPeriodEnd", header: "Paid through", cell: (row) => row.currentPeriodEnd ? new Date(row.currentPeriodEnd * 1e3).toLocaleDateString() : "Awaiting provider linkage" },
3493
+ { key: "refund", header: "Refund", cell: (row) => row.refundedCents < row.amountReceivedCents ? /* @__PURE__ */ jsx37(Button19, { variant: "danger", mini: true, disabled: busy !== null, onClick: () => refund(row), children: busy === row.seatId ? "Refunding\u2026" : "Refund seat" }) : "Refunded" }
3494
+ ];
3495
+ function NetworkSeatBilling(props) {
3496
+ const { data, loading, error, refresh } = useAdminResource(props.getToken, "/api/admin/network-commercial-read-model");
3497
+ const [busy, setBusy] = useState30(null);
3498
+ const [note, setNote] = useState30(null);
3499
+ const refund = async (row) => {
3500
+ setBusy(row.seatId);
3501
+ setNote(null);
3502
+ try {
3503
+ const receipt = await adminFetch(
3504
+ props.getToken,
3505
+ `/api/admin/membership-seats/${encodeURIComponent(row.seatId)}/refund`,
3506
+ { method: "POST" }
3507
+ );
3508
+ setNote(receipt.replayed ? `Seat ${row.seatId} was already refunded.` : `Refunded ${money3(row, receipt.refundedCents ?? row.amountReceivedCents)} for seat ${row.seatId}.`);
3509
+ refresh();
3510
+ } catch (failure) {
3511
+ setNote(failure instanceof Error ? failure.message : "Refund could not be completed.");
3512
+ } finally {
3513
+ setBusy(null);
3514
+ }
3515
+ };
3516
+ return /* @__PURE__ */ jsxs33(Panel, { title: "Additional membership seats", children: [
3517
+ /* @__PURE__ */ jsx37("p", { children: "Seat payments are included in the network totals. Renewal items share the primary subscription\u2019s term. An unaccepted seat is never refunded automatically." }),
3518
+ loading ? /* @__PURE__ */ jsx37("p", { children: "Loading seats\u2026" }) : error ? /* @__PURE__ */ jsxs33("p", { role: "alert", children: [
3519
+ "Seats could not be loaded: ",
3520
+ error
3521
+ ] }) : /* @__PURE__ */ jsx37(DataTable4, { rows: data?.seats ?? [], columns: columns2((row) => void refund(row), busy), rowKey: (row) => `${row.sourceKey}:${row.seatId}` }),
3522
+ note ? /* @__PURE__ */ jsx37("p", { role: "status", children: note }) : null
3523
+ ] });
3524
+ }
3525
+
3186
3526
  export {
3187
3527
  AdminPage,
3188
3528
  Panel,
@@ -3194,11 +3534,16 @@ export {
3194
3534
  adminSectionHref,
3195
3535
  adminFetch,
3196
3536
  useAdminResource,
3537
+ PaymentRecoveryQueue,
3197
3538
  billingSection,
3198
3539
  dashboardSection,
3540
+ applicationLifecycleAdapter,
3541
+ NamedSeatRecordPanel,
3542
+ APPLICATION_STAGES,
3543
+ CandidateStagePanel,
3544
+ RecordAdmissionPanel,
3199
3545
  RecordActions,
3200
3546
  NetworkShareActions,
3201
- applicationLifecycleAdapter,
3202
3547
  collectionSection,
3203
3548
  peopleSection,
3204
3549
  NetworkRecordsWorkspace,
@@ -3219,6 +3564,7 @@ export {
3219
3564
  ChapterAdmin,
3220
3565
  defaultAdminSections,
3221
3566
  meetingsSection,
3222
- NetworkRecordEditor
3567
+ NetworkRecordEditor,
3568
+ NetworkSeatBilling
3223
3569
  };
3224
- //# sourceMappingURL=chunk-MQ4OPZCS.js.map
3570
+ //# sourceMappingURL=chunk-4EA5V4JE.js.map