@odla-ai/chapter 0.36.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-IAWBE5PX.js";
8
8
 
9
9
  // src/ui/admin.tsx
10
- import { useEffect as useEffect9, useMemo as useMemo2, useRef, useState as useState15 } from "preact/hooks";
10
+ import { useEffect as useEffect10, useMemo as useMemo2, useRef, useState as useState16 } 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
 
@@ -453,7 +453,13 @@ async function adminFetch(getToken, path, init) {
453
453
  if (init?.body) headers.set("content-type", "application/json");
454
454
  const res = await fetch(path, { ...init, headers });
455
455
  const body = await res.json().catch(() => ({}));
456
- if (!res.ok) throw new Error(typeof body.error === "string" ? body.error : `request failed (${res.status})`);
456
+ if (!res.ok) {
457
+ const error = new Error(typeof body.error === "string" ? body.error : `request failed (${res.status})`);
458
+ if (Array.isArray(body.errors) && body.errors.every((item) => typeof item === "string")) {
459
+ error.errors = body.errors;
460
+ }
461
+ throw error;
462
+ }
457
463
  return body;
458
464
  }
459
465
  function useAdminResource(getToken, path) {
@@ -1765,8 +1771,140 @@ function admissionGrantsWorkspace(label = "Admission") {
1765
1771
  };
1766
1772
  }
1767
1773
 
1774
+ // src/ui/admin-member-content.tsx
1775
+ import { useEffect as useEffect8, useState as useState14 } from "preact/hooks";
1776
+ import { jsx as jsx19, jsxs as jsxs16 } from "preact/jsx-runtime";
1777
+ var emptyDraft = () => ({ pages: [], upsellOverrides: [] });
1778
+ function accessLabel(page) {
1779
+ return page.audience.kind === "all-members" ? "All members" : `Tiers: ${page.audience.tierIds.join(", ")}`;
1780
+ }
1781
+ function MemberContentAdmin({
1782
+ ctx,
1783
+ initialData
1784
+ }) {
1785
+ const resource = useAdminResource(ctx.getToken, "/api/admin/member-content");
1786
+ const [draft, setDraft] = useState14(JSON.stringify(initialData?.chapter?.document ?? emptyDraft(), null, 2));
1787
+ const [saveError, setSaveError] = useState14(null);
1788
+ const [saving, setSaving] = useState14(false);
1789
+ useEffect8(() => {
1790
+ if (!resource.data) return;
1791
+ setDraft(JSON.stringify(resource.data.chapter?.document ?? emptyDraft(), null, 2));
1792
+ }, [resource.data]);
1793
+ const loaded = initialData ?? resource.data;
1794
+ if (!loaded && resource.loading) return /* @__PURE__ */ jsx19(AdminPage, { children: /* @__PURE__ */ jsx19(AdminNote, { children: "Loading member content\u2026" }) });
1795
+ if (resource.error || !loaded) {
1796
+ return /* @__PURE__ */ jsx19(AdminPage, { children: /* @__PURE__ */ jsxs16(AdminNote, { children: [
1797
+ "Member content could not be loaded: ",
1798
+ resource.error ?? "unknown error"
1799
+ ] }) });
1800
+ }
1801
+ const data = loaded;
1802
+ const inherited = data.parent?.document.pages ?? [];
1803
+ const local = data.chapter?.document.pages ?? [];
1804
+ const save = async () => {
1805
+ setSaveError(null);
1806
+ let document2;
1807
+ try {
1808
+ document2 = JSON.parse(draft);
1809
+ } catch (error) {
1810
+ setSaveError([`JSON is invalid: ${error instanceof Error ? error.message : String(error)}`]);
1811
+ return;
1812
+ }
1813
+ setSaving(true);
1814
+ try {
1815
+ await adminFetch(ctx.getToken, "/api/admin/member-content", {
1816
+ method: "PUT",
1817
+ body: JSON.stringify({ expectedRevision: data.chapter?.revision ?? 0, document: document2 })
1818
+ });
1819
+ resource.refresh();
1820
+ } catch (error) {
1821
+ const structured = error;
1822
+ setSaveError(structured.errors ?? [error instanceof Error ? error.message : String(error)]);
1823
+ } finally {
1824
+ setSaving(false);
1825
+ }
1826
+ };
1827
+ return /* @__PURE__ */ jsxs16(AdminPage, { children: [
1828
+ /* @__PURE__ */ jsxs16(Panel, { children: [
1829
+ /* @__PURE__ */ jsx19("div", { className: "card-label", children: "Member content" }),
1830
+ /* @__PURE__ */ jsx19("h2", { children: "One catalog, two clear owners" }),
1831
+ /* @__PURE__ */ jsx19("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." }),
1832
+ /* @__PURE__ */ jsxs16("div", { className: "stat-band", children: [
1833
+ /* @__PURE__ */ jsxs16("div", { children: [
1834
+ /* @__PURE__ */ jsx19("strong", { children: inherited.length }),
1835
+ /* @__PURE__ */ jsx19("span", { children: "Inherited pages" })
1836
+ ] }),
1837
+ /* @__PURE__ */ jsxs16("div", { children: [
1838
+ /* @__PURE__ */ jsx19("strong", { children: local.length }),
1839
+ /* @__PURE__ */ jsx19("span", { children: "Chapter pages" })
1840
+ ] }),
1841
+ /* @__PURE__ */ jsxs16("div", { children: [
1842
+ /* @__PURE__ */ jsx19("strong", { children: data.tiers.length }),
1843
+ /* @__PURE__ */ jsx19("span", { children: "Declared tiers" })
1844
+ ] })
1845
+ ] })
1846
+ ] }),
1847
+ /* @__PURE__ */ jsxs16(Panel, { children: [
1848
+ /* @__PURE__ */ jsx19("div", { className: "card-label", children: "Inherited \xB7 read only" }),
1849
+ /* @__PURE__ */ jsxs16("h2", { children: [
1850
+ "Parent pages ",
1851
+ data.parent ? `\xB7 revision ${data.parent.revision}` : ""
1852
+ ] }),
1853
+ inherited.length === 0 ? /* @__PURE__ */ jsx19(AdminNote, { children: "No Parent pages have been delivered." }) : /* @__PURE__ */ jsx19("div", { className: "data-list", "data-member-content-inherited": true, children: inherited.map((page) => /* @__PURE__ */ jsxs16("article", { className: "card", children: [
1854
+ /* @__PURE__ */ jsx19("strong", { children: page.title }),
1855
+ /* @__PURE__ */ jsxs16("div", { className: "meeting-note", children: [
1856
+ "/",
1857
+ page.slug,
1858
+ " \xB7 ",
1859
+ page.navigation.section,
1860
+ " \xB7 ",
1861
+ accessLabel(page)
1862
+ ] }),
1863
+ /* @__PURE__ */ jsxs16("div", { className: "meeting-note", children: [
1864
+ "Upsell: ",
1865
+ page.upsell ? `${page.upsell.owner} controlled` : "none"
1866
+ ] })
1867
+ ] }, page.id)) })
1868
+ ] }),
1869
+ /* @__PURE__ */ jsxs16(Panel, { children: [
1870
+ /* @__PURE__ */ jsx19("div", { className: "card-label", children: "Chapter \xB7 editable" }),
1871
+ /* @__PURE__ */ jsxs16("h2", { children: [
1872
+ "Local document \xB7 revision ",
1873
+ data.chapter?.revision ?? 0
1874
+ ] }),
1875
+ /* @__PURE__ */ jsx19("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." }),
1876
+ /* @__PURE__ */ jsxs16("label", { className: "field", children: [
1877
+ /* @__PURE__ */ jsx19("span", { children: "Pages and delegated upsells (JSON)" }),
1878
+ /* @__PURE__ */ jsx19(
1879
+ "textarea",
1880
+ {
1881
+ rows: 24,
1882
+ value: draft,
1883
+ disabled: !data.localAuthoring || saving,
1884
+ onInput: (event) => setDraft(event.currentTarget.value),
1885
+ spellcheck: false
1886
+ }
1887
+ )
1888
+ ] }),
1889
+ saveError ? /* @__PURE__ */ jsxs16("div", { className: "notice danger", role: "alert", children: [
1890
+ /* @__PURE__ */ jsx19("strong", { children: "Fix these items before saving:" }),
1891
+ /* @__PURE__ */ jsx19("ul", { children: saveError.map((error) => /* @__PURE__ */ jsx19("li", { children: error }, error)) })
1892
+ ] }) : null,
1893
+ /* @__PURE__ */ jsx19("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring || saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save chapter content" }),
1894
+ !data.localAuthoring ? /* @__PURE__ */ jsx19(AdminNote, { children: "Local authoring is disabled in the checked-in Chapter config." }) : null
1895
+ ] })
1896
+ ] });
1897
+ }
1898
+ function memberContentSection() {
1899
+ return {
1900
+ id: "member-content",
1901
+ label: "Member content",
1902
+ render: (ctx) => /* @__PURE__ */ jsx19(MemberContentAdmin, { ctx })
1903
+ };
1904
+ }
1905
+
1768
1906
  // src/ui/admin-workspaces.tsx
1769
- import { jsx as jsx19 } from "preact/jsx-runtime";
1907
+ import { jsx as jsx20 } from "preact/jsx-runtime";
1770
1908
  var adminViewContext = (ctx, viewId, active) => {
1771
1909
  const route = {
1772
1910
  workspaceId: ctx.route.workspaceId,
@@ -1792,7 +1930,7 @@ function DashboardWorkspace({ chapter, ctx }) {
1792
1930
  const active = ctx.route.viewId === "billing" ? "billing" : "overview";
1793
1931
  const overview = dashboardSection({ id: "overview", label: copy.workspaces.overview });
1794
1932
  const billing = billingSection({ label: copy.workspaces.billing });
1795
- return /* @__PURE__ */ jsx19(
1933
+ return /* @__PURE__ */ jsx20(
1796
1934
  Tabs2,
1797
1935
  {
1798
1936
  ariaLabel: copy.workspaces.dashboardViewsLabel,
@@ -1817,10 +1955,11 @@ function DashboardWorkspace({ chapter, ctx }) {
1817
1955
  }
1818
1956
  function SettingsWorkspace({ chapter, ctx }) {
1819
1957
  const copy = chapter.copy.admin;
1820
- const active = ctx.route.viewId === "email" ? "email" : "calendar";
1958
+ const active = ctx.route.viewId === "email" ? "email" : ctx.route.viewId === "member-content" && chapter.memberContent ? "member-content" : "calendar";
1821
1959
  const calendar = availabilitySection({ id: "calendar", label: copy.workspaces.calendar });
1822
1960
  const email = emailSection({ label: copy.workspaces.email });
1823
- return /* @__PURE__ */ jsx19(
1961
+ const content = memberContentSection();
1962
+ return /* @__PURE__ */ jsx20(
1824
1963
  Tabs2,
1825
1964
  {
1826
1965
  ariaLabel: copy.workspaces.settingsViewsLabel,
@@ -1838,7 +1977,13 @@ function SettingsWorkspace({ chapter, ctx }) {
1838
1977
  label: copy.workspaces.email,
1839
1978
  href: ctx.href({ viewId: "email", recordId: null, detailTab: null }),
1840
1979
  panel: email.render(adminViewContext(ctx, "email", active === "email"))
1841
- }
1980
+ },
1981
+ ...chapter.memberContent ? [{
1982
+ value: "member-content",
1983
+ label: "Member content",
1984
+ href: ctx.href({ viewId: "member-content", recordId: null, detailTab: null }),
1985
+ panel: content.render(adminViewContext(ctx, "member-content", active === "member-content"))
1986
+ }] : []
1842
1987
  ]
1843
1988
  }
1844
1989
  );
@@ -1848,7 +1993,7 @@ function PeopleWorkspace({ chapter, ctx }) {
1848
1993
  const fallback = types[0]?.[0] ?? "person";
1849
1994
  const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
1850
1995
  const networkSharing = chapter.network.targets.length > 0;
1851
- return /* @__PURE__ */ jsx19(
1996
+ return /* @__PURE__ */ jsx20(
1852
1997
  Tabs2,
1853
1998
  {
1854
1999
  ariaLabel: chapter.copy.admin.workspaces.collectionsLabel,
@@ -1878,8 +2023,8 @@ function PortfolioWorkspace({ chapter, ctx }) {
1878
2023
  const types = Object.entries(chapter.crm.config.types).filter(([, def]) => def.workspace === "portfolio");
1879
2024
  const fallback = types[0]?.[0] ?? "";
1880
2025
  const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
1881
- if (!active) return /* @__PURE__ */ jsx19(LeaderNetworkOverview, { ctx });
1882
- return /* @__PURE__ */ jsx19(
2026
+ if (!active) return /* @__PURE__ */ jsx20(LeaderNetworkOverview, { ctx });
2027
+ return /* @__PURE__ */ jsx20(
1883
2028
  Tabs2,
1884
2029
  {
1885
2030
  ariaLabel: copy.workspaces.portfolioViewsLabel,
@@ -1903,7 +2048,7 @@ function PortfolioWorkspace({ chapter, ctx }) {
1903
2048
  );
1904
2049
  }
1905
2050
  function LeaderDashboardWorkspace({ chapter, ctx }) {
1906
- return /* @__PURE__ */ jsx19(
2051
+ return /* @__PURE__ */ jsx20(
1907
2052
  Tabs2,
1908
2053
  {
1909
2054
  ariaLabel: chapter.copy.admin.workspaces.dashboardViewsLabel,
@@ -1913,14 +2058,14 @@ function LeaderDashboardWorkspace({ chapter, ctx }) {
1913
2058
  value: "overview",
1914
2059
  label: chapter.copy.admin.workspaces.overview,
1915
2060
  href: ctx.href({ viewId: "overview", recordId: null, detailTab: null }),
1916
- panel: /* @__PURE__ */ jsx19(LeaderNetworkOverview, { ctx: adminViewContext(ctx, "overview", true) })
2061
+ panel: /* @__PURE__ */ jsx20(LeaderNetworkOverview, { ctx: adminViewContext(ctx, "overview", true) })
1917
2062
  }]
1918
2063
  }
1919
2064
  );
1920
2065
  }
1921
2066
  function LeaderSettingsWorkspace({ chapter, ctx }) {
1922
2067
  const email = emailSection({ label: chapter.copy.admin.workspaces.email });
1923
- return /* @__PURE__ */ jsx19(
2068
+ return /* @__PURE__ */ jsx20(
1924
2069
  Tabs2,
1925
2070
  {
1926
2071
  ariaLabel: chapter.copy.admin.workspaces.settingsViewsLabel,
@@ -1941,7 +2086,7 @@ function defaultAdminWorkspaces(chapter) {
1941
2086
  id: "people",
1942
2087
  label: copy.workspaces.people,
1943
2088
  defaultViewId: Object.keys(chapter.crm.config.types)[0] ?? "person",
1944
- render: (ctx) => /* @__PURE__ */ jsx19(PeopleWorkspace, { chapter, ctx })
2089
+ render: (ctx) => /* @__PURE__ */ jsx20(PeopleWorkspace, { chapter, ctx })
1945
2090
  };
1946
2091
  if (chapter.mode === "hub" && chapter.network.targets.length === 0) return [people];
1947
2092
  if (chapter.mode === "hub") {
@@ -1951,7 +2096,7 @@ function defaultAdminWorkspaces(chapter) {
1951
2096
  id: "dashboard",
1952
2097
  label: copy.workspaces.dashboard,
1953
2098
  defaultViewId: "overview",
1954
- render: (ctx) => /* @__PURE__ */ jsx19(LeaderDashboardWorkspace, { chapter, ctx })
2099
+ render: (ctx) => /* @__PURE__ */ jsx20(LeaderDashboardWorkspace, { chapter, ctx })
1955
2100
  },
1956
2101
  networkRecordsWorkspace(chapter),
1957
2102
  people,
@@ -1959,13 +2104,13 @@ function defaultAdminWorkspaces(chapter) {
1959
2104
  id: "portfolio",
1960
2105
  label: copy.workspaces.portfolio,
1961
2106
  defaultViewId: portfolioTypes[0]?.[0],
1962
- render: (ctx) => /* @__PURE__ */ jsx19(PortfolioWorkspace, { chapter, ctx })
2107
+ render: (ctx) => /* @__PURE__ */ jsx20(PortfolioWorkspace, { chapter, ctx })
1963
2108
  },
1964
2109
  {
1965
2110
  id: "settings",
1966
2111
  label: copy.workspaces.settings,
1967
2112
  defaultViewId: "email",
1968
- render: (ctx) => /* @__PURE__ */ jsx19(LeaderSettingsWorkspace, { chapter, ctx })
2113
+ render: (ctx) => /* @__PURE__ */ jsx20(LeaderSettingsWorkspace, { chapter, ctx })
1969
2114
  }
1970
2115
  ];
1971
2116
  }
@@ -1974,7 +2119,7 @@ function defaultAdminWorkspaces(chapter) {
1974
2119
  id: "dashboard",
1975
2120
  label: copy.workspaces.dashboard,
1976
2121
  defaultViewId: "overview",
1977
- render: (ctx) => /* @__PURE__ */ jsx19(DashboardWorkspace, { chapter, ctx })
2122
+ render: (ctx) => /* @__PURE__ */ jsx20(DashboardWorkspace, { chapter, ctx })
1978
2123
  },
1979
2124
  people,
1980
2125
  admissionGrantsWorkspace(copy.workspaces.admission),
@@ -1982,17 +2127,17 @@ function defaultAdminWorkspaces(chapter) {
1982
2127
  id: "settings",
1983
2128
  label: copy.workspaces.settings,
1984
2129
  defaultViewId: "calendar",
1985
- render: (ctx) => /* @__PURE__ */ jsx19(SettingsWorkspace, { chapter, ctx })
2130
+ render: (ctx) => /* @__PURE__ */ jsx20(SettingsWorkspace, { chapter, ctx })
1986
2131
  }
1987
2132
  ];
1988
2133
  }
1989
2134
 
1990
2135
  // src/ui/admin-frame.tsx
1991
2136
  import { ThemeScope as ThemeScope2 } from "@odla-ai/ui/components";
1992
- import { jsx as jsx20, jsxs as jsxs16 } from "preact/jsx-runtime";
2137
+ import { jsx as jsx21, jsxs as jsxs17 } from "preact/jsx-runtime";
1993
2138
  function AdminTheme(props) {
1994
2139
  const brand = props.chapter?.brand;
1995
- return /* @__PURE__ */ jsx20(ChapterCopyProvider, { copy: props.chapter?.copy, children: /* @__PURE__ */ jsxs16(
2140
+ return /* @__PURE__ */ jsx21(ChapterCopyProvider, { copy: props.chapter?.copy, children: /* @__PURE__ */ jsxs17(
1996
2141
  ThemeScope2,
1997
2142
  {
1998
2143
  ref: props.scopeRef,
@@ -2001,7 +2146,7 @@ function AdminTheme(props) {
2001
2146
  accent: brand?.accent,
2002
2147
  colorScheme: brand?.colorScheme ?? "light",
2003
2148
  children: [
2004
- /* @__PURE__ */ jsx20(BrandStyle, { brand, selector: "[data-chapter-admin]" }),
2149
+ /* @__PURE__ */ jsx21(BrandStyle, { brand, selector: "[data-chapter-admin]" }),
2005
2150
  props.children
2006
2151
  ]
2007
2152
  }
@@ -2021,11 +2166,11 @@ function signInRedirect(basePath, workspaces) {
2021
2166
  }
2022
2167
 
2023
2168
  // src/ui/admin-appearance.ts
2024
- import { useEffect as useEffect8, useState as useState14 } from "preact/hooks";
2169
+ import { useEffect as useEffect9, useState as useState15 } from "preact/hooks";
2025
2170
  import { clerkAppearanceFromTokens } from "@odla-ai/auth-clerk";
2026
2171
  function useScopedClerkAppearance(scope) {
2027
- const [appearance, setAppearance] = useState14();
2028
- useEffect8(() => {
2172
+ const [appearance, setAppearance] = useState15();
2173
+ useEffect9(() => {
2029
2174
  setAppearance(clerkAppearanceFromTokens(scope.current ?? void 0));
2030
2175
  }, [scope]);
2031
2176
  return appearance;
@@ -2056,7 +2201,7 @@ async function loadChapterAdminUser(adapter, apiBase, getToken) {
2056
2201
  }
2057
2202
 
2058
2203
  // src/ui/admin.tsx
2059
- import { jsx as jsx21, jsxs as jsxs17 } from "preact/jsx-runtime";
2204
+ import { jsx as jsx22, jsxs as jsxs18 } from "preact/jsx-runtime";
2060
2205
  function Authed(props) {
2061
2206
  const copy = useChapterCopy().admin;
2062
2207
  const {
@@ -2083,8 +2228,8 @@ function Authed(props) {
2083
2228
  }),
2084
2229
  [getToken, crmBasePath]
2085
2230
  );
2086
- const [state, setState] = useState15({ status: "checking" });
2087
- useEffect9(() => {
2231
+ const [state, setState] = useState16({ status: "checking" });
2232
+ useEffect10(() => {
2088
2233
  let live = true;
2089
2234
  void (async () => {
2090
2235
  try {
@@ -2103,17 +2248,17 @@ function Authed(props) {
2103
2248
  live = false;
2104
2249
  };
2105
2250
  }, [getToken, apiBase, auth]);
2106
- if (state.status === "checking") return /* @__PURE__ */ jsx21(Gate, { brand, children: /* @__PURE__ */ jsx21("p", { style: S.muted, children: copy.auth.checking }) });
2251
+ if (state.status === "checking") return /* @__PURE__ */ jsx22(Gate, { brand, children: /* @__PURE__ */ jsx22("p", { style: S.muted, children: copy.auth.checking }) });
2107
2252
  if (state.status === "denied") {
2108
- return /* @__PURE__ */ jsx21(Gate, { brand, children: /* @__PURE__ */ jsxs17("div", { className: "card", style: S.card, children: [
2109
- /* @__PURE__ */ jsx21("h2", { style: { marginTop: 0 }, children: copy.auth.notAuthorized }),
2110
- /* @__PURE__ */ jsx21("p", { style: S.muted, children: formatChapterCopy(copy.auth.accountNotAuthorized, {
2253
+ return /* @__PURE__ */ jsx22(Gate, { brand, children: /* @__PURE__ */ jsxs18("div", { className: "card", style: S.card, children: [
2254
+ /* @__PURE__ */ jsx22("h2", { style: { marginTop: 0 }, children: copy.auth.notAuthorized }),
2255
+ /* @__PURE__ */ jsx22("p", { style: S.muted, children: formatChapterCopy(copy.auth.accountNotAuthorized, {
2111
2256
  account: state.email ?? copy.auth.thisAccount
2112
2257
  }) }),
2113
- /* @__PURE__ */ jsx21("button", { className: "btn secondary", onClick: () => signOut(), children: copy.auth.signOut })
2258
+ /* @__PURE__ */ jsx22("button", { className: "btn secondary", onClick: () => signOut(), children: copy.auth.signOut })
2114
2259
  ] }) });
2115
2260
  }
2116
- return /* @__PURE__ */ jsx21(
2261
+ return /* @__PURE__ */ jsx22(
2117
2262
  AdminShell,
2118
2263
  {
2119
2264
  workspaces,
@@ -2154,10 +2299,10 @@ function ChapterAdmin(props) {
2154
2299
  const chrome = props.chrome ?? "embedded";
2155
2300
  const auth = props.auth ?? DEFAULT_ADMIN_AUTH;
2156
2301
  const redirect = signInRedirect(basePath, workspaces);
2157
- const [publishableKey, setPublishableKey] = useState15(void 0);
2302
+ const [publishableKey, setPublishableKey] = useState16(void 0);
2158
2303
  const scopeRef = useRef(null);
2159
2304
  const appearance = useScopedClerkAppearance(scopeRef);
2160
- useEffect9(() => {
2305
+ useEffect10(() => {
2161
2306
  let live = true;
2162
2307
  void loadChapterAdminConfig(auth, apiBase).then((config) => live && setPublishableKey(config.publishableKey ?? null)).catch(() => live && setPublishableKey(null));
2163
2308
  return () => {
@@ -2166,23 +2311,23 @@ function ChapterAdmin(props) {
2166
2311
  }, [apiBase, auth]);
2167
2312
  let content;
2168
2313
  if (publishableKey === void 0 || publishableKey && !appearance) {
2169
- content = /* @__PURE__ */ jsx21(Gate, { brand, children: /* @__PURE__ */ jsx21("p", { style: S.muted, children: copy.admin.auth.loading }) });
2314
+ content = /* @__PURE__ */ jsx22(Gate, { brand, children: /* @__PURE__ */ jsx22("p", { style: S.muted, children: copy.admin.auth.loading }) });
2170
2315
  } else if (!publishableKey) {
2171
- content = /* @__PURE__ */ jsx21(Gate, { brand, children: /* @__PURE__ */ jsxs17("div", { className: "card", style: S.card, children: [
2172
- /* @__PURE__ */ jsx21("h2", { style: { marginTop: 0 }, children: copy.admin.auth.signInNotConfigured }),
2173
- /* @__PURE__ */ jsx21("p", { style: S.muted, children: copy.admin.auth.missingPublishableKey })
2316
+ content = /* @__PURE__ */ jsx22(Gate, { brand, children: /* @__PURE__ */ jsxs18("div", { className: "card", style: S.card, children: [
2317
+ /* @__PURE__ */ jsx22("h2", { style: { marginTop: 0 }, children: copy.admin.auth.signInNotConfigured }),
2318
+ /* @__PURE__ */ jsx22("p", { style: S.muted, children: copy.admin.auth.missingPublishableKey })
2174
2319
  ] }) });
2175
2320
  } else if (workspaces.length === 0) {
2176
- content = /* @__PURE__ */ jsx21(Gate, { brand, children: /* @__PURE__ */ jsx21("p", { style: S.muted, children: copy.admin.auth.noWorkspaces }) });
2321
+ content = /* @__PURE__ */ jsx22(Gate, { brand, children: /* @__PURE__ */ jsx22("p", { style: S.muted, children: copy.admin.auth.noWorkspaces }) });
2177
2322
  } else {
2178
- content = /* @__PURE__ */ jsxs17(
2323
+ content = /* @__PURE__ */ jsxs18(
2179
2324
  ClerkGate,
2180
2325
  {
2181
2326
  publishableKey,
2182
2327
  appearance,
2183
2328
  afterSignOutUrl: "/",
2184
2329
  children: [
2185
- /* @__PURE__ */ jsx21(SignedOut, { children: /* @__PURE__ */ jsx21(Gate, { brand, tagline: copy.admin.auth.signInTagline, children: /* @__PURE__ */ jsx21(
2330
+ /* @__PURE__ */ jsx22(SignedOut, { children: /* @__PURE__ */ jsx22(Gate, { brand, tagline: copy.admin.auth.signInTagline, children: /* @__PURE__ */ jsx22(
2186
2331
  SignIn,
2187
2332
  {
2188
2333
  routing: "hash",
@@ -2190,7 +2335,7 @@ function ChapterAdmin(props) {
2190
2335
  signUpForceRedirectUrl: redirect
2191
2336
  }
2192
2337
  ) }) }),
2193
- /* @__PURE__ */ jsx21(SignedIn, { children: /* @__PURE__ */ jsx21(
2338
+ /* @__PURE__ */ jsx22(SignedIn, { children: /* @__PURE__ */ jsx22(
2194
2339
  Authed,
2195
2340
  {
2196
2341
  workspaces,
@@ -2210,7 +2355,7 @@ function ChapterAdmin(props) {
2210
2355
  }
2211
2356
  );
2212
2357
  }
2213
- return /* @__PURE__ */ jsx21(AdminTheme, { chapter: props.chapter, scopeRef, children: content });
2358
+ return /* @__PURE__ */ jsx22(AdminTheme, { chapter: props.chapter, scopeRef, children: content });
2214
2359
  }
2215
2360
 
2216
2361
  // src/ui/admin-defaults.ts
@@ -2219,17 +2364,17 @@ function defaultAdminSections(chapter) {
2219
2364
  }
2220
2365
 
2221
2366
  // src/ui/admin-meetings.tsx
2222
- import { useState as useState16 } from "preact/hooks";
2367
+ import { useState as useState17 } from "preact/hooks";
2223
2368
  import { Button as Button7 } from "@odla-ai/ui/components";
2224
- import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs18 } from "preact/jsx-runtime";
2369
+ import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs19 } from "preact/jsx-runtime";
2225
2370
  var when2 = (t) => new Date(t).toLocaleString([], { dateStyle: "medium", timeStyle: "short" });
2226
2371
  function MeetingsBody({ ctx }) {
2227
2372
  const copy = useChapterCopy().admin.meetings;
2228
2373
  const { data, loading, error, refresh } = useAdminResource(ctx.getToken, "/api/admin/meetings?all=1");
2229
- const [busy, setBusy] = useState16(null);
2230
- const [note, setNote] = useState16(null);
2231
- if (loading) return /* @__PURE__ */ jsx22(AdminNote, { children: copy.loading });
2232
- if (error || !data) return /* @__PURE__ */ jsxs18(AdminNote, { children: [
2374
+ const [busy, setBusy] = useState17(null);
2375
+ const [note, setNote] = useState17(null);
2376
+ if (loading) return /* @__PURE__ */ jsx23(AdminNote, { children: copy.loading });
2377
+ if (error || !data) return /* @__PURE__ */ jsxs19(AdminNote, { children: [
2233
2378
  copy.loadFailed,
2234
2379
  error ? `: ${error}` : "",
2235
2380
  "."
@@ -2260,32 +2405,32 @@ function MeetingsBody({ ctx }) {
2260
2405
  }
2261
2406
  void run(id, () => adminFetch(ctx.getToken, `/api/admin/meetings/${id}/reschedule`, { method: "POST", body: JSON.stringify({ startAt }) }));
2262
2407
  };
2263
- return /* @__PURE__ */ jsx22(AdminPage, { children: /* @__PURE__ */ jsx22(Panel, { title: /* @__PURE__ */ jsxs18(Fragment4, { children: [
2408
+ return /* @__PURE__ */ jsx23(AdminPage, { children: /* @__PURE__ */ jsx23(Panel, { title: /* @__PURE__ */ jsxs19(Fragment4, { children: [
2264
2409
  copy.agenda,
2265
2410
  " ",
2266
- /* @__PURE__ */ jsxs18("span", { className: "muted", style: { fontWeight: 400 }, children: [
2411
+ /* @__PURE__ */ jsxs19("span", { className: "muted", style: { fontWeight: 400 }, children: [
2267
2412
  "\xB7 ",
2268
2413
  data.timezone
2269
2414
  ] })
2270
- ] }), actions: note ? /* @__PURE__ */ jsx22("span", { className: "muted", children: note }) : void 0, children: data.meetings.length === 0 ? /* @__PURE__ */ jsx22("p", { className: "muted", style: { margin: 0 }, children: copy.empty }) : /* @__PURE__ */ jsx22("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 12 }, children: data.meetings.map((m) => /* @__PURE__ */ jsxs18("li", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap", opacity: m.status === "cancelled" ? 0.55 : 1 }, children: [
2271
- /* @__PURE__ */ jsx22("strong", { style: { minWidth: 170 }, children: when2(m.startAt) }),
2272
- /* @__PURE__ */ jsx22("span", { style: { flex: 1 }, children: m.applicant ? `${m.applicant.name} \xB7 ${m.applicant.email}` : copy.unknown }),
2273
- /* @__PURE__ */ jsx22("span", { className: "badge", children: m.status }),
2274
- m.drift && m.drift !== "none" ? /* @__PURE__ */ jsxs18("span", { className: "badge", children: [
2415
+ ] }), actions: note ? /* @__PURE__ */ jsx23("span", { className: "muted", children: note }) : void 0, children: data.meetings.length === 0 ? /* @__PURE__ */ jsx23("p", { className: "muted", style: { margin: 0 }, children: copy.empty }) : /* @__PURE__ */ jsx23("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 12 }, children: data.meetings.map((m) => /* @__PURE__ */ jsxs19("li", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap", opacity: m.status === "cancelled" ? 0.55 : 1 }, children: [
2416
+ /* @__PURE__ */ jsx23("strong", { style: { minWidth: 170 }, children: when2(m.startAt) }),
2417
+ /* @__PURE__ */ jsx23("span", { style: { flex: 1 }, children: m.applicant ? `${m.applicant.name} \xB7 ${m.applicant.email}` : copy.unknown }),
2418
+ /* @__PURE__ */ jsx23("span", { className: "badge", children: m.status }),
2419
+ m.drift && m.drift !== "none" ? /* @__PURE__ */ jsxs19("span", { className: "badge", children: [
2275
2420
  copy.drift,
2276
2421
  ": ",
2277
2422
  m.drift
2278
2423
  ] }) : null,
2279
- m.meetUrl ? /* @__PURE__ */ jsx22("a", { href: m.meetUrl, target: "_blank", rel: "noreferrer", children: copy.meet }) : null,
2280
- m.status === "scheduled" ? /* @__PURE__ */ jsxs18(Fragment4, { children: [
2281
- /* @__PURE__ */ jsx22(Button7, { variant: "secondary", mini: true, disabled: busy === m.id, onClick: () => reschedule(m.id), children: copy.reschedule }),
2282
- /* @__PURE__ */ jsx22(Button7, { variant: "danger", mini: true, disabled: busy === m.id, onClick: () => cancel(m.id), children: copy.cancel })
2424
+ m.meetUrl ? /* @__PURE__ */ jsx23("a", { href: m.meetUrl, target: "_blank", rel: "noreferrer", children: copy.meet }) : null,
2425
+ m.status === "scheduled" ? /* @__PURE__ */ jsxs19(Fragment4, { children: [
2426
+ /* @__PURE__ */ jsx23(Button7, { variant: "secondary", mini: true, disabled: busy === m.id, onClick: () => reschedule(m.id), children: copy.reschedule }),
2427
+ /* @__PURE__ */ jsx23(Button7, { variant: "danger", mini: true, disabled: busy === m.id, onClick: () => cancel(m.id), children: copy.cancel })
2283
2428
  ] }) : null
2284
2429
  ] }, m.id)) }) }) });
2285
2430
  }
2286
2431
  function meetingsSection(options = {}) {
2287
2432
  const { id = "meetings", label = "Meetings" } = options;
2288
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx22(MeetingsBody, { ctx }) };
2433
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx23(MeetingsBody, { ctx }) };
2289
2434
  }
2290
2435
 
2291
2436
  export {
@@ -2313,6 +2458,8 @@ export {
2313
2458
  LeaderNetworkOverview,
2314
2459
  AdmissionGrantsWorkspace,
2315
2460
  admissionGrantsWorkspace,
2461
+ MemberContentAdmin,
2462
+ memberContentSection,
2316
2463
  defaultAdminWorkspaces,
2317
2464
  loadChapterAdminConfig,
2318
2465
  loadChapterAdminUser,
@@ -2320,4 +2467,4 @@ export {
2320
2467
  defaultAdminSections,
2321
2468
  meetingsSection
2322
2469
  };
2323
- //# sourceMappingURL=chunk-LWM32REV.js.map
2470
+ //# sourceMappingURL=chunk-SI3JHSEX.js.map