@odla-ai/chapter 0.47.9 → 0.48.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.
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-4HS2JPE2.js";
8
8
 
9
9
  // src/ui/admin.tsx
10
- import { useEffect as useEffect11, useMemo as useMemo3, useRef, useState as useState17 } from "preact/hooks";
10
+ import { useEffect as useEffect12, useMemo as useMemo3, useRef as useRef3, useState as useState22 } 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
 
@@ -176,6 +176,24 @@ function Gate(props) {
176
176
  ] }) });
177
177
  }
178
178
 
179
+ // src/ui/admin-route-merge.ts
180
+ function mergeAdminRoute(current, target) {
181
+ if (typeof target === "string") return { workspaceId: target };
182
+ const changingWorkspace = target.workspaceId != null && target.workspaceId !== current.workspaceId;
183
+ const next = changingWorkspace ? { workspaceId: target.workspaceId } : { ...current, ...target.workspaceId ? { workspaceId: target.workspaceId } : {} };
184
+ for (const key of ["viewId", "recordId", "detailTab"]) {
185
+ const value = target[key];
186
+ if (value === null) delete next[key];
187
+ else if (value !== void 0) next[key] = value;
188
+ }
189
+ if (target.viewId !== void 0 && target.recordId === void 0) {
190
+ delete next.recordId;
191
+ delete next.detailTab;
192
+ }
193
+ if (target.recordId === null) delete next.detailTab;
194
+ return next;
195
+ }
196
+
179
197
  // src/ui/admin-route.ts
180
198
  import { parseCrmDiscussionReference } from "@odla-ai/crm";
181
199
  var DEFAULT_ALIASES = {
@@ -276,22 +294,6 @@ function adminSectionHref(current, basePath, id, routing = "fragment") {
276
294
 
277
295
  // src/ui/chrome.tsx
278
296
  import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
279
- var mergeRoute = (current, target) => {
280
- if (typeof target === "string") return { workspaceId: target };
281
- const changingWorkspace = target.workspaceId != null && target.workspaceId !== current.workspaceId;
282
- const next = changingWorkspace ? { workspaceId: target.workspaceId } : { ...current, ...target.workspaceId ? { workspaceId: target.workspaceId } : {} };
283
- for (const key of ["viewId", "recordId", "detailTab"]) {
284
- const value = target[key];
285
- if (value === null) delete next[key];
286
- else if (value !== void 0) next[key] = value;
287
- }
288
- if (target.viewId !== void 0 && target.recordId === void 0) {
289
- delete next.recordId;
290
- delete next.detailTab;
291
- }
292
- if (target.recordId === null) delete next.detailTab;
293
- return next;
294
- };
295
297
  function AdminShell({
296
298
  workspaces,
297
299
  basePath,
@@ -305,7 +307,8 @@ function AdminShell({
305
307
  chrome = "embedded",
306
308
  renderHeader,
307
309
  renderAccountMenu,
308
- renderWorkspaceNav
310
+ renderWorkspaceNav,
311
+ renderWorkspaceFrame
309
312
  }) {
310
313
  const copy = useChapterCopy().admin;
311
314
  const normalizeRoute = useCallback((candidate) => {
@@ -324,7 +327,7 @@ function AdminShell({
324
327
  const [route, setRoute] = useState2(routeFromLocation);
325
328
  const href = useCallback(
326
329
  (target) => {
327
- const next = normalizeRoute(mergeRoute(route, target));
330
+ const next = normalizeRoute(mergeAdminRoute(route, target));
328
331
  if (typeof window === "undefined") {
329
332
  return `#${[
330
333
  next.workspaceId,
@@ -339,7 +342,7 @@ function AdminShell({
339
342
  );
340
343
  const navigate = useCallback(
341
344
  (target) => {
342
- const next = normalizeRoute(mergeRoute(route, target));
345
+ const next = normalizeRoute(mergeAdminRoute(route, target));
343
346
  if (typeof window !== "undefined") {
344
347
  window.history.pushState(null, "", adminRouteHref(new URL(window.location.href), basePath, next, routing));
345
348
  }
@@ -384,7 +387,7 @@ function AdminShell({
384
387
  ] });
385
388
  const activeContent = active?.render(context);
386
389
  const workspaceContent = active?.accent ? /* @__PURE__ */ jsx3(ThemeScope, { accent: active.accent, children: activeContent }) : activeContent;
387
- if (chrome === "topbar") {
390
+ if (chrome === "topbar" && !renderWorkspaceFrame) {
388
391
  return /* @__PURE__ */ jsxs3(Fragment, { children: [
389
392
  /* @__PURE__ */ jsxs3(TopBar, { children: [
390
393
  /* @__PURE__ */ jsxs3("a", { className: "topbar-brand", href: "/", children: [
@@ -410,6 +413,20 @@ function AdminShell({
410
413
  /* @__PURE__ */ jsx3("span", { style: { flex: 1 } }),
411
414
  /* @__PURE__ */ jsx3("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: identity })
412
415
  ] }) : null;
416
+ if (renderWorkspaceFrame) return /* @__PURE__ */ jsxs3(Fragment, { children: [
417
+ header,
418
+ /* @__PURE__ */ jsx3(ThemeWarning, {}),
419
+ renderWorkspaceFrame({
420
+ ...accountProps,
421
+ workspaces,
422
+ route,
423
+ navigate,
424
+ href,
425
+ activeWorkspace: active,
426
+ context,
427
+ children: workspaceContent
428
+ })
429
+ ] });
413
430
  return /* @__PURE__ */ jsxs3(Fragment, { children: [
414
431
  header,
415
432
  /* @__PURE__ */ jsxs3("main", { className: "shell-main", style: S.main, children: [
@@ -429,7 +446,7 @@ function AdminShell({
429
446
  value: workspace.id,
430
447
  label: workspace.label,
431
448
  href: href(workspace.id),
432
- panel: workspace.id === route.workspaceId ? workspace.accent ? /* @__PURE__ */ jsx3(ThemeScope, { accent: workspace.accent, children: workspace.render(context) }) : workspace.render(context) : null
449
+ panel: workspace.id === route.workspaceId ? workspaceContent : null
433
450
  }))
434
451
  }
435
452
  )
@@ -480,15 +497,23 @@ function useAdminResource(getToken, path) {
480
497
  }
481
498
 
482
499
  // src/ui/admin-billing.tsx
483
- import { jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
484
- var money = (cents) => `$${(cents / 100).toLocaleString()}`;
500
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
501
+ var money = (cents) => cents === null ? "Unknown" : `$${(cents / 100).toLocaleString()}`;
485
502
  var date = (t) => t ? new Date(t).toLocaleDateString([], { dateStyle: "medium" }) : "\u2014";
486
503
  var columns = (copy) => [
487
504
  { key: "name", header: copy.name, cell: (r) => r.name, sortAs: "string" },
488
505
  { key: "email", header: copy.email, cell: (r) => r.email },
489
506
  { key: "applicationStatus", header: copy.application, cell: (r) => r.applicationStatus },
490
507
  { key: "subscriptionStatus", header: copy.subscription, cell: (r) => r.subscriptionStatus ? `${r.subscriptionStatus}${r.cancelAtPeriodEnd ? ` \xB7 ${copy.cancelling}` : ""}` : "\u2014" },
491
- { key: "amountCents", header: copy.amount, cell: (r) => `${money(r.amountCents)}/${r.interval === "month" ? "mo" : "yr"}`, sortAs: "number", sortValue: (r) => r.amountCents },
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) }),
511
+ " "
512
+ ] }) : null,
513
+ money(r.amountCents),
514
+ "/",
515
+ r.interval === "month" ? "mo" : "yr"
516
+ ] }), sortAs: "number", sortValue: (r) => r.amountCents ?? -1 },
492
517
  { key: "renewalAt", header: copy.renews, cell: (r) => date(r.renewalAt), sortAs: "number", sortValue: (r) => r.renewalAt ?? 0 }
493
518
  ];
494
519
  function BillingBody({ ctx }) {
@@ -523,7 +548,7 @@ function billingSection(options = {}) {
523
548
 
524
549
  // src/ui/admin-dashboard.tsx
525
550
  import { MetricWidget, StepPipeline } from "@odla-ai/ui/components";
526
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
551
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
527
552
  var number = (value) => Math.round(value).toLocaleString();
528
553
  var money2 = (cents) => `$${Math.round(cents / 100).toLocaleString()}`;
529
554
  var when = (time) => new Date(time).toLocaleString([], { dateStyle: "medium", timeStyle: "short" });
@@ -546,10 +571,11 @@ function DashboardBody({ ctx }) {
546
571
  }));
547
572
  const exceptions = ["declined", "refunded"].filter((stage) => stage in data.pipeline).map((stage) => `${stage} ${data.pipeline[stage]}`).join(" \xB7 ");
548
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,
549
575
  /* @__PURE__ */ jsx5(
550
576
  Panel,
551
577
  {
552
- title: /* @__PURE__ */ jsxs5(Fragment2, { children: [
578
+ title: /* @__PURE__ */ jsxs5(Fragment3, { children: [
553
579
  copy.upcomingCalls,
554
580
  " ",
555
581
  /* @__PURE__ */ jsxs5("span", { className: "muted", style: { fontWeight: 400 }, children: [
@@ -592,7 +618,7 @@ function DashboardBody({ ctx }) {
592
618
  copy.annualRunRate,
593
619
  ":",
594
620
  " ",
595
- money2(data.revenue.annualRunRateCents ?? 0),
621
+ data.revenue.annualRunRateCents == null ? "Unknown" : money2(data.revenue.annualRunRateCents),
596
622
  data.revenue.testMode ? ` \xB7 ${copy.testMode}` : ""
597
623
  ] })
598
624
  ] }) : /* @__PURE__ */ jsx5(Panel, { title: copy.revenue, children: /* @__PURE__ */ jsx5("p", { className: "muted", children: copy.revenueUnavailable }) }),
@@ -610,17 +636,229 @@ function dashboardSection(options = {}) {
610
636
  // src/ui/admin-people-workspace.tsx
611
637
  import { BillingCard, CrmWorkspace } from "@odla-ai/crm/ui";
612
638
 
613
- // src/ui/admin-record-actions.tsx
614
- import { useEffect as useEffect4, useState as useState4 } from "preact/hooks";
615
- import { Button, Field, Select } from "@odla-ai/ui/components";
639
+ // src/ui/admin-application-repair.tsx
640
+ import { useState as useState4 } from "preact/hooks";
641
+ import { Button } from "@odla-ai/ui/components";
616
642
  import { jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
643
+ 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 () => {
649
+ setBusy(true);
650
+ setError(null);
651
+ try {
652
+ await adminFetch(getToken, "/api/admin/crm/sync", { method: "POST", body: JSON.stringify({ recordId }) });
653
+ onChanged();
654
+ } catch (cause) {
655
+ setError(cause instanceof Error ? cause.message : String(cause));
656
+ } finally {
657
+ setBusy(false);
658
+ }
659
+ }, children: busy ? "Checking application link\u2026" : "Repair application link" }),
660
+ error ? /* @__PURE__ */ jsx6("p", { role: "alert", children: error }) : null
661
+ ] });
662
+ }
663
+
664
+ // 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";
668
+ function ApplicationStagePanel(props) {
669
+ const actions = useAdminResource(
670
+ props.getToken,
671
+ `/api/admin/applications/${encodeURIComponent(props.applicationId)}/actions`
672
+ );
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: [
678
+ "Could not load application actions: ",
679
+ actions.error
680
+ ] });
681
+ const allowed = actions.data?.allowedStages ?? [];
682
+ 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,
688
+ {
689
+ "aria-label": "Move to stage",
690
+ value: target,
691
+ disabled: busy,
692
+ onChange: (event) => setSelected(event.currentTarget.value),
693
+ options: [{ value: "", label: "Move to\u2026" }, ...allowed.map((value) => ({ value, label: value.replaceAll("_", " ") }))]
694
+ }
695
+ ),
696
+ /* @__PURE__ */ jsx7(Button2, { mini: true, disabled: busy || !target, onClick: async () => {
697
+ setBusy(true);
698
+ setError(null);
699
+ try {
700
+ await props.onMove(target);
701
+ setSelected("");
702
+ } catch (failure) {
703
+ setError(failure instanceof Error ? failure.message : "Action failed");
704
+ } finally {
705
+ setBusy(false);
706
+ actions.refresh();
707
+ }
708
+ }, children: "Move" })
709
+ ] }) : /* @__PURE__ */ jsx7("p", { children: "No stage changes are available under this chapter\u2019s current membership policy." })
710
+ ] });
711
+ }
712
+
713
+ // 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";
717
+ var valueText = (value) => value == null ? "" : typeof value === "object" ? JSON.stringify(value) : String(value);
718
+ 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);
722
+ const pending = useRef(null);
723
+ const changed = props.fields.filter((field) => draft[field.id] !== valueText(props.values[field.id]));
724
+ const save = async () => {
725
+ setBusy(true);
726
+ setError(null);
727
+ try {
728
+ const input = Object.fromEntries(changed.map((field) => {
729
+ const text = draft[field.id] ?? "";
730
+ let value = text || null;
731
+ if (text && (field.type === "number" || field.type === "date")) {
732
+ value = Number(text);
733
+ if (!Number.isFinite(value)) throw new Error(`${field.label} must be a number${field.type === "date" ? " (milliseconds since epoch)" : ""}.`);
734
+ }
735
+ if (text && field.type === "boolean") value = text === "true";
736
+ if (text && field.type === "json") value = JSON.parse(text);
737
+ return [field.id, value];
738
+ }));
739
+ const fingerprint = JSON.stringify(input);
740
+ if (pending.current?.fingerprint !== fingerprint) pending.current = { fingerprint, id: crypto.randomUUID() };
741
+ await props.onSave(input, pending.current.id);
742
+ pending.current = null;
743
+ } catch (cause) {
744
+ setError(cause instanceof Error ? cause.message : "Could not save profile.");
745
+ } finally {
746
+ setBusy(false);
747
+ }
748
+ };
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,
752
+ {
753
+ "aria-label": field.label,
754
+ value: draft[field.id],
755
+ disabled: busy,
756
+ onChange: (event) => setDraft({ ...draft, [field.id]: event.currentTarget.value }),
757
+ children: [
758
+ /* @__PURE__ */ jsx8("option", { value: "", children: "Not set" }),
759
+ (field.options ?? ["true", "false"]).map((option) => /* @__PURE__ */ jsx8("option", { value: option, children: option }, option))
760
+ ]
761
+ }
762
+ ) : field.type === "json" ? /* @__PURE__ */ jsx8(
763
+ Textarea,
764
+ {
765
+ "aria-label": field.label,
766
+ value: draft[field.id],
767
+ disabled: busy,
768
+ onInput: (event) => setDraft({ ...draft, [field.id]: event.currentTarget.value })
769
+ }
770
+ ) : /* @__PURE__ */ jsx8(
771
+ Input,
772
+ {
773
+ "aria-label": field.label,
774
+ value: draft[field.id],
775
+ disabled: busy,
776
+ required: field.required,
777
+ onInput: (event) => setDraft({ ...draft, [field.id]: event.currentTarget.value })
778
+ }
779
+ ) }, 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" }) })
782
+ ] });
783
+ }
784
+
785
+ // src/ui/admin-person-profile.tsx
786
+ import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
787
+ function ChapterPersonProfile(props) {
788
+ const path = `/api/admin/people/profile?${new URLSearchParams({ recordId: props.recordId })}`;
789
+ 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 });
792
+ 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: [
796
+ String(record.fields.email ?? ""),
797
+ " \u2014 login email changes use the verified account workflow."
798
+ ] }),
799
+ /* @__PURE__ */ jsx9(
800
+ OperationalProfileForm,
801
+ {
802
+ fields: record.edit.fields,
803
+ values: record.fields,
804
+ onSave: async (input, mutationId) => {
805
+ await adminFetch(props.getToken, path, { method: "PATCH", body: JSON.stringify({ input, mutationId, expectedRevision: record.revision }) });
806
+ resource.refresh();
807
+ props.onChanged();
808
+ }
809
+ },
810
+ `${record.id}:${record.revision}`
811
+ )
812
+ ] });
813
+ }
814
+
815
+ // 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";
819
+ 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 () => {
824
+ setBusy(true);
825
+ setMessage("");
826
+ let after = null, count = 0, errors = 0;
827
+ try {
828
+ do {
829
+ const page = await adminFetch(
830
+ getToken,
831
+ "/api/admin/crm/accounts/sync",
832
+ { method: "POST", body: JSON.stringify(after ? { after } : {}) }
833
+ );
834
+ count += page.synced;
835
+ errors += page.errors.length;
836
+ if (page.next && after && page.next <= after) throw new Error("Account repair cursor did not advance");
837
+ after = page.next;
838
+ setMessage(`Checked ${count} accounts${errors ? `; ${errors} need identity review` : ""}.`);
839
+ } while (after);
840
+ await refresh();
841
+ } catch {
842
+ setMessage("Account repair could not finish. Retry is safe; membership and billing are unchanged.");
843
+ } finally {
844
+ setBusy(false);
845
+ }
846
+ }, children: busy ? "Syncing accounts\u2026" : "Sync accounts" }),
847
+ message ? /* @__PURE__ */ jsx10("p", { role: "status", children: message }) : null
848
+ ] });
849
+ }
850
+
851
+ // 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";
617
855
  function RecordActions({ getToken, record, roles, onChanged }) {
618
856
  const copy = useChapterCopy().admin.records;
619
857
  const userId = typeof record.clerkUserId === "string" ? record.clerkUserId : null;
620
858
  const applicationId = typeof record.fields?.applicationId === "string" ? record.fields.applicationId : null;
621
- const [access, setAccess] = useState4(null);
622
- const [busy, setBusy] = useState4(null);
623
- const [note, setNote] = useState4(null);
859
+ const [access, setAccess] = useState8(null);
860
+ const [busy, setBusy] = useState8(null);
861
+ const [note, setNote] = useState8(null);
624
862
  useEffect4(() => {
625
863
  if (!userId) {
626
864
  setAccess(null);
@@ -649,34 +887,34 @@ function RecordActions({ getToken, record, roles, onChanged }) {
649
887
  const approve = () => act("approve", () => adminFetch(getToken, `/api/admin/applications/${applicationId}/approve`, { method: "POST" }), copy.approved);
650
888
  const refund = () => act("refund", () => adminFetch(getToken, `/api/admin/applications/${applicationId}/refund`, { method: "POST" }), copy.refunded);
651
889
  if (!userId && !applicationId) return null;
652
- return /* @__PURE__ */ jsxs6("section", { className: "panel", style: { display: "flex", flexDirection: "column", gap: 14, marginTop: 16 }, children: [
653
- /* @__PURE__ */ jsx6("h3", { style: { margin: 0, fontSize: 16 }, children: copy.lifecycle }),
654
- userId ? /* @__PURE__ */ jsx6(Field, { label: copy.role, hint: access?.superAdmin ? copy.superAdminHint : void 0, children: /* @__PURE__ */ jsx6(
655
- Select,
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,
656
894
  {
657
895
  value: access?.role ?? "",
658
896
  disabled: busy === "role" || access?.superAdmin,
659
897
  options: roles.map((r) => ({ value: r, label: r })),
660
898
  onChange: (e) => void setRole(e.target.value)
661
899
  }
662
- ) }) : /* @__PURE__ */ jsx6("p", { className: "muted", style: { margin: 0 }, children: copy.noAccount }),
663
- applicationId ? /* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: 8 }, children: [
664
- /* @__PURE__ */ jsx6(Button, { variant: "secondary", mini: true, disabled: busy === "approve", onClick: () => void approve(), children: copy.approve }),
665
- /* @__PURE__ */ jsx6(Button, { variant: "danger", mini: true, disabled: busy === "refund", onClick: () => void refund(), children: copy.refund })
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 })
666
904
  ] }) : null,
667
- note ? /* @__PURE__ */ jsx6("p", { className: "muted", style: { margin: 0 }, children: note }) : null
905
+ note ? /* @__PURE__ */ jsx11("p", { className: "muted", style: { margin: 0 }, children: note }) : null
668
906
  ] });
669
907
  }
670
908
 
671
909
  // src/ui/admin-network.tsx
672
- import { useState as useState5 } from "preact/hooks";
673
- import { jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
910
+ import { useState as useState9 } from "preact/hooks";
911
+ import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
674
912
  function NetworkShareActions(props) {
675
913
  const copy = useChapterCopy().admin.network;
676
914
  const { recordId, recordType, getToken } = props;
677
915
  const targets = useAdminResource(getToken, "/api/admin/network/targets");
678
- const [busy, setBusy] = useState5(null);
679
- const [message, setMessage] = useState5(null);
916
+ const [busy, setBusy] = useState9(null);
917
+ const [message, setMessage] = useState9(null);
680
918
  const compatible = (targets.data?.targets ?? []).filter((target) => target.types.includes(recordType));
681
919
  if (targets.loading || targets.error || compatible.length === 0) return null;
682
920
  const push = async (target) => {
@@ -695,26 +933,26 @@ function NetworkShareActions(props) {
695
933
  setBusy(null);
696
934
  }
697
935
  };
698
- return /* @__PURE__ */ jsxs7("section", { className: "panel", style: { marginTop: 14, display: "flex", flexDirection: "column", gap: 10 }, children: [
699
- /* @__PURE__ */ jsxs7("div", { children: [
700
- /* @__PURE__ */ jsx7("h3", { style: { margin: 0, fontSize: 16 }, children: copy.title }),
701
- /* @__PURE__ */ jsx7("p", { className: "muted", style: { margin: "4px 0 0", fontSize: 13 }, children: copy.allowlistDescription })
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 })
702
940
  ] }),
703
- /* @__PURE__ */ jsx7("div", { style: { display: "flex", flexWrap: "wrap", gap: 8 }, children: compatible.map((target) => /* @__PURE__ */ jsx7("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)) }),
704
- message ? /* @__PURE__ */ jsx7("p", { role: "status", style: { margin: 0, fontSize: 13 }, children: message }) : null
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
705
943
  ] });
706
944
  }
707
945
 
708
946
  // src/ui/admin-record-activity.tsx
709
- import { useCallback as useCallback3, useEffect as useEffect5, useState as useState6 } from "preact/hooks";
947
+ import { useCallback as useCallback3, useEffect as useEffect5, useState as useState10 } from "preact/hooks";
710
948
  import { ActivityFeed } from "@odla-ai/crm/ui";
711
949
  import { parseCrmDiscussionReference as parseCrmDiscussionReference2 } from "@odla-ai/crm";
712
- import { jsx as jsx8 } from "preact/jsx-runtime";
950
+ import { jsx as jsx13 } from "preact/jsx-runtime";
713
951
  function RecordActivityPanel(props) {
714
952
  const { client, recordId } = props;
715
- const [activities, setActivities] = useState6([]);
716
- const [busy, setBusy] = useState6(false);
717
- const [error, setError] = useState6(null);
953
+ const [activities, setActivities] = useState10([]);
954
+ const [busy, setBusy] = useState10(false);
955
+ const [error, setError] = useState10(null);
718
956
  const reference = typeof window === "undefined" ? null : parseCrmDiscussionReference2(new URL(window.location.href));
719
957
  const focusedActivityId = reference?.kind === "crm:activity" && reference.recordId === recordId ? reference.activityId : void 0;
720
958
  const load = useCallback3(async () => {
@@ -736,8 +974,8 @@ function RecordActivityPanel(props) {
736
974
  setBusy(false);
737
975
  }
738
976
  };
739
- if (error) return /* @__PURE__ */ jsx8("p", { role: "alert", className: "muted", children: error });
740
- return /* @__PURE__ */ jsx8(
977
+ if (error) return /* @__PURE__ */ jsx13("p", { role: "alert", className: "muted", children: error });
978
+ return /* @__PURE__ */ jsx13(
741
979
  ActivityFeed,
742
980
  {
743
981
  activities,
@@ -751,17 +989,17 @@ function RecordActivityPanel(props) {
751
989
  }
752
990
 
753
991
  // src/ui/admin-record-comms.tsx
754
- import { useCallback as useCallback4, useEffect as useEffect6, useState as useState7 } from "preact/hooks";
755
- import { Button as Button2, Field as Field2, Select as Select2 } from "@odla-ai/ui/components";
756
- import { jsx as jsx9, jsxs as jsxs8 } from "preact/jsx-runtime";
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";
757
995
  function RecordCommsPanel(props) {
758
996
  const copy = useChapterCopy().admin.records;
759
997
  const { client, recordId, getToken } = props;
760
998
  const config = useAdminResource(getToken, "/api/admin/group/email");
761
999
  const templates = Object.entries(config.data?.emailTemplates ?? {}).filter(([, value]) => value.enabled);
762
- const [template, setTemplate] = useState7("");
763
- const [busy, setBusy] = useState7(false);
764
- const [note, setNote] = useState7(null);
1000
+ const [template, setTemplate] = useState11("");
1001
+ const [busy, setBusy] = useState11(false);
1002
+ const [note, setNote] = useState11(null);
765
1003
  const send = async () => {
766
1004
  if (!template) return;
767
1005
  setBusy(true);
@@ -775,11 +1013,11 @@ function RecordCommsPanel(props) {
775
1013
  setBusy(false);
776
1014
  }
777
1015
  };
778
- if (config.loading) return /* @__PURE__ */ jsx9("p", { className: "muted", children: copy.loadingTemplates });
779
- if (config.error) return /* @__PURE__ */ jsx9("p", { role: "alert", className: "muted", children: config.error });
780
- return /* @__PURE__ */ jsxs8("div", { style: { display: "grid", gap: 14, maxWidth: 560 }, children: [
781
- /* @__PURE__ */ jsx9(Field2, { label: copy.template, children: /* @__PURE__ */ jsx9(
782
- Select2,
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,
783
1021
  {
784
1022
  value: template,
785
1023
  onChange: (event) => setTemplate(event.currentTarget.value),
@@ -789,15 +1027,15 @@ function RecordCommsPanel(props) {
789
1027
  ]
790
1028
  }
791
1029
  ) }),
792
- /* @__PURE__ */ jsx9("div", { children: /* @__PURE__ */ jsx9(Button2, { disabled: !template || busy, onClick: () => void send(), children: busy ? copy.sending : copy.send }) }),
793
- note ? /* @__PURE__ */ jsx9("p", { role: "status", className: "muted", children: note }) : null
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
794
1032
  ] });
795
1033
  }
796
1034
  function RecordCommsHistory(props) {
797
1035
  const copy = useChapterCopy().admin.records;
798
1036
  const { client, recordId } = props;
799
- const [rows, setRows] = useState7([]);
800
- const [error, setError] = useState7(null);
1037
+ const [rows, setRows] = useState11([]);
1038
+ const [error, setError] = useState11(null);
801
1039
  const load = useCallback4(async () => {
802
1040
  try {
803
1041
  const result = await client.emailLog({ recordId, limit: 100 });
@@ -808,11 +1046,11 @@ function RecordCommsHistory(props) {
808
1046
  }
809
1047
  }, [client, recordId]);
810
1048
  useEffect6(() => void load(), [load]);
811
- if (error) return /* @__PURE__ */ jsx9("p", { role: "alert", className: "muted", children: error });
812
- if (rows.length === 0) return /* @__PURE__ */ jsx9("p", { className: "muted", children: copy.noMessages });
813
- return /* @__PURE__ */ jsx9("ul", { style: { listStyle: "none", padding: 0, margin: 0, display: "grid", gap: 10 }, children: rows.map((row, index) => /* @__PURE__ */ jsxs8("li", { className: "panel", children: [
814
- /* @__PURE__ */ jsx9("strong", { children: String(row["templateId"] ?? row["template"] ?? copy.message) }),
815
- /* @__PURE__ */ jsxs8("div", { className: "muted", children: [
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: [
816
1054
  row["to"] ? String(row["to"]) : "",
817
1055
  row["sentAt"] ? ` \xB7 ${new Date(Number(row["sentAt"])).toLocaleString()}` : ""
818
1056
  ] })
@@ -820,9 +1058,9 @@ function RecordCommsHistory(props) {
820
1058
  }
821
1059
 
822
1060
  // src/ui/admin-record-scheduling.tsx
823
- import { useState as useState8 } from "preact/hooks";
824
- import { Button as Button3 } from "@odla-ai/ui/components";
825
- import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs9 } from "preact/jsx-runtime";
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";
826
1064
  function RecordSchedulingPanel(props) {
827
1065
  const copy = useChapterCopy().admin.records;
828
1066
  const { getToken, applicationId } = props;
@@ -830,8 +1068,8 @@ function RecordSchedulingPanel(props) {
830
1068
  getToken,
831
1069
  "/api/admin/meetings?all=1"
832
1070
  );
833
- const [busy, setBusy] = useState8(null);
834
- const [note, setNote] = useState8(null);
1071
+ const [busy, setBusy] = useState12(null);
1072
+ const [note, setNote] = useState12(null);
835
1073
  const meetings = (resource.data?.meetings ?? []).filter((meeting) => meeting.applicationId === applicationId);
836
1074
  const run = async (meeting, action) => {
837
1075
  let body;
@@ -858,33 +1096,33 @@ function RecordSchedulingPanel(props) {
858
1096
  setBusy(null);
859
1097
  }
860
1098
  };
861
- if (!applicationId) return /* @__PURE__ */ jsx10("p", { className: "muted", children: copy.noApplication });
862
- if (resource.loading) return /* @__PURE__ */ jsx10("p", { className: "muted", children: copy.loadingMeetings });
863
- if (resource.error) return /* @__PURE__ */ jsx10("p", { role: "alert", className: "muted", children: resource.error });
864
- if (meetings.length === 0) return /* @__PURE__ */ jsx10("p", { className: "muted", children: copy.noMeetings });
865
- return /* @__PURE__ */ jsxs9("div", { style: { display: "grid", gap: 12 }, children: [
866
- meetings.map((meeting) => /* @__PURE__ */ jsxs9("section", { className: "panel", children: [
867
- /* @__PURE__ */ jsx10("strong", { children: new Date(meeting.startAt).toLocaleString() }),
868
- /* @__PURE__ */ jsxs9("p", { className: "muted", children: [
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: [
869
1107
  meeting.status,
870
1108
  " \xB7 ",
871
1109
  resource.data?.timezone
872
1110
  ] }),
873
- /* @__PURE__ */ jsxs9("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
874
- meeting.meetUrl ? /* @__PURE__ */ jsx10("a", { href: meeting.meetUrl, target: "_blank", rel: "noreferrer", children: copy.joinMeeting }) : null,
875
- meeting.htmlLink ? /* @__PURE__ */ jsx10("a", { href: meeting.htmlLink, target: "_blank", rel: "noreferrer", children: copy.openCalendar }) : null,
876
- meeting.status === "scheduled" ? /* @__PURE__ */ jsxs9(Fragment3, { children: [
877
- /* @__PURE__ */ jsx10(Button3, { variant: "secondary", mini: true, disabled: busy === meeting.id, onClick: () => void run(meeting, "reschedule"), children: copy.reschedule }),
878
- /* @__PURE__ */ jsx10(Button3, { variant: "danger", mini: true, disabled: busy === meeting.id, onClick: () => void run(meeting, "cancel"), children: copy.cancel })
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 })
879
1117
  ] }) : null
880
1118
  ] })
881
1119
  ] }, meeting.id)),
882
- note ? /* @__PURE__ */ jsx10("p", { role: "status", className: "muted", children: note }) : null
1120
+ note ? /* @__PURE__ */ jsx15("p", { role: "status", className: "muted", children: note }) : null
883
1121
  ] });
884
1122
  }
885
1123
 
886
1124
  // src/ui/admin-people-workspace.tsx
887
- import { jsx as jsx11 } from "preact/jsx-runtime";
1125
+ import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs15 } from "preact/jsx-runtime";
888
1126
  function applicationLifecycleAdapter(ctx, copy = DEFAULT_CHAPTER_COPY.admin.records) {
889
1127
  return {
890
1128
  transitionStage: async ({ record, to }) => {
@@ -933,7 +1171,7 @@ function PeopleBody(props) {
933
1171
  const builtInLifecycle = lifecycle ? applicationLifecycleAdapter(ctx, copy) : void 0;
934
1172
  const resolvedLifecycle = typeof lifecycleAdapter === "function" ? lifecycleAdapter(ctx) : lifecycleAdapter ?? builtInLifecycle;
935
1173
  const workspaceClient = client;
936
- return /* @__PURE__ */ jsx11(AdminPage, { children: /* @__PURE__ */ jsx11(
1174
+ return /* @__PURE__ */ jsx16(AdminPage, { children: /* @__PURE__ */ jsx16(
937
1175
  CrmWorkspace,
938
1176
  {
939
1177
  crm,
@@ -949,7 +1187,10 @@ function PeopleBody(props) {
949
1187
  collapseClosedDetail,
950
1188
  lifecycle: resolvedLifecycle,
951
1189
  requireLifecycleAdapter: requireLifecycleAdapter ?? lifecycle,
952
- renderSummary: renderSummary ? (context) => renderSummary(context, ctx) : void 0,
1190
+ renderSummary: (context) => /* @__PURE__ */ jsxs15(Fragment7, { children: [
1191
+ renderSummary?.(context, ctx),
1192
+ type === "person" ? /* @__PURE__ */ jsx16(AccountPeopleSync, { getToken: ctx.getToken, refresh: context.query.refresh }) : null
1193
+ ] }),
953
1194
  renderMaster: renderMaster ? (context) => renderMaster(context, ctx) : void 0,
954
1195
  renderDetailHeader: renderDetailHeader ? (context) => renderDetailHeader(context, ctx) : void 0,
955
1196
  renderDetail: renderDetail ? (context, defaultDetail) => renderDetail(context, defaultDetail, ctx) : void 0,
@@ -961,7 +1202,43 @@ function PeopleBody(props) {
961
1202
  const tabs = [];
962
1203
  const add = (id) => {
963
1204
  const tab = byId.get(id);
964
- if (tab) tabs.push(tab);
1205
+ if (tab && lifecycle && type === "person" && id === "profile" && !lifecycleAdapter) {
1206
+ tabs.push({ ...tab, panel: /* @__PURE__ */ jsx16(
1207
+ ChapterPersonProfile,
1208
+ {
1209
+ recordId: record.id,
1210
+ getToken: ctx.getToken,
1211
+ onChanged: () => {
1212
+ context.refreshRecord();
1213
+ context.refreshList();
1214
+ }
1215
+ },
1216
+ record.id
1217
+ ) });
1218
+ return;
1219
+ }
1220
+ if (tab && lifecycle && applicationId && id === "stage" && !lifecycleAdapter) {
1221
+ tabs.push({ ...tab, panel: /* @__PURE__ */ jsx16(
1222
+ ApplicationStagePanel,
1223
+ {
1224
+ applicationId,
1225
+ getToken: ctx.getToken,
1226
+ onMove: context.moveStage
1227
+ },
1228
+ record.id + record.updatedAt
1229
+ ) });
1230
+ return;
1231
+ }
1232
+ if (tab) tabs.push(lifecycle && !applicationId && id === "stage" ? {
1233
+ ...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: () => {
1236
+ context.refreshRecord();
1237
+ context.refreshList();
1238
+ } }, record.id),
1239
+ tab.panel
1240
+ ] })
1241
+ } : tab);
965
1242
  };
966
1243
  add("stage");
967
1244
  add("profile");
@@ -969,35 +1246,35 @@ function PeopleBody(props) {
969
1246
  tabs.push({
970
1247
  id: "comms",
971
1248
  label: copy.comms,
972
- panel: /* @__PURE__ */ jsx11(RecordCommsPanel, { client, recordId: record.id, getToken: ctx.getToken })
1249
+ panel: /* @__PURE__ */ jsx16(RecordCommsPanel, { client, recordId: record.id, getToken: ctx.getToken })
973
1250
  });
974
1251
  tabs.push({
975
1252
  id: "history",
976
1253
  label: copy.commsHistory,
977
- panel: /* @__PURE__ */ jsx11(RecordCommsHistory, { client, recordId: record.id })
1254
+ panel: /* @__PURE__ */ jsx16(RecordCommsHistory, { client, recordId: record.id })
978
1255
  });
979
1256
  }
980
1257
  if (lifecycle) {
981
1258
  tabs.push({
982
1259
  id: "scheduling",
983
1260
  label: copy.scheduling,
984
- panel: /* @__PURE__ */ jsx11(RecordSchedulingPanel, { getToken: ctx.getToken, applicationId })
1261
+ panel: /* @__PURE__ */ jsx16(RecordSchedulingPanel, { getToken: ctx.getToken, applicationId })
985
1262
  });
986
- tabs.push({ id: "billing", label: copy.billing, panel: /* @__PURE__ */ jsx11(BillingCard, { record }) });
1263
+ tabs.push({ id: "billing", label: copy.billing, panel: /* @__PURE__ */ jsx16(BillingCard, { record }) });
987
1264
  } else {
988
1265
  add("billing");
989
1266
  }
990
1267
  tabs.push({
991
1268
  id: "notes",
992
1269
  label: copy.notes,
993
- panel: /* @__PURE__ */ jsx11(RecordActivityPanel, { client, recordId: record.id })
1270
+ panel: /* @__PURE__ */ jsx16(RecordActivityPanel, { client, recordId: record.id })
994
1271
  });
995
1272
  add("connections");
996
1273
  if (lifecycle) {
997
1274
  tabs.push({
998
1275
  id: "access",
999
1276
  label: copy.access,
1000
- panel: /* @__PURE__ */ jsx11(
1277
+ panel: /* @__PURE__ */ jsx16(
1001
1278
  RecordActions,
1002
1279
  {
1003
1280
  getToken: ctx.getToken,
@@ -1016,7 +1293,7 @@ function PeopleBody(props) {
1016
1293
  tabs.push({
1017
1294
  id: "sharing",
1018
1295
  label: copy.sharing,
1019
- panel: /* @__PURE__ */ jsx11(NetworkShareActions, { recordId: record.id, recordType: record.type, getToken: ctx.getToken })
1296
+ panel: /* @__PURE__ */ jsx16(NetworkShareActions, { recordId: record.id, recordType: record.type, getToken: ctx.getToken })
1020
1297
  });
1021
1298
  }
1022
1299
  return extendRecordTabs?.(tabs, context) ?? tabs;
@@ -1026,7 +1303,7 @@ function PeopleBody(props) {
1026
1303
  }
1027
1304
 
1028
1305
  // src/ui/admin-people.tsx
1029
- import { jsx as jsx12 } from "preact/jsx-runtime";
1306
+ import { jsx as jsx17 } from "preact/jsx-runtime";
1030
1307
  var DEFAULT_ROLES = ["provisional", "member", "admin"];
1031
1308
  function collectionSection(options) {
1032
1309
  const { crm, type } = options;
@@ -1056,7 +1333,7 @@ function collectionSection(options) {
1056
1333
  return {
1057
1334
  id,
1058
1335
  label,
1059
- render: (ctx) => /* @__PURE__ */ jsx12(
1336
+ render: (ctx) => /* @__PURE__ */ jsx17(
1060
1337
  PeopleBody,
1061
1338
  {
1062
1339
  crm,
@@ -1125,17 +1402,17 @@ function peopleSection(options) {
1125
1402
  // src/ui/admin-network-records.tsx
1126
1403
  import {
1127
1404
  DataTable as DataTable2,
1128
- Field as Field4,
1405
+ Field as Field6,
1129
1406
  MasterDetail,
1130
1407
  Pagination,
1131
- Select as Select3
1408
+ Select as Select5
1132
1409
  } from "@odla-ai/ui/components";
1133
- import { useEffect as useEffect7, useMemo, useState as useState10 } from "preact/hooks";
1410
+ import { useEffect as useEffect7, useMemo, useState as useState14 } from "preact/hooks";
1134
1411
 
1135
1412
  // src/ui/admin-network-notes.tsx
1136
- import { Button as Button4, Field as Field3, Textarea } from "@odla-ai/ui/components";
1137
- import { useState as useState9 } from "preact/hooks";
1138
- import { jsx as jsx13, jsxs as jsxs10 } from "preact/jsx-runtime";
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";
1139
1416
  function displayValue(value) {
1140
1417
  if (Array.isArray(value)) return value.join(", ");
1141
1418
  if (value && typeof value === "object") return JSON.stringify(value);
@@ -1150,9 +1427,9 @@ function PrivateNotes(props) {
1150
1427
  });
1151
1428
  const path = `/api/admin/network/notes?${query}`;
1152
1429
  const notes = useAdminResource(ctx.getToken, path);
1153
- const [body, setBody] = useState9("");
1154
- const [busy, setBusy] = useState9(false);
1155
- const [error, setError] = useState9(null);
1430
+ const [body, setBody] = useState13("");
1431
+ const [busy, setBusy] = useState13(false);
1432
+ const [error, setError] = useState13(null);
1156
1433
  const submit = async () => {
1157
1434
  const trimmed = body.trim();
1158
1435
  if (!trimmed) return;
@@ -1171,19 +1448,19 @@ function PrivateNotes(props) {
1171
1448
  setBusy(false);
1172
1449
  }
1173
1450
  };
1174
- return /* @__PURE__ */ jsxs10("section", { style: { display: "grid", gap: 12 }, children: [
1175
- /* @__PURE__ */ jsxs10("h3", { style: { margin: "8px 0 0" }, children: [
1451
+ return /* @__PURE__ */ jsxs16("section", { style: { display: "grid", gap: 12 }, children: [
1452
+ /* @__PURE__ */ jsxs16("h3", { style: { margin: "8px 0 0" }, children: [
1176
1453
  "Private to ",
1177
1454
  leaderName
1178
1455
  ] }),
1179
- /* @__PURE__ */ jsx13(
1180
- Field3,
1456
+ /* @__PURE__ */ jsx18(
1457
+ Field5,
1181
1458
  {
1182
1459
  label: "Add a note",
1183
1460
  hint: `Visible only to ${leaderName} admins. Nothing is written back to the follower.`,
1184
1461
  error,
1185
- children: /* @__PURE__ */ jsx13(
1186
- Textarea,
1462
+ children: /* @__PURE__ */ jsx18(
1463
+ Textarea2,
1187
1464
  {
1188
1465
  rows: 4,
1189
1466
  value: body,
@@ -1193,13 +1470,13 @@ function PrivateNotes(props) {
1193
1470
  )
1194
1471
  }
1195
1472
  ),
1196
- /* @__PURE__ */ jsx13("div", { children: /* @__PURE__ */ jsx13(Button4, { disabled: busy || !body.trim(), onClick: () => void submit(), children: busy ? "Saving\u2026" : "Save note" }) }),
1197
- notes.loading ? /* @__PURE__ */ jsx13("p", { className: "muted", children: "Loading notes\u2026" }) : null,
1198
- notes.error ? /* @__PURE__ */ jsx13("p", { role: "alert", children: notes.error }) : null,
1199
- !notes.loading && !notes.error && (notes.data?.notes.length ?? 0) === 0 ? /* @__PURE__ */ jsx13("p", { className: "muted", children: "No notes yet." }) : null,
1200
- (notes.data?.notes ?? []).map((note) => /* @__PURE__ */ jsxs10("article", { className: "panel", style: { padding: 14 }, children: [
1201
- /* @__PURE__ */ jsx13("p", { style: { margin: 0, whiteSpace: "pre-wrap" }, children: note.body }),
1202
- /* @__PURE__ */ jsxs10("p", { className: "muted", style: { margin: "8px 0 0", fontSize: 12 }, children: [
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: [
1203
1480
  note.authorEmail ?? note.authorId,
1204
1481
  " \xB7 ",
1205
1482
  new Date(note.createdAt).toLocaleString()
@@ -1216,9 +1493,9 @@ function SharedNotes(props) {
1216
1493
  });
1217
1494
  const path = `/api/admin/network/shared-notes?${query}`;
1218
1495
  const notes = useAdminResource(ctx.getToken, path);
1219
- const [body, setBody] = useState9("");
1220
- const [busy, setBusy] = useState9(false);
1221
- const [error, setError] = useState9(null);
1496
+ const [body, setBody] = useState13("");
1497
+ const [busy, setBusy] = useState13(false);
1498
+ const [error, setError] = useState13(null);
1222
1499
  const submit = async () => {
1223
1500
  const trimmed = body.trim();
1224
1501
  if (!trimmed) return;
@@ -1237,19 +1514,19 @@ function SharedNotes(props) {
1237
1514
  setBusy(false);
1238
1515
  }
1239
1516
  };
1240
- return /* @__PURE__ */ jsxs10("section", { style: { display: "grid", gap: 12 }, children: [
1241
- /* @__PURE__ */ jsxs10("h3", { style: { margin: "8px 0 0" }, children: [
1517
+ return /* @__PURE__ */ jsxs16("section", { style: { display: "grid", gap: 12 }, children: [
1518
+ /* @__PURE__ */ jsxs16("h3", { style: { margin: "8px 0 0" }, children: [
1242
1519
  "Shared with ",
1243
1520
  targetName
1244
1521
  ] }),
1245
- /* @__PURE__ */ jsx13(
1246
- Field3,
1522
+ /* @__PURE__ */ jsx18(
1523
+ Field5,
1247
1524
  {
1248
1525
  label: "Add a shared note",
1249
1526
  hint: `This is written to the record's Notes feed for ${targetName} admins.`,
1250
1527
  error,
1251
- children: /* @__PURE__ */ jsx13(
1252
- Textarea,
1528
+ children: /* @__PURE__ */ jsx18(
1529
+ Textarea2,
1253
1530
  {
1254
1531
  rows: 4,
1255
1532
  value: body,
@@ -1259,13 +1536,13 @@ function SharedNotes(props) {
1259
1536
  )
1260
1537
  }
1261
1538
  ),
1262
- /* @__PURE__ */ jsx13("div", { children: /* @__PURE__ */ jsx13(Button4, { disabled: busy || !body.trim(), onClick: () => void submit(), children: busy ? "Sharing\u2026" : `Share with ${targetName}` }) }),
1263
- notes.loading ? /* @__PURE__ */ jsx13("p", { className: "muted", children: "Loading shared notes\u2026" }) : null,
1264
- notes.error ? /* @__PURE__ */ jsx13("p", { role: "alert", children: notes.error }) : null,
1265
- !notes.loading && !notes.error && (notes.data?.notes.length ?? 0) === 0 ? /* @__PURE__ */ jsx13("p", { className: "muted", children: "No shared notes yet." }) : null,
1266
- (notes.data?.notes ?? []).map((note) => /* @__PURE__ */ jsxs10("article", { className: "panel", style: { padding: 14 }, children: [
1267
- /* @__PURE__ */ jsx13("p", { style: { margin: 0, whiteSpace: "pre-wrap" }, children: note.body }),
1268
- /* @__PURE__ */ jsxs10("p", { className: "muted", style: { margin: "8px 0 0", fontSize: 12 }, children: [
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: [
1269
1546
  "Shared with ",
1270
1547
  targetName,
1271
1548
  " \xB7 ",
@@ -1276,23 +1553,23 @@ function SharedNotes(props) {
1276
1553
  }
1277
1554
  function NetworkRecordDetail(props) {
1278
1555
  const { ctx, targetId, targetName, leaderName, sharedEnabled, record } = props;
1279
- return /* @__PURE__ */ jsxs10("div", { style: { display: "grid", gap: 14 }, children: [
1280
- /* @__PURE__ */ jsxs10("header", { children: [
1281
- /* @__PURE__ */ jsx13("h2", { style: { margin: 0 }, children: record.name }),
1282
- record.stage ? /* @__PURE__ */ jsx13("span", { className: "badge", style: { marginTop: 8 }, children: record.stage.replaceAll("_", " ") }) : null
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
1283
1560
  ] }),
1284
- /* @__PURE__ */ jsxs10("dl", { style: { display: "grid", gridTemplateColumns: "minmax(8rem, auto) 1fr", gap: "8px 16px", margin: 0 }, children: [
1285
- Object.entries(record.fields).map(([name, value]) => /* @__PURE__ */ jsxs10("div", { style: { display: "contents" }, children: [
1286
- /* @__PURE__ */ jsx13("dt", { className: "muted", children: name.replaceAll("_", " ") }),
1287
- /* @__PURE__ */ jsx13("dd", { style: { margin: 0, overflowWrap: "anywhere" }, children: displayValue(value) })
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) })
1288
1565
  ] }, name)),
1289
- /* @__PURE__ */ jsxs10("div", { style: { display: "contents" }, children: [
1290
- /* @__PURE__ */ jsx13("dt", { className: "muted", children: "Updated" }),
1291
- /* @__PURE__ */ jsx13("dd", { style: { margin: 0 }, children: new Date(record.updatedAt).toLocaleString() })
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() })
1292
1569
  ] })
1293
1570
  ] }),
1294
- /* @__PURE__ */ jsxs10("div", { style: { display: "grid", gap: 22 }, children: [
1295
- /* @__PURE__ */ jsx13(
1571
+ /* @__PURE__ */ jsxs16("div", { style: { display: "grid", gap: 22 }, children: [
1572
+ /* @__PURE__ */ jsx18(
1296
1573
  PrivateNotes,
1297
1574
  {
1298
1575
  ctx,
@@ -1301,7 +1578,7 @@ function NetworkRecordDetail(props) {
1301
1578
  leaderName
1302
1579
  }
1303
1580
  ),
1304
- sharedEnabled ? /* @__PURE__ */ jsx13(
1581
+ sharedEnabled ? /* @__PURE__ */ jsx18(
1305
1582
  SharedNotes,
1306
1583
  {
1307
1584
  ctx,
@@ -1315,11 +1592,11 @@ function NetworkRecordDetail(props) {
1315
1592
  }
1316
1593
 
1317
1594
  // src/ui/admin-network-records.tsx
1318
- import { jsx as jsx14, jsxs as jsxs11 } from "preact/jsx-runtime";
1595
+ import { jsx as jsx19, jsxs as jsxs17 } from "preact/jsx-runtime";
1319
1596
  function RecordsExplorer(props) {
1320
1597
  const { ctx, target, type, leaderName } = props;
1321
- const [offset, setOffset] = useState10(0);
1322
- const [search, setSearch] = useState10("");
1598
+ const [offset, setOffset] = useState14(0);
1599
+ const [search, setSearch] = useState14("");
1323
1600
  const query = new URLSearchParams({
1324
1601
  targetId: target.id,
1325
1602
  type,
@@ -1336,12 +1613,12 @@ function RecordsExplorer(props) {
1336
1613
  {
1337
1614
  key: "name",
1338
1615
  header: "Name",
1339
- cell: (record) => /* @__PURE__ */ jsx14("a", { href: ctx.href({ recordId: record.id, detailTab: null }), children: record.name })
1616
+ cell: (record) => /* @__PURE__ */ jsx19("a", { href: ctx.href({ recordId: record.id, detailTab: null }), children: record.name })
1340
1617
  },
1341
1618
  {
1342
1619
  key: "stage",
1343
1620
  header: "Stage",
1344
- cell: (record) => record.stage ? /* @__PURE__ */ jsx14("span", { className: "badge", children: record.stage.replaceAll("_", " ") }) : "\u2014"
1621
+ cell: (record) => record.stage ? /* @__PURE__ */ jsx19("span", { className: "badge", children: record.stage.replaceAll("_", " ") }) : "\u2014"
1345
1622
  },
1346
1623
  {
1347
1624
  key: "updatedAt",
@@ -1349,7 +1626,7 @@ function RecordsExplorer(props) {
1349
1626
  cell: (record) => new Date(record.updatedAt).toLocaleDateString()
1350
1627
  }
1351
1628
  ], [ctx]);
1352
- return /* @__PURE__ */ jsx14(
1629
+ return /* @__PURE__ */ jsx19(
1353
1630
  MasterDetail,
1354
1631
  {
1355
1632
  collapseClosedDetail: true,
@@ -1357,13 +1634,13 @@ function RecordsExplorer(props) {
1357
1634
  detailLabel: "Follower record details, private notes, and shared notes",
1358
1635
  detailOpen: Boolean(selected),
1359
1636
  closeHref: ctx.href({ recordId: null, detailTab: null }),
1360
- master: /* @__PURE__ */ jsxs11("div", { style: { display: "grid", gap: 14, padding: "var(--ui-space-4)" }, children: [
1361
- /* @__PURE__ */ jsxs11("h2", { style: { margin: 0, fontSize: 18 }, children: [
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: [
1362
1639
  target.name,
1363
1640
  " \xB7 ",
1364
1641
  type.replaceAll("_", " ")
1365
1642
  ] }),
1366
- /* @__PURE__ */ jsx14(
1643
+ /* @__PURE__ */ jsx19(
1367
1644
  DataTable2,
1368
1645
  {
1369
1646
  manual: true,
@@ -1383,7 +1660,7 @@ function RecordsExplorer(props) {
1383
1660
  ariaLabel: `${target.name} ${type} records`
1384
1661
  }
1385
1662
  ),
1386
- /* @__PURE__ */ jsx14(
1663
+ /* @__PURE__ */ jsx19(
1387
1664
  Pagination,
1388
1665
  {
1389
1666
  offset: page.data?.offset ?? offset,
@@ -1398,7 +1675,7 @@ function RecordsExplorer(props) {
1398
1675
  }
1399
1676
  )
1400
1677
  ] }),
1401
- detail: selected ? /* @__PURE__ */ jsx14(
1678
+ detail: selected ? /* @__PURE__ */ jsx19(
1402
1679
  NetworkRecordDetail,
1403
1680
  {
1404
1681
  ctx,
@@ -1415,8 +1692,8 @@ function RecordsExplorer(props) {
1415
1692
  function NetworkRecordsWorkspace(props) {
1416
1693
  const { chapter, ctx } = props;
1417
1694
  const targets = useAdminResource(ctx.getToken, "/api/admin/network/targets");
1418
- const [targetId, setTargetId] = useState10("");
1419
- const [type, setType] = useState10("");
1695
+ const [targetId, setTargetId] = useState14("");
1696
+ const [type, setType] = useState14("");
1420
1697
  const target = targets.data?.targets.find((candidate) => candidate.id === targetId) ?? targets.data?.targets[0];
1421
1698
  useEffect7(() => {
1422
1699
  if (target && target.id !== targetId) setTargetId(target.id);
@@ -1425,17 +1702,17 @@ function NetworkRecordsWorkspace(props) {
1425
1702
  const first = target?.types[0] ?? "";
1426
1703
  if (target && !target.types.includes(type)) setType(first);
1427
1704
  }, [target, type]);
1428
- if (targets.loading) return /* @__PURE__ */ jsx14(AdminNote, { children: "Loading follower records\u2026" });
1429
- if (targets.error || !targets.data) return /* @__PURE__ */ jsxs11(AdminNote, { children: [
1705
+ if (targets.loading) return /* @__PURE__ */ jsx19(AdminNote, { children: "Loading follower records\u2026" });
1706
+ if (targets.error || !targets.data) return /* @__PURE__ */ jsxs17(AdminNote, { children: [
1430
1707
  "Could not load followers",
1431
1708
  targets.error ? `: ${targets.error}` : "",
1432
1709
  "."
1433
1710
  ] });
1434
- if (!target) return /* @__PURE__ */ jsx14(AdminPage, { children: /* @__PURE__ */ jsx14(Panel, { title: "Follower records", children: /* @__PURE__ */ jsx14("p", { className: "muted", children: "No followers are configured." }) }) });
1435
- return /* @__PURE__ */ jsxs11(AdminPage, { children: [
1436
- /* @__PURE__ */ jsxs11("div", { style: { display: "flex", gap: 12, flexWrap: "wrap", alignItems: "end" }, children: [
1437
- /* @__PURE__ */ jsx14(Field4, { label: "Chapter", style: { minWidth: 240 }, children: /* @__PURE__ */ jsx14(
1438
- Select3,
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,
1439
1716
  {
1440
1717
  value: target.id,
1441
1718
  options: targets.data.targets.map((item) => ({ value: item.id, label: item.name })),
@@ -1446,8 +1723,8 @@ function NetworkRecordsWorkspace(props) {
1446
1723
  }
1447
1724
  }
1448
1725
  ) }),
1449
- /* @__PURE__ */ jsx14(Field4, { label: "Record type", style: { minWidth: 180 }, children: /* @__PURE__ */ jsx14(
1450
- Select3,
1726
+ /* @__PURE__ */ jsx19(Field6, { label: "Record type", style: { minWidth: 180 }, children: /* @__PURE__ */ jsx19(
1727
+ Select5,
1451
1728
  {
1452
1729
  value: type,
1453
1730
  options: target.types.map((item) => ({ value: item, label: item.replaceAll("_", " ") })),
@@ -1458,7 +1735,7 @@ function NetworkRecordsWorkspace(props) {
1458
1735
  }
1459
1736
  ) })
1460
1737
  ] }),
1461
- type ? /* @__PURE__ */ jsx14(
1738
+ type ? /* @__PURE__ */ jsx19(
1462
1739
  RecordsExplorer,
1463
1740
  {
1464
1741
  ctx,
@@ -1467,7 +1744,7 @@ function NetworkRecordsWorkspace(props) {
1467
1744
  leaderName: chapter.name
1468
1745
  },
1469
1746
  `${target.id}:${type}`
1470
- ) : /* @__PURE__ */ jsx14(Panel, { children: /* @__PURE__ */ jsx14("p", { className: "muted", children: "This follower has no browsable record types configured." }) })
1747
+ ) : /* @__PURE__ */ jsx19(Panel, { children: /* @__PURE__ */ jsx19("p", { className: "muted", children: "This follower has no browsable record types configured." }) })
1471
1748
  ] });
1472
1749
  }
1473
1750
  function networkRecordsWorkspace(chapter) {
@@ -1475,63 +1752,63 @@ function networkRecordsWorkspace(chapter) {
1475
1752
  id: "network",
1476
1753
  label: chapter.copy.admin.workspaces.network,
1477
1754
  defaultViewId: "records",
1478
- render: (ctx) => /* @__PURE__ */ jsx14(NetworkRecordsWorkspace, { chapter, ctx })
1755
+ render: (ctx) => /* @__PURE__ */ jsx19(NetworkRecordsWorkspace, { chapter, ctx })
1479
1756
  };
1480
1757
  }
1481
1758
 
1482
1759
  // src/ui/admin-portfolio.tsx
1483
1760
  import { StatBand as StatBand2, StepPipeline as StepPipeline2 } from "@odla-ai/ui/components";
1484
- import { jsx as jsx15, jsxs as jsxs12 } from "preact/jsx-runtime";
1761
+ import { jsx as jsx20, jsxs as jsxs18 } from "preact/jsx-runtime";
1485
1762
  function LeaderNetworkOverview({ ctx }) {
1486
1763
  const copy = useChapterCopy().admin.network;
1487
1764
  const { data, loading, error } = useAdminResource(
1488
1765
  ctx.getToken,
1489
1766
  "/api/admin/network/rollup"
1490
1767
  );
1491
- if (loading) return /* @__PURE__ */ jsx15(AdminNote, { children: copy.loadingRollup });
1492
- if (error || !data) return /* @__PURE__ */ jsxs12(AdminNote, { children: [
1768
+ if (loading) return /* @__PURE__ */ jsx20(AdminNote, { children: copy.loadingRollup });
1769
+ if (error || !data) return /* @__PURE__ */ jsxs18(AdminNote, { children: [
1493
1770
  copy.loadRollupFailed,
1494
1771
  error ? `: ${error}` : "",
1495
1772
  "."
1496
1773
  ] });
1497
- if (data.configured === 0) return /* @__PURE__ */ jsx15(AdminPage, { children: /* @__PURE__ */ jsx15(Panel, { title: copy.overview, children: /* @__PURE__ */ jsx15("p", { className: "muted", children: copy.noFollowers }) }) });
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 }) }) });
1498
1775
  const stats = [
1499
1776
  { value: data.configured.toLocaleString(), label: copy.configuredFollowers },
1500
1777
  { value: data.available.toLocaleString(), label: copy.reachableFollowers },
1501
1778
  { value: data.totalRecords.toLocaleString(), label: copy.recordsAcrossFollowers }
1502
1779
  ];
1503
1780
  const steps = data.types.map((type) => ({
1504
- icon: /* @__PURE__ */ jsx15("span", { style: { fontSize: 22, fontWeight: 700 }, children: type.total }),
1781
+ icon: /* @__PURE__ */ jsx20("span", { style: { fontSize: 22, fontWeight: 700 }, children: type.total }),
1505
1782
  title: type.type.replaceAll("_", " "),
1506
1783
  description: Object.entries(type.stages).filter(([, count]) => count > 0).map(([stage, count]) => `${stage.replaceAll("_", " ")} ${count}`).join(" \xB7 ") || copy.noRecordTotals
1507
1784
  }));
1508
- return /* @__PURE__ */ jsxs12(AdminPage, { children: [
1509
- /* @__PURE__ */ jsx15(StatBand2, { stats }),
1510
- /* @__PURE__ */ jsx15(Panel, { title: copy.followers, children: /* @__PURE__ */ jsx15("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "grid", gap: 10 }, children: data.targets.map((target) => /* @__PURE__ */ jsxs12("li", { style: { display: "flex", gap: 12, alignItems: "baseline", flexWrap: "wrap" }, children: [
1511
- /* @__PURE__ */ jsx15("strong", { style: { minWidth: 180 }, children: target.name }),
1512
- /* @__PURE__ */ jsx15("span", { className: "badge", children: target.transport.reachable === null ? copy.transportNotChecked : target.transport.reachable ? copy.transportReachable : copy.transportUnavailable }),
1513
- /* @__PURE__ */ jsx15("span", { className: "muted", children: target.transport.kind === "binding" ? formatChapterCopy(copy.bindingTransport, { binding: target.transport.binding ?? "" }) : copy.urlTransport }),
1514
- /* @__PURE__ */ jsx15("span", { className: "muted", children: target.configuration.activeRevision === null ? copy.noActiveConfiguration : formatChapterCopy(copy.activeConfiguration, { revision: target.configuration.activeRevision }) }),
1515
- /* @__PURE__ */ jsx15("span", { className: "muted", children: target.publicSite.available === null ? copy.publicSiteNotChecked : target.publicSite.available ? copy.publicSiteAvailable : copy.publicSiteUnavailable }),
1516
- target.error ? /* @__PURE__ */ jsx15("span", { className: "muted", children: target.error }) : null,
1517
- /* @__PURE__ */ jsx15("a", { href: target.url, target: "_blank", rel: "noreferrer", style: { marginLeft: "auto" }, children: target.url })
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 })
1518
1795
  ] }, target.id)) }) }),
1519
- /* @__PURE__ */ jsx15(Panel, { title: copy.recordTotals, children: steps.length ? /* @__PURE__ */ jsx15(StepPipeline2, { ariaLabel: copy.recordTotals, steps }) : /* @__PURE__ */ jsx15("p", { className: "muted", children: copy.noRecordTotals }) })
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 }) })
1520
1797
  ] });
1521
1798
  }
1522
1799
 
1523
1800
  // src/ui/admin-admission.tsx
1524
- import { useState as useState11 } from "preact/hooks";
1525
- import { jsx as jsx16, jsxs as jsxs13 } from "preact/jsx-runtime";
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";
1526
1803
  function AdmissionGrantsWorkspace(props) {
1527
1804
  const copy = useChapterCopy().admin.admission;
1528
1805
  const resource = useAdminResource(props.getToken, "/api/admin/admission-grants");
1529
- const [email, setEmail] = useState11("");
1530
- const [decision, setDecision] = useState11("waive_interview");
1531
- const [note, setNote] = useState11("");
1532
- const [expires, setExpires] = useState11("");
1533
- const [busy, setBusy] = useState11(false);
1534
- const [error, setError] = useState11(null);
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);
1535
1812
  const submit = async (event) => {
1536
1813
  event.preventDefault();
1537
1814
  setBusy(true);
@@ -1568,48 +1845,48 @@ function AdmissionGrantsWorkspace(props) {
1568
1845
  setBusy(false);
1569
1846
  }
1570
1847
  };
1571
- return /* @__PURE__ */ jsxs13(AdminPage, { children: [
1572
- /* @__PURE__ */ jsxs13(Panel, { title: copy.title, children: [
1573
- /* @__PURE__ */ jsx16("p", { className: "muted", style: { margin: 0 }, children: copy.description }),
1574
- /* @__PURE__ */ jsxs13("form", { onSubmit: (event) => void submit(event), style: { display: "grid", gap: 12, gridTemplateColumns: "minmax(220px,2fr) minmax(180px,1fr) minmax(160px,1fr)" }, children: [
1575
- /* @__PURE__ */ jsxs13("label", { children: [
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: [
1576
1853
  copy.email,
1577
- /* @__PURE__ */ jsx16("input", { required: true, type: "email", value: email, onInput: (event) => setEmail(event.currentTarget.value) })
1854
+ /* @__PURE__ */ jsx21("input", { required: true, type: "email", value: email, onInput: (event) => setEmail(event.currentTarget.value) })
1578
1855
  ] }),
1579
- /* @__PURE__ */ jsxs13("label", { children: [
1856
+ /* @__PURE__ */ jsxs19("label", { children: [
1580
1857
  copy.decision,
1581
- /* @__PURE__ */ jsxs13("select", { value: decision, onChange: (event) => setDecision(event.currentTarget.value), children: [
1582
- /* @__PURE__ */ jsx16("option", { value: "waive_interview", children: copy.waive }),
1583
- /* @__PURE__ */ jsx16("option", { value: "require_interview", children: copy.require })
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 })
1584
1861
  ] })
1585
1862
  ] }),
1586
- /* @__PURE__ */ jsxs13("label", { children: [
1863
+ /* @__PURE__ */ jsxs19("label", { children: [
1587
1864
  copy.expires,
1588
- /* @__PURE__ */ jsx16("input", { type: "date", value: expires, onInput: (event) => setExpires(event.currentTarget.value) })
1865
+ /* @__PURE__ */ jsx21("input", { type: "date", value: expires, onInput: (event) => setExpires(event.currentTarget.value) })
1589
1866
  ] }),
1590
- /* @__PURE__ */ jsxs13("label", { style: { gridColumn: "1 / -1" }, children: [
1867
+ /* @__PURE__ */ jsxs19("label", { style: { gridColumn: "1 / -1" }, children: [
1591
1868
  copy.note,
1592
- /* @__PURE__ */ jsx16("input", { value: note, maxLength: 2e3, onInput: (event) => setNote(event.currentTarget.value) })
1869
+ /* @__PURE__ */ jsx21("input", { value: note, maxLength: 2e3, onInput: (event) => setNote(event.currentTarget.value) })
1593
1870
  ] }),
1594
- /* @__PURE__ */ jsx16("button", { className: "btn secondary", type: "submit", disabled: busy, children: copy.add })
1871
+ /* @__PURE__ */ jsx21("button", { className: "btn secondary", type: "submit", disabled: busy, children: copy.add })
1595
1872
  ] }),
1596
- error ? /* @__PURE__ */ jsx16("p", { role: "alert", children: error }) : null
1873
+ error ? /* @__PURE__ */ jsx21("p", { role: "alert", children: error }) : null
1597
1874
  ] }),
1598
- /* @__PURE__ */ jsxs13(Panel, { title: copy.ledger, children: [
1599
- resource.loading ? /* @__PURE__ */ jsx16("p", { className: "muted", children: copy.loading }) : resource.error ? /* @__PURE__ */ jsx16("p", { role: "alert", children: resource.error }) : null,
1600
- /* @__PURE__ */ jsx16("div", { style: { display: "grid", gap: 10 }, children: (resource.data?.grants ?? []).map((grant) => {
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) => {
1601
1878
  const state = grant.consumedAt ? copy.consumed : grant.revokedAt || !grant.active ? copy.revoked : grant.expiresAt && grant.expiresAt <= Date.now() ? copy.expired : copy.active;
1602
- return /* @__PURE__ */ jsxs13("article", { className: "card", style: { padding: 14 }, children: [
1603
- /* @__PURE__ */ jsx16("strong", { children: grant.email }),
1879
+ return /* @__PURE__ */ jsxs19("article", { className: "card", style: { padding: 14 }, children: [
1880
+ /* @__PURE__ */ jsx21("strong", { children: grant.email }),
1604
1881
  " \xB7 ",
1605
1882
  grant.decision === "waive_interview" ? copy.waive : copy.require,
1606
- /* @__PURE__ */ jsxs13("p", { className: "muted", style: { margin: "6px 0" }, children: [
1883
+ /* @__PURE__ */ jsxs19("p", { className: "muted", style: { margin: "6px 0" }, children: [
1607
1884
  grant.sourceScope === "local" ? copy.local : copy.parent,
1608
1885
  " \xB7 ",
1609
1886
  state,
1610
1887
  grant.note ? ` \xB7 ${grant.note}` : ""
1611
1888
  ] }),
1612
- grant.sourceScope === "local" && state === copy.active ? /* @__PURE__ */ jsx16("button", { className: "btn secondary mini", disabled: busy, onClick: () => void revoke(grant), children: copy.revoke }) : null
1889
+ grant.sourceScope === "local" && state === copy.active ? /* @__PURE__ */ jsx21("button", { className: "btn secondary mini", disabled: busy, onClick: () => void revoke(grant), children: copy.revoke }) : null
1613
1890
  ] }, grant.id);
1614
1891
  }) })
1615
1892
  ] })
@@ -1620,28 +1897,56 @@ function admissionGrantsWorkspace(label = "Admission") {
1620
1897
  id: "admission",
1621
1898
  label,
1622
1899
  defaultViewId: "grants",
1623
- render: (ctx) => /* @__PURE__ */ jsx16(AdmissionGrantsWorkspace, { getToken: ctx.getToken })
1900
+ render: (ctx) => /* @__PURE__ */ jsx21(AdmissionGrantsWorkspace, { getToken: ctx.getToken })
1624
1901
  };
1625
1902
  }
1626
1903
  function LeaderAdmissionAction(props) {
1627
- const [decision, setDecision] = useState11("waive_interview");
1628
- const [note, setNote] = useState11("");
1629
- const [busy, setBusy] = useState11(false);
1630
- const [error, setError] = useState11(null);
1904
+ return /* @__PURE__ */ jsx21(LeaderAdmissionForm, { ...props }, JSON.stringify([props.targetId, props.personId, props.sourceRecordId]));
1905
+ }
1906
+ 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);
1913
+ const attempt = useRef2(null);
1914
+ useEffect8(() => {
1915
+ let live = true;
1916
+ const personId = props.sourceRecordId ? `chapter-person:${props.targetId}:${props.sourceRecordId}` : props.personId;
1917
+ void adminFetch(props.getToken, `/api/admin/network/admissions?targetId=${encodeURIComponent(props.targetId)}`).then((result) => {
1918
+ if (!live) return;
1919
+ const saved = result.assignments.find((row) => row.personId === personId && row.active && (!row.expiresAt || row.expiresAt > Date.now()));
1920
+ setDecision(saved?.decision ?? "");
1921
+ setNote(saved?.note ?? "");
1922
+ setLoaded(true);
1923
+ if (saved && result.delivery?.status !== "acknowledged") setStatus("Saved; delivery is pending. Retry to reconcile the same setting.");
1924
+ }).catch((cause) => {
1925
+ if (live) setError(cause instanceof Error ? cause.message : "Invitation setting could not be loaded.");
1926
+ });
1927
+ return () => {
1928
+ live = false;
1929
+ };
1930
+ }, [props.getToken, props.targetId, props.personId, props.sourceRecordId]);
1631
1931
  const submit = async () => {
1932
+ if (!loaded || !decision || busy) return;
1632
1933
  setBusy(true);
1633
1934
  setError(null);
1634
1935
  try {
1936
+ const fingerprint = JSON.stringify([props.targetId, props.personId, props.sourceRecordId, decision, note.trim()]);
1937
+ if (attempt.current?.fingerprint !== fingerprint) attempt.current = { fingerprint, id: crypto.randomUUID() };
1635
1938
  const result = await adminFetch(props.getToken, "/api/admin/network/admissions", {
1636
1939
  method: "POST",
1637
1940
  body: JSON.stringify({
1638
1941
  targetId: props.targetId,
1639
- personId: props.personId,
1942
+ ...props.sourceRecordId ? { sourceRecordId: props.sourceRecordId } : { personId: props.personId },
1640
1943
  decision,
1641
1944
  ...note.trim() ? { note: note.trim() } : {},
1642
- mutationId: crypto.randomUUID()
1945
+ mutationId: attempt.current.id
1643
1946
  })
1644
1947
  });
1948
+ setStatus(result.delivery.status === "acknowledged" ? "Invitation setting saved at the chapter." : "Saved; delivery is pending. Retry to reconcile the same setting.");
1949
+ if (result.delivery.status === "acknowledged") attempt.current = null;
1645
1950
  props.onSaved?.(result);
1646
1951
  } catch (cause) {
1647
1952
  setError(cause instanceof Error ? cause.message : String(cause));
@@ -1649,20 +1954,22 @@ function LeaderAdmissionAction(props) {
1649
1954
  setBusy(false);
1650
1955
  }
1651
1956
  };
1652
- return /* @__PURE__ */ jsxs13("div", { style: { display: "grid", gap: 8 }, children: [
1653
- /* @__PURE__ */ jsxs13("label", { children: [
1957
+ return /* @__PURE__ */ jsxs19("div", { style: { display: "grid", gap: 8 }, children: [
1958
+ /* @__PURE__ */ jsxs19("label", { children: [
1654
1959
  "Interview",
1655
- /* @__PURE__ */ jsxs13("select", { value: decision, onChange: (event) => setDecision(event.currentTarget.value), children: [
1656
- /* @__PURE__ */ jsx16("option", { value: "waive_interview", children: "Already completed" }),
1657
- /* @__PURE__ */ jsx16("option", { value: "require_interview", children: "Required" })
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" })
1658
1964
  ] })
1659
1965
  ] }),
1660
- /* @__PURE__ */ jsxs13("label", { children: [
1966
+ /* @__PURE__ */ jsxs19("label", { children: [
1661
1967
  "Internal note",
1662
- /* @__PURE__ */ jsx16("input", { maxLength: 2e3, value: note, onInput: (event) => setNote(event.currentTarget.value) })
1968
+ /* @__PURE__ */ jsx21("input", { disabled: !loaded || busy, maxLength: 2e3, value: note, onInput: (event) => setNote(event.currentTarget.value) })
1663
1969
  ] }),
1664
- /* @__PURE__ */ jsx16("button", { className: "btn secondary", type: "button", disabled: busy, onClick: () => void submit(), children: busy ? "Saving\u2026" : "Prepare for chapter" }),
1665
- error ? /* @__PURE__ */ jsx16("p", { role: "alert", children: error }) : null
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
1666
1973
  ] });
1667
1974
  }
1668
1975
 
@@ -1670,19 +1977,19 @@ function LeaderAdmissionAction(props) {
1670
1977
  import { Tabs as Tabs2 } from "@odla-ai/ui/components";
1671
1978
 
1672
1979
  // src/ui/admin-availability.tsx
1673
- import { useState as useState12 } from "preact/hooks";
1674
- import { Button as Button5, Checkbox, Field as Field5, Input } from "@odla-ai/ui/components";
1675
- import { jsx as jsx17, jsxs as jsxs14 } from "preact/jsx-runtime";
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";
1676
1983
  function AvailabilityBody({ ctx }) {
1677
1984
  const copy = useChapterCopy().admin.availability;
1678
1985
  const { data, loading, error, refresh } = useAdminResource(ctx.getToken, "/api/admin/scheduling");
1679
- const [draft, setDraft] = useState12(null);
1680
- const [busy, setBusy] = useState12(false);
1681
- const [note, setNote] = useState12(null);
1682
- const [errors, setErrors] = useState12({});
1986
+ const [draft, setDraft] = useState16(null);
1987
+ const [busy, setBusy] = useState16(false);
1988
+ const [note, setNote] = useState16(null);
1989
+ const [errors, setErrors] = useState16({});
1683
1990
  const cfg = draft ?? data?.scheduling ?? null;
1684
- if (loading) return /* @__PURE__ */ jsx17(AdminNote, { children: copy.loading });
1685
- if (error || !cfg) return /* @__PURE__ */ jsxs14(AdminNote, { children: [
1991
+ if (loading) return /* @__PURE__ */ jsx22(AdminNote, { children: copy.loading });
1992
+ if (error || !cfg) return /* @__PURE__ */ jsxs20(AdminNote, { children: [
1686
1993
  copy.loadFailed,
1687
1994
  error ? `: ${error}` : "",
1688
1995
  "."
@@ -1712,29 +2019,29 @@ function AvailabilityBody({ ctx }) {
1712
2019
  setBusy(false);
1713
2020
  }
1714
2021
  };
1715
- const numField = (key, label) => /* @__PURE__ */ jsx17(Field5, { label, error: errors[key], children: /* @__PURE__ */ jsx17(Input, { type: "number", value: cfg[key], onInput: (e) => edit({ [key]: num(e.target.value, cfg[key]) }) }) });
1716
- return /* @__PURE__ */ jsx17(AdminPage, { children: /* @__PURE__ */ jsxs14(Panel, { title: copy.title, actions: note ? /* @__PURE__ */ jsx17("span", { className: "muted", children: note }) : void 0, children: [
1717
- /* @__PURE__ */ jsx17(Field5, { label: copy.days, error: errors.days, children: /* @__PURE__ */ jsx17("div", { style: { display: "flex", gap: 14, flexWrap: "wrap" }, children: copy.dayLabels.map((d, i) => /* @__PURE__ */ jsx17(Checkbox, { label: d, checked: cfg.days.includes(i), onChange: () => toggleDay(i) }, d)) }) }),
1718
- /* @__PURE__ */ jsxs14("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))", gap: 14 }, children: [
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: [
1719
2026
  numField("startHour", copy.startHour),
1720
2027
  numField("endHour", copy.endHour),
1721
2028
  numField("slotMinutes", copy.slotMinutes),
1722
2029
  numField("minNoticeHours", copy.minNoticeHours),
1723
2030
  numField("windowDays", copy.windowDays),
1724
- /* @__PURE__ */ jsx17(Field5, { label: copy.timezone, error: errors.timezone, children: /* @__PURE__ */ jsx17(Input, { value: cfg.timezone, onInput: (e) => edit({ timezone: e.target.value }) }) })
2031
+ /* @__PURE__ */ jsx22(Field7, { label: copy.timezone, error: errors.timezone, children: /* @__PURE__ */ jsx22(Input2, { value: cfg.timezone, onInput: (e) => edit({ timezone: e.target.value }) }) })
1725
2032
  ] }),
1726
- /* @__PURE__ */ jsx17(Field5, { label: copy.summaryTemplate, error: errors.summaryTemplate, children: /* @__PURE__ */ jsx17(Input, { value: cfg.summaryTemplate, onInput: (e) => edit({ summaryTemplate: e.target.value }) }) }),
1727
- /* @__PURE__ */ jsx17("div", { children: /* @__PURE__ */ jsx17(Button5, { disabled: !draft || busy, onClick: () => void save(), children: copy.save }) })
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 }) })
1728
2035
  ] }) });
1729
2036
  }
1730
2037
  function availabilitySection(options = {}) {
1731
2038
  const { id = "availability", label = "Availability" } = options;
1732
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx17(AvailabilityBody, { ctx }) };
2039
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx22(AvailabilityBody, { ctx }) };
1733
2040
  }
1734
2041
 
1735
2042
  // src/ui/admin-builder-library.tsx
1736
- import { useEffect as useEffect8, useMemo as useMemo2, useState as useState13 } from "preact/hooks";
1737
- import { jsx as jsx18, jsxs as jsxs15 } from "preact/jsx-runtime";
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";
1738
2045
  var KINDS = ["document", "note", "link", "inspiration", "image", "file"];
1739
2046
  var KIND_LABEL = { document: "Document", note: "Note", link: "Link", inspiration: "Inspiration", image: "Image", file: "File" };
1740
2047
  var STATUS_LABEL = { draft: "Draft", published: "Published", archived: "Archived" };
@@ -1766,13 +2073,13 @@ function localResource(kind, chapterId, mode) {
1766
2073
  };
1767
2074
  }
1768
2075
  function ResourcePreview({ item }) {
1769
- return /* @__PURE__ */ jsxs15("div", { className: "card", style: { padding: 14 }, children: [
1770
- /* @__PURE__ */ jsx18("div", { className: "card-label", children: "Preview" }),
1771
- /* @__PURE__ */ jsx18("h3", { style: { margin: "6px 0" }, children: item.title || "Untitled" }),
1772
- item.summary ? /* @__PURE__ */ jsx18("p", { style: { margin: "0 0 10px" }, children: item.summary }) : null,
1773
- item.bodyMarkdown ? /* @__PURE__ */ jsx18("pre", { style: { margin: 0, whiteSpace: "pre-wrap", font: "inherit", lineHeight: 1.55 }, children: item.bodyMarkdown }) : null,
1774
- item.url ? /* @__PURE__ */ jsx18("a", { href: item.url, target: "_blank", rel: "noreferrer", children: item.url }) : null,
1775
- item.brandAsset ? /* @__PURE__ */ jsxs15("div", { style: META, children: [
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: [
1776
2083
  "Brand asset \xB7 ",
1777
2084
  item.brandAsset.bookId,
1778
2085
  " / ",
@@ -1784,15 +2091,15 @@ function ResourcePreview({ item }) {
1784
2091
  function BuilderLibraryAdmin({ ctx, initialData }) {
1785
2092
  const remote = useAdminResource(ctx.getToken, "/api/admin/builder-library");
1786
2093
  const seed = initialData ?? remote.data;
1787
- const [resources, setResources] = useState13(() => [...seed?.local?.document.resources ?? []]);
1788
- const [selectedKey, setSelectedKey] = useState13(() => seed?.local?.document.resources[0]?.id ? localKey(seed.local.document.resources[0].id) : null);
1789
- const [query, setQuery] = useState13("");
1790
- const [kindFilter, setKindFilter] = useState13("all");
1791
- const [statusFilter, setStatusFilter] = useState13("all");
1792
- const [newKind, setNewKind] = useState13("document");
1793
- const [saveError, setSaveError] = useState13(null);
1794
- const [saving, setSaving] = useState13(false);
1795
- useEffect8(() => {
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);
2102
+ useEffect9(() => {
1796
2103
  if (!remote.data) return;
1797
2104
  const next = [...remote.data.local?.document.resources ?? []];
1798
2105
  setResources(next);
@@ -1808,8 +2115,8 @@ function BuilderLibraryAdmin({ ctx, initialData }) {
1808
2115
  return (!query.trim() || haystack.includes(query.toLowerCase().trim())) && (kindFilter === "all" || resource.kind === kindFilter) && (statusFilter === "all" || resource.status === statusFilter);
1809
2116
  });
1810
2117
  const selected = entries.find((entry) => entry.key === selectedKey) ?? visible[0] ?? null;
1811
- if (!data && remote.loading) return /* @__PURE__ */ jsx18(AdminPage, { children: /* @__PURE__ */ jsx18(AdminNote, { children: "Loading Builder Library\u2026" }) });
1812
- if (remote.error || !data) return /* @__PURE__ */ jsx18(AdminPage, { children: /* @__PURE__ */ jsxs15(AdminNote, { children: [
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: [
1813
2120
  "Builder Library could not be loaded: ",
1814
2121
  remote.error ?? "unknown error"
1815
2122
  ] }) });
@@ -1845,179 +2152,232 @@ function BuilderLibraryAdmin({ ctx, initialData }) {
1845
2152
  }
1846
2153
  };
1847
2154
  const scopeValue = selected?.resource.scope.kind === "chapter" ? `chapter:${selected.resource.scope.chapterId}` : selected?.resource.scope.kind ?? "built_not_found";
1848
- return /* @__PURE__ */ jsxs15(AdminPage, { children: [
1849
- /* @__PURE__ */ jsxs15(Panel, { title: /* @__PURE__ */ jsxs15("span", { children: [
2155
+ return /* @__PURE__ */ jsxs21(AdminPage, { children: [
2156
+ /* @__PURE__ */ jsxs21(Panel, { title: /* @__PURE__ */ jsxs21("span", { children: [
1850
2157
  "Builder Library ",
1851
- /* @__PURE__ */ jsx18("span", { className: "muted", children: "\xB7 private" })
1852
- ] }), actions: /* @__PURE__ */ jsxs15("div", { style: ROW, children: [
1853
- /* @__PURE__ */ jsx18("select", { "aria-label": "New resource type", value: newKind, onChange: (event) => setNewKind(event.currentTarget.value), children: KINDS.map((kind) => /* @__PURE__ */ jsx18("option", { value: kind, children: KIND_LABEL[kind] }, kind)) }),
1854
- /* @__PURE__ */ jsx18("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring, onClick: add, children: "Add resource" })
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" })
1855
2162
  ] }), children: [
1856
- /* @__PURE__ */ jsx18("p", { className: "muted", style: { margin: 0 }, children: "Documents, links, and Brand assets used by site-building agents. Nothing here appears on a member page." }),
1857
- /* @__PURE__ */ jsxs15("div", { style: ROW, children: [
1858
- /* @__PURE__ */ jsx18("input", { "aria-label": "Search resources", placeholder: "Search resources", value: query, onInput: (event) => setQuery(event.currentTarget.value), style: { flex: "1 1 220px" } }),
1859
- /* @__PURE__ */ jsxs15("select", { "aria-label": "Filter by type", value: kindFilter, onChange: (event) => setKindFilter(event.currentTarget.value), children: [
1860
- /* @__PURE__ */ jsx18("option", { value: "all", children: "All types" }),
1861
- KINDS.map((kind) => /* @__PURE__ */ jsx18("option", { value: kind, children: KIND_LABEL[kind] }, kind))
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))
1862
2169
  ] }),
1863
- /* @__PURE__ */ jsxs15("select", { "aria-label": "Filter by status", value: statusFilter, onChange: (event) => setStatusFilter(event.currentTarget.value), children: [
1864
- /* @__PURE__ */ jsx18("option", { value: "all", children: "All statuses" }),
1865
- /* @__PURE__ */ jsx18("option", { value: "draft", children: "Draft" }),
1866
- /* @__PURE__ */ jsx18("option", { value: "published", children: "Published" }),
1867
- /* @__PURE__ */ jsx18("option", { value: "archived", children: "Archived" })
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" })
1868
2175
  ] })
1869
2176
  ] })
1870
2177
  ] }),
1871
- /* @__PURE__ */ jsxs15("div", { style: GRID, "data-builder-library-cms": true, children: [
1872
- /* @__PURE__ */ jsx18(Panel, { title: `${visible.length} resource${visible.length === 1 ? "" : "s"}`, children: /* @__PURE__ */ jsx18("div", { style: { ...STACK, maxHeight: "70vh", overflow: "auto" }, children: visible.length === 0 ? /* @__PURE__ */ jsx18("p", { className: "muted", children: "No resources match these filters." }) : visible.map((entry) => /* @__PURE__ */ jsxs15("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: [
1873
- /* @__PURE__ */ jsxs15("div", { style: { ...ROW, justifyContent: "space-between" }, children: [
1874
- /* @__PURE__ */ jsx18("strong", { children: entry.resource.title }),
1875
- /* @__PURE__ */ jsx18("span", { className: "badge", children: KIND_LABEL[entry.resource.kind] })
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] })
1876
2183
  ] }),
1877
- /* @__PURE__ */ jsx18("p", { className: "muted", style: { margin: "6px 0", lineHeight: 1.4 }, children: contentSummary(entry.resource) }),
1878
- /* @__PURE__ */ jsxs15("div", { style: META, children: [
1879
- /* @__PURE__ */ jsx18("span", { children: STATUS_LABEL[entry.resource.status] }),
1880
- /* @__PURE__ */ jsx18("span", { children: "\xB7" }),
1881
- /* @__PURE__ */ jsx18("span", { children: scopeLabel(entry.resource.scope) }),
1882
- /* @__PURE__ */ jsx18("span", { children: "\xB7" }),
1883
- /* @__PURE__ */ jsx18("span", { children: entry.sourceId })
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 })
1884
2191
  ] })
1885
2192
  ] }, entry.key)) }) }),
1886
- /* @__PURE__ */ jsxs15(Panel, { title: selected ? selected.resource.title : "Select a resource", actions: selected?.local ? /* @__PURE__ */ jsxs15("div", { style: ROW, children: [
1887
- /* @__PURE__ */ jsx18("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" }),
1888
- /* @__PURE__ */ jsx18("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring || saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save changes" })
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" })
1889
2196
  ] }) : null, children: [
1890
- !selected ? /* @__PURE__ */ jsx18("p", { className: "muted", children: "Add a resource or choose one from the list." }) : selected.local ? /* @__PURE__ */ jsx18(LocalEditor, { selected: selected.resource, data, scopeValue, saving, update, setResources, setSelectedKey }) : /* @__PURE__ */ jsxs15("div", { style: STACK, children: [
1891
- /* @__PURE__ */ jsxs15("div", { style: META, 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: [
1892
2199
  "Read only \xB7 supplied by ",
1893
2200
  selected.sourceId,
1894
2201
  " \xB7 source revision ",
1895
2202
  selected.sourceRevision
1896
2203
  ] }),
1897
- /* @__PURE__ */ jsxs15("div", { children: [
1898
- /* @__PURE__ */ jsx18("span", { className: "badge", children: STATUS_LABEL[selected.resource.status] }),
2204
+ /* @__PURE__ */ jsxs21("div", { children: [
2205
+ /* @__PURE__ */ jsx23("span", { className: "badge", children: STATUS_LABEL[selected.resource.status] }),
1899
2206
  " ",
1900
- /* @__PURE__ */ jsx18("span", { className: "badge", children: scopeLabel(selected.resource.scope) })
2207
+ /* @__PURE__ */ jsx23("span", { className: "badge", children: scopeLabel(selected.resource.scope) })
1901
2208
  ] }),
1902
- /* @__PURE__ */ jsx18(ResourcePreview, { item: selected.resource }),
1903
- data.mode === "hub" && selected.resource.scope.kind === "chapter" ? /* @__PURE__ */ jsx18("button", { className: "btn secondary", type: "button", onClick: () => void promote(selected), children: "Copy to all chapters" }) : null
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
1904
2211
  ] }),
1905
- saveError ? /* @__PURE__ */ jsxs15("div", { className: "notice danger", role: "alert", children: [
1906
- /* @__PURE__ */ jsx18("strong", { children: "Fix these items before saving:" }),
1907
- /* @__PURE__ */ jsx18("ul", { children: saveError.map((error) => /* @__PURE__ */ jsx18("li", { children: error }, error)) })
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)) })
1908
2215
  ] }) : null
1909
2216
  ] })
1910
2217
  ] })
1911
2218
  ] });
1912
2219
  }
1913
2220
  function LocalEditor({ selected, data, scopeValue, update, setResources, setSelectedKey }) {
1914
- return /* @__PURE__ */ jsxs15("div", { style: STACK, children: [
1915
- /* @__PURE__ */ jsxs15("div", { style: META, children: [
2221
+ return /* @__PURE__ */ jsxs21("div", { style: STACK, children: [
2222
+ /* @__PURE__ */ jsxs21("div", { style: META, children: [
1916
2223
  "Local \xB7 resource revision ",
1917
2224
  selected.revision,
1918
2225
  " \xB7 library revision ",
1919
2226
  data.local?.revision ?? 0
1920
2227
  ] }),
1921
- /* @__PURE__ */ jsxs15("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }, children: [
1922
- /* @__PURE__ */ jsxs15("label", { className: "field", children: [
1923
- /* @__PURE__ */ jsx18("span", { children: "Title" }),
1924
- /* @__PURE__ */ jsx18("input", { value: selected.title, onInput: (event) => update({ title: event.currentTarget.value }) })
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 }) })
1925
2232
  ] }),
1926
- /* @__PURE__ */ jsxs15("label", { className: "field", children: [
1927
- /* @__PURE__ */ jsx18("span", { children: "ID" }),
1928
- /* @__PURE__ */ jsx18("input", { value: selected.id, onInput: (event) => {
2233
+ /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2234
+ /* @__PURE__ */ jsx23("span", { children: "ID" }),
2235
+ /* @__PURE__ */ jsx23("input", { value: selected.id, onInput: (event) => {
1929
2236
  const id = cleanId(event.currentTarget.value);
1930
2237
  setResources((items) => items.map((item) => item.id === selected.id ? { ...item, id } : item));
1931
2238
  setSelectedKey(localKey(id));
1932
2239
  } })
1933
2240
  ] }),
1934
- /* @__PURE__ */ jsxs15("label", { className: "field", children: [
1935
- /* @__PURE__ */ jsx18("span", { children: "Type" }),
1936
- /* @__PURE__ */ jsx18("select", { value: selected.kind, onChange: (event) => {
2241
+ /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2242
+ /* @__PURE__ */ jsx23("span", { children: "Type" }),
2243
+ /* @__PURE__ */ jsx23("select", { value: selected.kind, onChange: (event) => {
1937
2244
  const kind = event.currentTarget.value;
1938
2245
  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 });
1939
- }, children: KINDS.map((kind) => /* @__PURE__ */ jsx18("option", { value: kind, children: KIND_LABEL[kind] }, kind)) })
2246
+ }, children: KINDS.map((kind) => /* @__PURE__ */ jsx23("option", { value: kind, children: KIND_LABEL[kind] }, kind)) })
1940
2247
  ] }),
1941
- /* @__PURE__ */ jsxs15("label", { className: "field", children: [
1942
- /* @__PURE__ */ jsx18("span", { children: "Status" }),
1943
- /* @__PURE__ */ jsxs15("select", { value: selected.status, onChange: (event) => update({ status: event.currentTarget.value }), children: [
1944
- /* @__PURE__ */ jsx18("option", { value: "draft", children: "Draft" }),
1945
- /* @__PURE__ */ jsx18("option", { value: "published", children: "Published" }),
1946
- /* @__PURE__ */ jsx18("option", { value: "archived", children: "Archived" })
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" })
1947
2254
  ] })
1948
2255
  ] }),
1949
- /* @__PURE__ */ jsxs15("label", { className: "field", children: [
1950
- /* @__PURE__ */ jsx18("span", { children: "Visible to" }),
1951
- /* @__PURE__ */ jsxs15("select", { value: scopeValue, onChange: (event) => {
2256
+ /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2257
+ /* @__PURE__ */ jsx23("span", { children: "Visible to" }),
2258
+ /* @__PURE__ */ jsxs21("select", { value: scopeValue, onChange: (event) => {
1952
2259
  const value = event.currentTarget.value;
1953
2260
  update({ scope: value === "global" ? { kind: "global" } : value === "built_not_found" ? { kind: "built_not_found" } : { kind: "chapter", chapterId: value.slice("chapter:".length) } });
1954
2261
  }, children: [
1955
- data.mode === "hub" ? /* @__PURE__ */ jsx18("option", { value: "built_not_found", children: "Built Not Found only" }) : null,
1956
- data.mode === "hub" ? /* @__PURE__ */ jsx18("option", { value: "global", children: "All chapters" }) : null,
1957
- data.chapterTargets.map(({ chapterId }) => /* @__PURE__ */ jsxs15("option", { value: `chapter:${chapterId}`, 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: [
1958
2265
  "Only ",
1959
2266
  chapterId
1960
2267
  ] }, chapterId))
1961
2268
  ] })
1962
2269
  ] }),
1963
- /* @__PURE__ */ jsxs15("label", { className: "field", children: [
1964
- /* @__PURE__ */ jsx18("span", { children: "Tags" }),
1965
- /* @__PURE__ */ jsx18("input", { value: selected.tags.join(", "), placeholder: "brand, membership", onInput: (event) => update({ tags: event.currentTarget.value.split(",").map((tag) => tag.trim()).filter(Boolean) }) })
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) }) })
1966
2273
  ] })
1967
2274
  ] }),
1968
- /* @__PURE__ */ jsxs15("label", { className: "field", children: [
1969
- /* @__PURE__ */ jsx18("span", { children: "Summary" }),
1970
- /* @__PURE__ */ jsx18("textarea", { rows: 2, value: selected.summary ?? "", onInput: (event) => update({ summary: event.currentTarget.value || void 0 }) })
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 }) })
1971
2278
  ] }),
1972
- selected.kind === "document" || selected.kind === "note" ? /* @__PURE__ */ jsxs15("label", { className: "field", children: [
1973
- /* @__PURE__ */ jsx18("span", { children: "Markdown" }),
1974
- /* @__PURE__ */ jsx18("textarea", { rows: 12, value: selected.bodyMarkdown ?? "", onInput: (event) => update({ bodyMarkdown: event.currentTarget.value }) })
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 }) })
1975
2282
  ] }) : null,
1976
- selected.kind === "link" || selected.kind === "inspiration" ? /* @__PURE__ */ jsxs15("label", { className: "field", children: [
1977
- /* @__PURE__ */ jsx18("span", { children: "HTTPS URL" }),
1978
- /* @__PURE__ */ jsx18("input", { type: "url", value: selected.url ?? "", onInput: (event) => update({ url: event.currentTarget.value }) })
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 }) })
1979
2286
  ] }) : null,
1980
- selected.kind === "image" || selected.kind === "file" ? /* @__PURE__ */ jsxs15("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }, children: [
1981
- /* @__PURE__ */ jsxs15("label", { className: "field", children: [
1982
- /* @__PURE__ */ jsx18("span", { children: "Brand book ID" }),
1983
- /* @__PURE__ */ jsx18("input", { value: selected.brandAsset?.bookId ?? "", onInput: (event) => update({ brandAsset: { bookId: event.currentTarget.value, assetId: selected.brandAsset?.assetId ?? "", ...selected.brandAsset?.filename ? { filename: selected.brandAsset.filename } : {} } }) })
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 } : {} } }) })
1984
2291
  ] }),
1985
- /* @__PURE__ */ jsxs15("label", { className: "field", children: [
1986
- /* @__PURE__ */ jsx18("span", { children: "Asset ID" }),
1987
- /* @__PURE__ */ jsx18("input", { value: selected.brandAsset?.assetId ?? "", onInput: (event) => update({ brandAsset: { bookId: selected.brandAsset?.bookId ?? "", assetId: event.currentTarget.value, ...selected.brandAsset?.filename ? { filename: selected.brandAsset.filename } : {} } }) })
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 } : {} } }) })
1988
2295
  ] }),
1989
- /* @__PURE__ */ jsxs15("label", { className: "field", children: [
1990
- /* @__PURE__ */ jsx18("span", { children: "Filename (optional)" }),
1991
- /* @__PURE__ */ jsx18("input", { value: selected.brandAsset?.filename ?? "", onInput: (event) => update({ brandAsset: { bookId: selected.brandAsset?.bookId ?? "", assetId: selected.brandAsset?.assetId ?? "", ...event.currentTarget.value ? { filename: event.currentTarget.value } : {} } }) })
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 } : {} } }) })
1992
2299
  ] })
1993
2300
  ] }) : null,
1994
- /* @__PURE__ */ jsx18(ResourcePreview, { item: selected })
2301
+ /* @__PURE__ */ jsx23(ResourcePreview, { item: selected })
1995
2302
  ] });
1996
2303
  }
1997
2304
  function builderLibrarySection() {
1998
- return { id: "builder-library", label: "Builder Library", render: (ctx) => /* @__PURE__ */ jsx18(BuilderLibraryAdmin, { ctx }) };
2305
+ return { id: "builder-library", label: "Builder Library", render: (ctx) => /* @__PURE__ */ jsx23(BuilderLibraryAdmin, { ctx }) };
2306
+ }
2307
+
2308
+ // 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";
2311
+
2312
+ // 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";
2316
+ 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("");
2319
+ if (!["sending", "uncertain"].includes(row.deliveryState ?? "") || !row.deliveryAttempt) return null;
2320
+ const resolve2 = async (decision) => {
2321
+ setBusy(true);
2322
+ setNote("");
2323
+ try {
2324
+ await adminFetch(ctx.getToken, `/api/admin/email/log/${encodeURIComponent(row.id)}/resolve`, {
2325
+ method: "POST",
2326
+ body: JSON.stringify({
2327
+ expectedAttempt: row.deliveryAttempt,
2328
+ expectedState: row.deliveryState,
2329
+ decision,
2330
+ reason,
2331
+ ...messageId.trim() ? { messageId: messageId.trim() } : {}
2332
+ })
2333
+ });
2334
+ setOpen(false);
2335
+ onResolved();
2336
+ } catch (error) {
2337
+ setNote(error instanceof Error ? error.message : "Unable to record evidence");
2338
+ } finally {
2339
+ setBusy(false);
2340
+ }
2341
+ };
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: [
2345
+ "Attempt ",
2346
+ row.deliveryAttempt,
2347
+ ": ",
2348
+ row.subject,
2349
+ ". Check provider evidence, not just whether the message is in an inbox. This action does not send mail."
2350
+ ] }),
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
2357
+ ] });
1999
2358
  }
2000
2359
 
2001
2360
  // src/ui/admin-email.tsx
2002
- import { useState as useState14 } from "preact/hooks";
2003
- import { Button as Button6, Checkbox as Checkbox2, DataTable as DataTable3, Field as Field6, Input as Input2, Textarea as Textarea2 } from "@odla-ai/ui/components";
2004
- import { jsx as jsx19, jsxs as jsxs16 } from "preact/jsx-runtime";
2005
- var logColumns = (copy) => [
2361
+ import { jsx as jsx25, jsxs as jsxs23 } from "preact/jsx-runtime";
2362
+ var logColumns = (copy, ctx, refresh) => [
2006
2363
  { key: "sentAt", header: copy.sentColumn, cell: (r) => new Date(r.sentAt).toLocaleString(), sortAs: "number", sortValue: (r) => r.sentAt },
2007
2364
  { key: "template", header: copy.templateColumn, cell: (r) => r.template },
2008
2365
  { key: "to", header: copy.toColumn, cell: (r) => r.to },
2009
- { key: "status", header: copy.statusColumn, cell: (r) => r.error ? /* @__PURE__ */ jsx19("span", { className: "badge", children: copy.failed }) : r.redirected ? /* @__PURE__ */ jsx19("span", { className: "badge", children: copy.redirected }) : copy.delivered }
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 })
2369
+ ] }) }
2010
2370
  ];
2011
2371
  function EmailBody({ ctx }) {
2012
2372
  const copy = useChapterCopy().admin.email;
2013
2373
  const cfg = useAdminResource(ctx.getToken, "/api/admin/group/email");
2014
2374
  const log = useAdminResource(ctx.getToken, "/api/admin/email/log");
2015
- const [draft, setDraft] = useState14(null);
2016
- const [busy, setBusy] = useState14(null);
2017
- const [note, setNote] = useState14(null);
2375
+ const [draft, setDraft] = useState19(null);
2376
+ const [busy, setBusy] = useState19(null);
2377
+ const [note, setNote] = useState19(null);
2018
2378
  const data = draft ?? cfg.data;
2019
- if (cfg.loading) return /* @__PURE__ */ jsx19(AdminNote, { children: copy.loading });
2020
- if (cfg.error || !data) return /* @__PURE__ */ jsxs16(AdminNote, { children: [
2379
+ if (cfg.loading) return /* @__PURE__ */ jsx25(AdminNote, { children: copy.loading });
2380
+ if (cfg.error || !data) return /* @__PURE__ */ jsxs23(AdminNote, { children: [
2021
2381
  copy.loadFailed,
2022
2382
  cfg.error ? `: ${cfg.error}` : "",
2023
2383
  "."
@@ -2050,44 +2410,44 @@ function EmailBody({ ctx }) {
2050
2410
  }) : copy.testFailed);
2051
2411
  log.refresh();
2052
2412
  });
2053
- return /* @__PURE__ */ jsxs16(AdminPage, { children: [
2054
- /* @__PURE__ */ jsxs16(
2413
+ return /* @__PURE__ */ jsxs23(AdminPage, { children: [
2414
+ /* @__PURE__ */ jsxs23(
2055
2415
  Panel,
2056
2416
  {
2057
2417
  title: copy.delivery,
2058
- actions: /* @__PURE__ */ jsxs16("span", { className: "muted", children: [
2418
+ actions: /* @__PURE__ */ jsxs23("span", { className: "muted", children: [
2059
2419
  data.envName,
2060
2420
  " \xB7 ",
2061
2421
  data.transport,
2062
2422
  data.fromEmail ? ` \xB7 ${data.fromEmail}` : ""
2063
2423
  ] }),
2064
2424
  children: [
2065
- /* @__PURE__ */ jsx19(Field6, { label: copy.notificationAddress, children: /* @__PURE__ */ jsx19(Input2, { value: data.notificationEmail, onInput: (e) => edit({ notificationEmail: e.target.value }) }) }),
2066
- /* @__PURE__ */ jsx19(Field6, { label: copy.replyTo, children: /* @__PURE__ */ jsx19(Input2, { value: data.replyTo, onInput: (e) => edit({ replyTo: e.target.value }) }) }),
2067
- /* @__PURE__ */ jsx19(Field6, { label: copy.debugInbox, hint: copy.debugInboxHint, children: /* @__PURE__ */ jsx19(Input2, { value: data.debugEmail, onInput: (e) => edit({ debugEmail: e.target.value }) }) })
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 }) }) })
2068
2428
  ]
2069
2429
  }
2070
2430
  ),
2071
- Object.entries(data.emailTemplates).map(([key, t]) => /* @__PURE__ */ jsxs16(Panel, { title: key, actions: /* @__PURE__ */ jsx19(Button6, { variant: "secondary", mini: true, disabled: busy === `test:${key}`, onClick: () => void test(key), children: copy.sendTest }), children: [
2072
- /* @__PURE__ */ jsx19(Checkbox2, { label: copy.enabled, checked: t.enabled, onChange: (e) => editTemplate(key, { enabled: e.target.checked }) }),
2073
- /* @__PURE__ */ jsx19(Field6, { label: copy.subject, children: /* @__PURE__ */ jsx19(Input2, { value: t.subject, onInput: (e) => editTemplate(key, { subject: e.target.value }) }) }),
2074
- /* @__PURE__ */ jsx19(Field6, { label: copy.body, children: /* @__PURE__ */ jsx19(Textarea2, { prose: true, rows: 5, value: t.text, onInput: (e) => editTemplate(key, { text: e.target.value }) }) })
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 }) }) })
2075
2435
  ] }, key)),
2076
- /* @__PURE__ */ jsxs16("div", { style: { display: "flex", gap: 12, alignItems: "center" }, children: [
2077
- /* @__PURE__ */ jsx19(Button6, { disabled: !draft || busy === "save", onClick: () => void save(), children: copy.save }),
2078
- note ? /* @__PURE__ */ jsx19("span", { className: "muted", children: note }) : null
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
2079
2439
  ] }),
2080
- /* @__PURE__ */ jsx19(Panel, { title: copy.sendLog, children: /* @__PURE__ */ jsx19(DataTable3, { rows: log.data?.sends ?? [], columns: logColumns(copy), rowKey: (r) => r.id }) })
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 }) })
2081
2441
  ] });
2082
2442
  }
2083
2443
  function emailSection(options = {}) {
2084
2444
  const { id = "email", label = "Email" } = options;
2085
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx19(EmailBody, { ctx }) };
2445
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx25(EmailBody, { ctx }) };
2086
2446
  }
2087
2447
 
2088
2448
  // src/ui/admin-member-content.tsx
2089
- import { useEffect as useEffect9, useState as useState15 } from "preact/hooks";
2090
- import { jsx as jsx20, jsxs as jsxs17 } from "preact/jsx-runtime";
2449
+ import { useEffect as useEffect10, useState as useState20 } from "preact/hooks";
2450
+ import { jsx as jsx26, jsxs as jsxs24 } from "preact/jsx-runtime";
2091
2451
  var emptyDraft = () => ({ pages: [], upsellOverrides: [] });
2092
2452
  function accessLabel(page) {
2093
2453
  return page.audience.kind === "all-members" ? "All members" : `Tiers: ${page.audience.tierIds.join(", ")}`;
@@ -2097,17 +2457,17 @@ function MemberContentAdmin({
2097
2457
  initialData
2098
2458
  }) {
2099
2459
  const resource = useAdminResource(ctx.getToken, "/api/admin/member-content");
2100
- const [draft, setDraft] = useState15(JSON.stringify(initialData?.chapter?.document ?? emptyDraft(), null, 2));
2101
- const [saveError, setSaveError] = useState15(null);
2102
- const [saving, setSaving] = useState15(false);
2103
- useEffect9(() => {
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);
2463
+ useEffect10(() => {
2104
2464
  if (!resource.data) return;
2105
2465
  setDraft(JSON.stringify(resource.data.chapter?.document ?? emptyDraft(), null, 2));
2106
2466
  }, [resource.data]);
2107
2467
  const loaded = initialData ?? resource.data;
2108
- if (!loaded && resource.loading) return /* @__PURE__ */ jsx20(AdminPage, { children: /* @__PURE__ */ jsx20(AdminNote, { children: "Loading member content\u2026" }) });
2468
+ if (!loaded && resource.loading) return /* @__PURE__ */ jsx26(AdminPage, { children: /* @__PURE__ */ jsx26(AdminNote, { children: "Loading member content\u2026" }) });
2109
2469
  if (resource.error || !loaded) {
2110
- return /* @__PURE__ */ jsx20(AdminPage, { children: /* @__PURE__ */ jsxs17(AdminNote, { children: [
2470
+ return /* @__PURE__ */ jsx26(AdminPage, { children: /* @__PURE__ */ jsxs24(AdminNote, { children: [
2111
2471
  "Member content could not be loaded: ",
2112
2472
  resource.error ?? "unknown error"
2113
2473
  ] }) });
@@ -2138,35 +2498,35 @@ function MemberContentAdmin({
2138
2498
  setSaving(false);
2139
2499
  }
2140
2500
  };
2141
- return /* @__PURE__ */ jsxs17(AdminPage, { children: [
2142
- /* @__PURE__ */ jsxs17(Panel, { children: [
2143
- /* @__PURE__ */ jsx20("div", { className: "card-label", children: "Member content" }),
2144
- /* @__PURE__ */ jsx20("h2", { children: "One catalog, two clear owners" }),
2145
- /* @__PURE__ */ jsx20("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." }),
2146
- /* @__PURE__ */ jsxs17("div", { className: "stat-band", children: [
2147
- /* @__PURE__ */ jsxs17("div", { children: [
2148
- /* @__PURE__ */ jsx20("strong", { children: inherited.length }),
2149
- /* @__PURE__ */ jsx20("span", { children: "Inherited pages" })
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" })
2150
2510
  ] }),
2151
- /* @__PURE__ */ jsxs17("div", { children: [
2152
- /* @__PURE__ */ jsx20("strong", { children: local.length }),
2153
- /* @__PURE__ */ jsx20("span", { children: "Chapter pages" })
2511
+ /* @__PURE__ */ jsxs24("div", { children: [
2512
+ /* @__PURE__ */ jsx26("strong", { children: local.length }),
2513
+ /* @__PURE__ */ jsx26("span", { children: "Chapter pages" })
2154
2514
  ] }),
2155
- /* @__PURE__ */ jsxs17("div", { children: [
2156
- /* @__PURE__ */ jsx20("strong", { children: data.tiers.length }),
2157
- /* @__PURE__ */ jsx20("span", { children: "Declared tiers" })
2515
+ /* @__PURE__ */ jsxs24("div", { children: [
2516
+ /* @__PURE__ */ jsx26("strong", { children: data.tiers.length }),
2517
+ /* @__PURE__ */ jsx26("span", { children: "Declared tiers" })
2158
2518
  ] })
2159
2519
  ] })
2160
2520
  ] }),
2161
- /* @__PURE__ */ jsxs17(Panel, { children: [
2162
- /* @__PURE__ */ jsx20("div", { className: "card-label", children: "Inherited \xB7 read only" }),
2163
- /* @__PURE__ */ jsxs17("h2", { children: [
2521
+ /* @__PURE__ */ jsxs24(Panel, { children: [
2522
+ /* @__PURE__ */ jsx26("div", { className: "card-label", children: "Inherited \xB7 read only" }),
2523
+ /* @__PURE__ */ jsxs24("h2", { children: [
2164
2524
  "Parent pages ",
2165
2525
  data.parent ? `\xB7 revision ${data.parent.revision}` : ""
2166
2526
  ] }),
2167
- inherited.length === 0 ? /* @__PURE__ */ jsx20(AdminNote, { children: "No Parent pages have been delivered." }) : /* @__PURE__ */ jsx20("div", { className: "data-list", "data-member-content-inherited": true, children: inherited.map((page) => /* @__PURE__ */ jsxs17("article", { className: "card", children: [
2168
- /* @__PURE__ */ jsx20("strong", { children: page.title }),
2169
- /* @__PURE__ */ jsxs17("div", { className: "meeting-note", children: [
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: [
2170
2530
  "/",
2171
2531
  page.slug,
2172
2532
  " \xB7 ",
@@ -2174,22 +2534,22 @@ function MemberContentAdmin({
2174
2534
  " \xB7 ",
2175
2535
  accessLabel(page)
2176
2536
  ] }),
2177
- /* @__PURE__ */ jsxs17("div", { className: "meeting-note", children: [
2537
+ /* @__PURE__ */ jsxs24("div", { className: "meeting-note", children: [
2178
2538
  "Upsell: ",
2179
2539
  page.upsell ? `${page.upsell.owner} controlled` : "none"
2180
2540
  ] })
2181
2541
  ] }, page.id)) })
2182
2542
  ] }),
2183
- /* @__PURE__ */ jsxs17(Panel, { children: [
2184
- /* @__PURE__ */ jsx20("div", { className: "card-label", children: "Chapter \xB7 editable" }),
2185
- /* @__PURE__ */ jsxs17("h2", { children: [
2543
+ /* @__PURE__ */ jsxs24(Panel, { children: [
2544
+ /* @__PURE__ */ jsx26("div", { className: "card-label", children: "Chapter \xB7 editable" }),
2545
+ /* @__PURE__ */ jsxs24("h2", { children: [
2186
2546
  "Local document \xB7 revision ",
2187
2547
  data.chapter?.revision ?? 0
2188
2548
  ] }),
2189
- /* @__PURE__ */ jsx20("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." }),
2190
- /* @__PURE__ */ jsxs17("label", { className: "field", children: [
2191
- /* @__PURE__ */ jsx20("span", { children: "Pages and delegated upsells (JSON)" }),
2192
- /* @__PURE__ */ jsx20(
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(
2193
2553
  "textarea",
2194
2554
  {
2195
2555
  rows: 24,
@@ -2200,12 +2560,12 @@ function MemberContentAdmin({
2200
2560
  }
2201
2561
  )
2202
2562
  ] }),
2203
- saveError ? /* @__PURE__ */ jsxs17("div", { className: "notice danger", role: "alert", children: [
2204
- /* @__PURE__ */ jsx20("strong", { children: "Fix these items before saving:" }),
2205
- /* @__PURE__ */ jsx20("ul", { children: saveError.map((error) => /* @__PURE__ */ jsx20("li", { children: error }, error)) })
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)) })
2206
2566
  ] }) : null,
2207
- /* @__PURE__ */ jsx20("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring || saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save chapter content" }),
2208
- !data.localAuthoring ? /* @__PURE__ */ jsx20(AdminNote, { children: "Local authoring is disabled in the checked-in Chapter config." }) : 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
2209
2569
  ] })
2210
2570
  ] });
2211
2571
  }
@@ -2213,12 +2573,12 @@ function memberContentSection() {
2213
2573
  return {
2214
2574
  id: "member-content",
2215
2575
  label: "Member content",
2216
- render: (ctx) => /* @__PURE__ */ jsx20(MemberContentAdmin, { ctx })
2576
+ render: (ctx) => /* @__PURE__ */ jsx26(MemberContentAdmin, { ctx })
2217
2577
  };
2218
2578
  }
2219
2579
 
2220
2580
  // src/ui/admin-settings-workspace.tsx
2221
- import { jsx as jsx21 } from "preact/jsx-runtime";
2581
+ import { jsx as jsx27 } from "preact/jsx-runtime";
2222
2582
  var viewContext = (ctx, viewId, active) => {
2223
2583
  const route = { workspaceId: ctx.route.workspaceId, viewId, ...active && ctx.route.recordId ? { recordId: ctx.route.recordId } : {}, ...active && ctx.route.detailTab ? { detailTab: ctx.route.detailTab } : {} };
2224
2584
  const targetFromView = (target) => {
@@ -2236,7 +2596,7 @@ function SettingsWorkspace({ chapter, ctx }) {
2236
2596
  const email = emailSection({ label: copy.workspaces.email });
2237
2597
  const content = memberContentSection();
2238
2598
  const library = builderLibrarySection();
2239
- return /* @__PURE__ */ jsx21(Tabs2, { ariaLabel: copy.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
2599
+ return /* @__PURE__ */ jsx27(Tabs2, { ariaLabel: copy.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
2240
2600
  { value: "calendar", label: copy.workspaces.calendar, href: ctx.href({ viewId: "calendar", recordId: null, detailTab: null }), panel: calendar.render(viewContext(ctx, "calendar", active === "calendar")) },
2241
2601
  { value: "email", label: copy.workspaces.email, href: ctx.href({ viewId: "email", recordId: null, detailTab: null }), panel: email.render(viewContext(ctx, "email", active === "email")) },
2242
2602
  ...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")) }] : [],
@@ -2247,14 +2607,14 @@ function LeaderSettingsWorkspace({ chapter, ctx }) {
2247
2607
  const email = emailSection({ label: chapter.copy.admin.workspaces.email });
2248
2608
  const library = builderLibrarySection();
2249
2609
  const active = ctx.route.viewId === "builder-library" && chapter.builderLibrary ? "builder-library" : "email";
2250
- return /* @__PURE__ */ jsx21(Tabs2, { ariaLabel: chapter.copy.admin.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
2610
+ return /* @__PURE__ */ jsx27(Tabs2, { ariaLabel: chapter.copy.admin.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
2251
2611
  { 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")) },
2252
2612
  ...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")) }] : []
2253
2613
  ] });
2254
2614
  }
2255
2615
 
2256
2616
  // src/ui/admin-workspaces.tsx
2257
- import { jsx as jsx22 } from "preact/jsx-runtime";
2617
+ import { jsx as jsx28 } from "preact/jsx-runtime";
2258
2618
  var adminViewContext = (ctx, viewId, active) => {
2259
2619
  const route = {
2260
2620
  workspaceId: ctx.route.workspaceId,
@@ -2280,7 +2640,7 @@ function DashboardWorkspace({ chapter, ctx }) {
2280
2640
  const active = ctx.route.viewId === "billing" ? "billing" : "overview";
2281
2641
  const overview = dashboardSection({ id: "overview", label: copy.workspaces.overview });
2282
2642
  const billing = billingSection({ label: copy.workspaces.billing });
2283
- return /* @__PURE__ */ jsx22(
2643
+ return /* @__PURE__ */ jsx28(
2284
2644
  Tabs3,
2285
2645
  {
2286
2646
  ariaLabel: copy.workspaces.dashboardViewsLabel,
@@ -2308,7 +2668,7 @@ function PeopleWorkspace({ chapter, ctx }) {
2308
2668
  const fallback = types[0]?.[0] ?? "person";
2309
2669
  const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
2310
2670
  const networkSharing = chapter.network.targets.length > 0;
2311
- return /* @__PURE__ */ jsx22(
2671
+ return /* @__PURE__ */ jsx28(
2312
2672
  Tabs3,
2313
2673
  {
2314
2674
  ariaLabel: chapter.copy.admin.workspaces.collectionsLabel,
@@ -2338,8 +2698,8 @@ function PortfolioWorkspace({ chapter, ctx }) {
2338
2698
  const types = Object.entries(chapter.crm.config.types).filter(([, def]) => def.workspace === "portfolio");
2339
2699
  const fallback = types[0]?.[0] ?? "";
2340
2700
  const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
2341
- if (!active) return /* @__PURE__ */ jsx22(LeaderNetworkOverview, { ctx });
2342
- return /* @__PURE__ */ jsx22(
2701
+ if (!active) return /* @__PURE__ */ jsx28(LeaderNetworkOverview, { ctx });
2702
+ return /* @__PURE__ */ jsx28(
2343
2703
  Tabs3,
2344
2704
  {
2345
2705
  ariaLabel: copy.workspaces.portfolioViewsLabel,
@@ -2363,7 +2723,7 @@ function PortfolioWorkspace({ chapter, ctx }) {
2363
2723
  );
2364
2724
  }
2365
2725
  function LeaderDashboardWorkspace({ chapter, ctx }) {
2366
- return /* @__PURE__ */ jsx22(
2726
+ return /* @__PURE__ */ jsx28(
2367
2727
  Tabs3,
2368
2728
  {
2369
2729
  ariaLabel: chapter.copy.admin.workspaces.dashboardViewsLabel,
@@ -2373,7 +2733,7 @@ function LeaderDashboardWorkspace({ chapter, ctx }) {
2373
2733
  value: "overview",
2374
2734
  label: chapter.copy.admin.workspaces.overview,
2375
2735
  href: ctx.href({ viewId: "overview", recordId: null, detailTab: null }),
2376
- panel: /* @__PURE__ */ jsx22(LeaderNetworkOverview, { ctx: adminViewContext(ctx, "overview", true) })
2736
+ panel: /* @__PURE__ */ jsx28(LeaderNetworkOverview, { ctx: adminViewContext(ctx, "overview", true) })
2377
2737
  }]
2378
2738
  }
2379
2739
  );
@@ -2384,7 +2744,7 @@ function defaultAdminWorkspaces(chapter) {
2384
2744
  id: "people",
2385
2745
  label: copy.workspaces.people,
2386
2746
  defaultViewId: Object.keys(chapter.crm.config.types)[0] ?? "person",
2387
- render: (ctx) => /* @__PURE__ */ jsx22(PeopleWorkspace, { chapter, ctx })
2747
+ render: (ctx) => /* @__PURE__ */ jsx28(PeopleWorkspace, { chapter, ctx })
2388
2748
  };
2389
2749
  if (chapter.mode === "hub" && chapter.network.targets.length === 0) return [people];
2390
2750
  if (chapter.mode === "hub") {
@@ -2394,7 +2754,7 @@ function defaultAdminWorkspaces(chapter) {
2394
2754
  id: "dashboard",
2395
2755
  label: copy.workspaces.dashboard,
2396
2756
  defaultViewId: "overview",
2397
- render: (ctx) => /* @__PURE__ */ jsx22(LeaderDashboardWorkspace, { chapter, ctx })
2757
+ render: (ctx) => /* @__PURE__ */ jsx28(LeaderDashboardWorkspace, { chapter, ctx })
2398
2758
  },
2399
2759
  networkRecordsWorkspace(chapter),
2400
2760
  people,
@@ -2402,13 +2762,13 @@ function defaultAdminWorkspaces(chapter) {
2402
2762
  id: "portfolio",
2403
2763
  label: copy.workspaces.portfolio,
2404
2764
  defaultViewId: portfolioTypes[0]?.[0],
2405
- render: (ctx) => /* @__PURE__ */ jsx22(PortfolioWorkspace, { chapter, ctx })
2765
+ render: (ctx) => /* @__PURE__ */ jsx28(PortfolioWorkspace, { chapter, ctx })
2406
2766
  },
2407
2767
  {
2408
2768
  id: "settings",
2409
2769
  label: copy.workspaces.settings,
2410
2770
  defaultViewId: "email",
2411
- render: (ctx) => /* @__PURE__ */ jsx22(LeaderSettingsWorkspace, { chapter, ctx })
2771
+ render: (ctx) => /* @__PURE__ */ jsx28(LeaderSettingsWorkspace, { chapter, ctx })
2412
2772
  }
2413
2773
  ];
2414
2774
  }
@@ -2417,7 +2777,7 @@ function defaultAdminWorkspaces(chapter) {
2417
2777
  id: "dashboard",
2418
2778
  label: copy.workspaces.dashboard,
2419
2779
  defaultViewId: "overview",
2420
- render: (ctx) => /* @__PURE__ */ jsx22(DashboardWorkspace, { chapter, ctx })
2780
+ render: (ctx) => /* @__PURE__ */ jsx28(DashboardWorkspace, { chapter, ctx })
2421
2781
  },
2422
2782
  people,
2423
2783
  admissionGrantsWorkspace(copy.workspaces.admission),
@@ -2425,17 +2785,17 @@ function defaultAdminWorkspaces(chapter) {
2425
2785
  id: "settings",
2426
2786
  label: copy.workspaces.settings,
2427
2787
  defaultViewId: "calendar",
2428
- render: (ctx) => /* @__PURE__ */ jsx22(SettingsWorkspace, { chapter, ctx })
2788
+ render: (ctx) => /* @__PURE__ */ jsx28(SettingsWorkspace, { chapter, ctx })
2429
2789
  }
2430
2790
  ];
2431
2791
  }
2432
2792
 
2433
2793
  // src/ui/admin-frame.tsx
2434
2794
  import { ThemeScope as ThemeScope2 } from "@odla-ai/ui/components";
2435
- import { jsx as jsx23, jsxs as jsxs18 } from "preact/jsx-runtime";
2795
+ import { jsx as jsx29, jsxs as jsxs25 } from "preact/jsx-runtime";
2436
2796
  function AdminTheme(props) {
2437
2797
  const brand = props.chapter?.brand;
2438
- return /* @__PURE__ */ jsx23(ChapterCopyProvider, { copy: props.chapter?.copy, children: /* @__PURE__ */ jsxs18(
2798
+ return /* @__PURE__ */ jsx29(ChapterCopyProvider, { copy: props.chapter?.copy, children: /* @__PURE__ */ jsxs25(
2439
2799
  ThemeScope2,
2440
2800
  {
2441
2801
  ref: props.scopeRef,
@@ -2444,7 +2804,7 @@ function AdminTheme(props) {
2444
2804
  accent: brand?.accent,
2445
2805
  colorScheme: brand?.colorScheme ?? "light",
2446
2806
  children: [
2447
- /* @__PURE__ */ jsx23(BrandStyle, { brand, selector: "[data-chapter-admin]" }),
2807
+ /* @__PURE__ */ jsx29(BrandStyle, { brand, selector: "[data-chapter-admin]" }),
2448
2808
  props.children
2449
2809
  ]
2450
2810
  }
@@ -2464,11 +2824,11 @@ function signInRedirect(basePath, workspaces) {
2464
2824
  }
2465
2825
 
2466
2826
  // src/ui/admin-appearance.ts
2467
- import { useEffect as useEffect10, useState as useState16 } from "preact/hooks";
2827
+ import { useEffect as useEffect11, useState as useState21 } from "preact/hooks";
2468
2828
  import { clerkAppearanceFromTokens } from "@odla-ai/auth-clerk";
2469
2829
  function useScopedClerkAppearance(scope) {
2470
- const [appearance, setAppearance] = useState16();
2471
- useEffect10(() => {
2830
+ const [appearance, setAppearance] = useState21();
2831
+ useEffect11(() => {
2472
2832
  setAppearance(clerkAppearanceFromTokens(scope.current ?? void 0));
2473
2833
  }, [scope]);
2474
2834
  return appearance;
@@ -2499,7 +2859,7 @@ async function loadChapterAdminUser(adapter, apiBase, getToken) {
2499
2859
  }
2500
2860
 
2501
2861
  // src/ui/admin.tsx
2502
- import { jsx as jsx24, jsxs as jsxs19 } from "preact/jsx-runtime";
2862
+ import { jsx as jsx30, jsxs as jsxs26 } from "preact/jsx-runtime";
2503
2863
  function Authed(props) {
2504
2864
  const copy = useChapterCopy().admin;
2505
2865
  const {
@@ -2513,7 +2873,8 @@ function Authed(props) {
2513
2873
  auth,
2514
2874
  renderHeader,
2515
2875
  renderAccountMenu,
2516
- renderWorkspaceNav
2876
+ renderWorkspaceNav,
2877
+ renderWorkspaceFrame
2517
2878
  } = props;
2518
2879
  const { getToken, signOut } = useClerkAuth();
2519
2880
  const client = useMemo3(
@@ -2526,8 +2887,8 @@ function Authed(props) {
2526
2887
  }),
2527
2888
  [getToken, crmBasePath]
2528
2889
  );
2529
- const [state, setState] = useState17({ status: "checking" });
2530
- useEffect11(() => {
2890
+ const [state, setState] = useState22({ status: "checking" });
2891
+ useEffect12(() => {
2531
2892
  let live = true;
2532
2893
  void (async () => {
2533
2894
  try {
@@ -2546,17 +2907,17 @@ function Authed(props) {
2546
2907
  live = false;
2547
2908
  };
2548
2909
  }, [getToken, apiBase, auth]);
2549
- if (state.status === "checking") return /* @__PURE__ */ jsx24(Gate, { brand, children: /* @__PURE__ */ jsx24("p", { style: S.muted, children: copy.auth.checking }) });
2910
+ if (state.status === "checking") return /* @__PURE__ */ jsx30(Gate, { brand, children: /* @__PURE__ */ jsx30("p", { style: S.muted, children: copy.auth.checking }) });
2550
2911
  if (state.status === "denied") {
2551
- return /* @__PURE__ */ jsx24(Gate, { brand, children: /* @__PURE__ */ jsxs19("div", { className: "card", style: S.card, children: [
2552
- /* @__PURE__ */ jsx24("h2", { style: { marginTop: 0 }, children: copy.auth.notAuthorized }),
2553
- /* @__PURE__ */ jsx24("p", { style: S.muted, children: formatChapterCopy(copy.auth.accountNotAuthorized, {
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, {
2554
2915
  account: state.email ?? copy.auth.thisAccount
2555
2916
  }) }),
2556
- /* @__PURE__ */ jsx24("button", { className: "btn secondary", onClick: () => signOut(), children: copy.auth.signOut })
2917
+ /* @__PURE__ */ jsx30("button", { className: "btn secondary", onClick: () => signOut(), children: copy.auth.signOut })
2557
2918
  ] }) });
2558
2919
  }
2559
- return /* @__PURE__ */ jsx24(
2920
+ return /* @__PURE__ */ jsx30(
2560
2921
  AdminShell,
2561
2922
  {
2562
2923
  workspaces,
@@ -2571,7 +2932,8 @@ function Authed(props) {
2571
2932
  chrome,
2572
2933
  renderHeader,
2573
2934
  renderAccountMenu,
2574
- renderWorkspaceNav
2935
+ renderWorkspaceNav,
2936
+ renderWorkspaceFrame
2575
2937
  }
2576
2938
  );
2577
2939
  }
@@ -2597,10 +2959,10 @@ function ChapterAdmin(props) {
2597
2959
  const chrome = props.chrome ?? "embedded";
2598
2960
  const auth = props.auth ?? DEFAULT_ADMIN_AUTH;
2599
2961
  const redirect = signInRedirect(basePath, workspaces);
2600
- const [publishableKey, setPublishableKey] = useState17(void 0);
2601
- const scopeRef = useRef(null);
2962
+ const [publishableKey, setPublishableKey] = useState22(void 0);
2963
+ const scopeRef = useRef3(null);
2602
2964
  const appearance = useScopedClerkAppearance(scopeRef);
2603
- useEffect11(() => {
2965
+ useEffect12(() => {
2604
2966
  let live = true;
2605
2967
  void loadChapterAdminConfig(auth, apiBase).then((config) => live && setPublishableKey(config.publishableKey ?? null)).catch(() => live && setPublishableKey(null));
2606
2968
  return () => {
@@ -2609,23 +2971,23 @@ function ChapterAdmin(props) {
2609
2971
  }, [apiBase, auth]);
2610
2972
  let content;
2611
2973
  if (publishableKey === void 0 || publishableKey && !appearance) {
2612
- content = /* @__PURE__ */ jsx24(Gate, { brand, children: /* @__PURE__ */ jsx24("p", { style: S.muted, children: copy.admin.auth.loading }) });
2974
+ content = /* @__PURE__ */ jsx30(Gate, { brand, children: /* @__PURE__ */ jsx30("p", { style: S.muted, children: copy.admin.auth.loading }) });
2613
2975
  } else if (!publishableKey) {
2614
- content = /* @__PURE__ */ jsx24(Gate, { brand, children: /* @__PURE__ */ jsxs19("div", { className: "card", style: S.card, children: [
2615
- /* @__PURE__ */ jsx24("h2", { style: { marginTop: 0 }, children: copy.admin.auth.signInNotConfigured }),
2616
- /* @__PURE__ */ jsx24("p", { style: S.muted, children: copy.admin.auth.missingPublishableKey })
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 })
2617
2979
  ] }) });
2618
2980
  } else if (workspaces.length === 0) {
2619
- content = /* @__PURE__ */ jsx24(Gate, { brand, children: /* @__PURE__ */ jsx24("p", { style: S.muted, children: copy.admin.auth.noWorkspaces }) });
2981
+ content = /* @__PURE__ */ jsx30(Gate, { brand, children: /* @__PURE__ */ jsx30("p", { style: S.muted, children: copy.admin.auth.noWorkspaces }) });
2620
2982
  } else {
2621
- content = /* @__PURE__ */ jsxs19(
2983
+ content = /* @__PURE__ */ jsxs26(
2622
2984
  ClerkGate,
2623
2985
  {
2624
2986
  publishableKey,
2625
2987
  appearance,
2626
2988
  afterSignOutUrl: "/",
2627
2989
  children: [
2628
- /* @__PURE__ */ jsx24(SignedOut, { children: /* @__PURE__ */ jsx24(Gate, { brand, tagline: copy.admin.auth.signInTagline, children: /* @__PURE__ */ jsx24(
2990
+ /* @__PURE__ */ jsx30(SignedOut, { children: /* @__PURE__ */ jsx30(Gate, { brand, tagline: copy.admin.auth.signInTagline, children: /* @__PURE__ */ jsx30(
2629
2991
  SignIn,
2630
2992
  {
2631
2993
  routing: "hash",
@@ -2633,7 +2995,7 @@ function ChapterAdmin(props) {
2633
2995
  signUpForceRedirectUrl: redirect
2634
2996
  }
2635
2997
  ) }) }),
2636
- /* @__PURE__ */ jsx24(SignedIn, { children: /* @__PURE__ */ jsx24(
2998
+ /* @__PURE__ */ jsx30(SignedIn, { children: /* @__PURE__ */ jsx30(
2637
2999
  Authed,
2638
3000
  {
2639
3001
  workspaces,
@@ -2646,14 +3008,15 @@ function ChapterAdmin(props) {
2646
3008
  auth,
2647
3009
  renderHeader: props.renderHeader,
2648
3010
  renderAccountMenu: props.renderAccountMenu,
2649
- renderWorkspaceNav: props.renderWorkspaceNav
3011
+ renderWorkspaceNav: props.renderWorkspaceNav,
3012
+ renderWorkspaceFrame: props.renderWorkspaceFrame
2650
3013
  }
2651
3014
  ) })
2652
3015
  ]
2653
3016
  }
2654
3017
  );
2655
3018
  }
2656
- return /* @__PURE__ */ jsx24(AdminTheme, { chapter: props.chapter, scopeRef, children: content });
3019
+ return /* @__PURE__ */ jsx30(AdminTheme, { chapter: props.chapter, scopeRef, children: content });
2657
3020
  }
2658
3021
 
2659
3022
  // src/ui/admin-defaults.ts
@@ -2662,17 +3025,17 @@ function defaultAdminSections(chapter) {
2662
3025
  }
2663
3026
 
2664
3027
  // src/ui/admin-meetings.tsx
2665
- import { useState as useState18 } from "preact/hooks";
2666
- import { Button as Button7 } from "@odla-ai/ui/components";
2667
- import { Fragment as Fragment4, jsx as jsx25, jsxs as jsxs20 } from "preact/jsx-runtime";
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";
2668
3031
  var when2 = (t) => new Date(t).toLocaleString([], { dateStyle: "medium", timeStyle: "short" });
2669
3032
  function MeetingsBody({ ctx }) {
2670
3033
  const copy = useChapterCopy().admin.meetings;
2671
3034
  const { data, loading, error, refresh } = useAdminResource(ctx.getToken, "/api/admin/meetings?all=1");
2672
- const [busy, setBusy] = useState18(null);
2673
- const [note, setNote] = useState18(null);
2674
- if (loading) return /* @__PURE__ */ jsx25(AdminNote, { children: copy.loading });
2675
- if (error || !data) return /* @__PURE__ */ jsxs20(AdminNote, { children: [
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: [
2676
3039
  copy.loadFailed,
2677
3040
  error ? `: ${error}` : "",
2678
3041
  "."
@@ -2703,32 +3066,121 @@ function MeetingsBody({ ctx }) {
2703
3066
  }
2704
3067
  void run(id, () => adminFetch(ctx.getToken, `/api/admin/meetings/${id}/reschedule`, { method: "POST", body: JSON.stringify({ startAt }) }));
2705
3068
  };
2706
- return /* @__PURE__ */ jsx25(AdminPage, { children: /* @__PURE__ */ jsx25(Panel, { title: /* @__PURE__ */ jsxs20(Fragment4, { children: [
3069
+ return /* @__PURE__ */ jsx31(AdminPage, { children: /* @__PURE__ */ jsx31(Panel, { title: /* @__PURE__ */ jsxs27(Fragment8, { children: [
2707
3070
  copy.agenda,
2708
3071
  " ",
2709
- /* @__PURE__ */ jsxs20("span", { className: "muted", style: { fontWeight: 400 }, children: [
3072
+ /* @__PURE__ */ jsxs27("span", { className: "muted", style: { fontWeight: 400 }, children: [
2710
3073
  "\xB7 ",
2711
3074
  data.timezone
2712
3075
  ] })
2713
- ] }), actions: note ? /* @__PURE__ */ jsx25("span", { className: "muted", children: note }) : void 0, children: data.meetings.length === 0 ? /* @__PURE__ */ jsx25("p", { className: "muted", style: { margin: 0 }, children: copy.empty }) : /* @__PURE__ */ jsx25("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 12 }, children: data.meetings.map((m) => /* @__PURE__ */ jsxs20("li", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap", opacity: m.status === "cancelled" ? 0.55 : 1 }, children: [
2714
- /* @__PURE__ */ jsx25("strong", { style: { minWidth: 170 }, children: when2(m.startAt) }),
2715
- /* @__PURE__ */ jsx25("span", { style: { flex: 1 }, children: m.applicant ? `${m.applicant.name} \xB7 ${m.applicant.email}` : copy.unknown }),
2716
- /* @__PURE__ */ jsx25("span", { className: "badge", children: m.status }),
2717
- m.drift && m.drift !== "none" ? /* @__PURE__ */ jsxs20("span", { className: "badge", children: [
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: [
2718
3081
  copy.drift,
2719
3082
  ": ",
2720
3083
  m.drift
2721
3084
  ] }) : null,
2722
- m.meetUrl ? /* @__PURE__ */ jsx25("a", { href: m.meetUrl, target: "_blank", rel: "noreferrer", children: copy.meet }) : null,
2723
- m.status === "scheduled" ? /* @__PURE__ */ jsxs20(Fragment4, { children: [
2724
- /* @__PURE__ */ jsx25(Button7, { variant: "secondary", mini: true, disabled: busy === m.id, onClick: () => reschedule(m.id), children: copy.reschedule }),
2725
- /* @__PURE__ */ jsx25(Button7, { variant: "danger", mini: true, disabled: busy === m.id, onClick: () => cancel(m.id), children: copy.cancel })
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 })
2726
3089
  ] }) : null
2727
3090
  ] }, m.id)) }) }) });
2728
3091
  }
2729
3092
  function meetingsSection(options = {}) {
2730
3093
  const { id = "meetings", label = "Meetings" } = options;
2731
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx25(MeetingsBody, { ctx }) };
3094
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx31(MeetingsBody, { ctx }) };
3095
+ }
3096
+
3097
+ // 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";
3101
+ function NetworkRecordEditor(props) {
3102
+ const { ctx, record } = props;
3103
+ const [stage, setStage] = useState24("");
3104
+ const [busy, setBusy] = useState24(false);
3105
+ const [error, setError] = useState24(null);
3106
+ const attempt = useRef4(null);
3107
+ const pending = record.edit?.pendingAction;
3108
+ const superAdmin = ctx.currentUser?.superAdmin === true;
3109
+ const ownPending = !pending || pending.actorId === ctx.currentUser?.userId || pending.actorId === ctx.currentUser?.id || Boolean(pending.actorEmail && pending.actorEmail === ctx.currentUser?.email);
3110
+ const mutate = async (change, mutationId, retry = false) => {
3111
+ await adminFetch(ctx.getToken, "/api/admin/network/records", { method: "PATCH", body: JSON.stringify({
3112
+ targetId: props.targetId,
3113
+ type: record.type,
3114
+ recordId: record.id,
3115
+ expectedRevision: retry && pending ? pending.expectedRevision : record.revision,
3116
+ expectedStage: retry && pending ? pending.expectedStage : record.stage ?? null,
3117
+ mutationId,
3118
+ ...change
3119
+ }) });
3120
+ props.onChanged();
3121
+ };
3122
+ const move = async () => {
3123
+ setBusy(true);
3124
+ setError(null);
3125
+ try {
3126
+ const destination = pending?.stage ?? stage;
3127
+ if (attempt.current?.stage !== destination) attempt.current = { stage: destination, id: crypto.randomUUID() };
3128
+ await mutate({ stage: destination }, pending?.mutationId ?? attempt.current.id, Boolean(pending));
3129
+ attempt.current = null;
3130
+ setStage("");
3131
+ } catch (cause) {
3132
+ setError(cause instanceof Error ? cause.message : "Action could not be completed.");
3133
+ props.onChanged();
3134
+ } finally {
3135
+ setBusy(false);
3136
+ }
3137
+ };
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(
3143
+ OperationalProfileForm,
3144
+ {
3145
+ fields: record.edit.fields,
3146
+ values: record.fields,
3147
+ onSave: (fields, id) => mutate({ fields }, id)
3148
+ },
3149
+ `${record.id}:${record.revision}`
3150
+ )
3151
+ ] }),
3152
+ /* @__PURE__ */ jsxs28("section", { style: { display: "grid", gap: 12 }, children: [
3153
+ /* @__PURE__ */ jsx32("h3", { children: "Membership actions" }),
3154
+ pending ? /* @__PURE__ */ jsxs28("p", { children: [
3155
+ "An application action is pending: ",
3156
+ pending.stage.replaceAll("_", " "),
3157
+ ". ",
3158
+ 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
3165
+ ] })
3166
+ ] }) : 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 })
3171
+ ] }) : null,
3172
+ /* @__PURE__ */ jsx32(
3173
+ NetworkRecordDetail,
3174
+ {
3175
+ ctx,
3176
+ targetId: props.targetId,
3177
+ targetName: props.targetName,
3178
+ leaderName: props.leaderName,
3179
+ record,
3180
+ sharedEnabled: superAdmin && props.sharedNotes === true
3181
+ }
3182
+ )
3183
+ ] });
2732
3184
  }
2733
3185
 
2734
3186
  export {
@@ -2766,6 +3218,7 @@ export {
2766
3218
  loadChapterAdminUser,
2767
3219
  ChapterAdmin,
2768
3220
  defaultAdminSections,
2769
- meetingsSection
3221
+ meetingsSection,
3222
+ NetworkRecordEditor
2770
3223
  };
2771
- //# sourceMappingURL=chunk-7MEVZEL2.js.map
3224
+ //# sourceMappingURL=chunk-MQ4OPZCS.js.map