@odla-ai/chapter 0.49.0 → 0.51.0

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