@odla-ai/chapter 0.35.0 → 0.36.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-JAWTIROV.js";
7
+ } from "./chunk-IAWBE5PX.js";
8
8
 
9
9
  // src/ui/admin.tsx
10
- import { useEffect as useEffect9, useMemo as useMemo2, useRef, useState as useState14 } from "preact/hooks";
10
+ import { useEffect as useEffect9, useMemo as useMemo2, useRef, useState as useState15 } 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
 
@@ -1661,8 +1661,112 @@ function LeaderNetworkOverview({ ctx }) {
1661
1661
  ] });
1662
1662
  }
1663
1663
 
1664
+ // src/ui/admin-admission.tsx
1665
+ import { useState as useState13 } from "preact/hooks";
1666
+ import { jsx as jsx18, jsxs as jsxs15 } from "preact/jsx-runtime";
1667
+ function AdmissionGrantsWorkspace(props) {
1668
+ const copy = useChapterCopy().admin.admission;
1669
+ const resource = useAdminResource(props.getToken, "/api/admin/admission-grants");
1670
+ const [email, setEmail] = useState13("");
1671
+ const [decision, setDecision] = useState13("waive_interview");
1672
+ const [note, setNote] = useState13("");
1673
+ const [expires, setExpires] = useState13("");
1674
+ const [busy, setBusy] = useState13(false);
1675
+ const [error, setError] = useState13(null);
1676
+ const submit = async (event) => {
1677
+ event.preventDefault();
1678
+ setBusy(true);
1679
+ setError(null);
1680
+ try {
1681
+ await adminFetch(props.getToken, "/api/admin/admission-grants", {
1682
+ method: "POST",
1683
+ body: JSON.stringify({
1684
+ email,
1685
+ decision,
1686
+ ...note.trim() ? { note } : {},
1687
+ ...expires ? { expiresAt: (/* @__PURE__ */ new Date(`${expires}T23:59:59Z`)).getTime() } : {}
1688
+ })
1689
+ });
1690
+ setEmail("");
1691
+ setNote("");
1692
+ setExpires("");
1693
+ resource.refresh();
1694
+ } catch (cause) {
1695
+ setError(cause instanceof Error ? cause.message : String(cause));
1696
+ } finally {
1697
+ setBusy(false);
1698
+ }
1699
+ };
1700
+ const revoke = async (grant) => {
1701
+ setBusy(true);
1702
+ setError(null);
1703
+ try {
1704
+ await adminFetch(props.getToken, `/api/admin/admission-grants/${encodeURIComponent(grant.id)}`, { method: "DELETE" });
1705
+ resource.refresh();
1706
+ } catch (cause) {
1707
+ setError(cause instanceof Error ? cause.message : String(cause));
1708
+ } finally {
1709
+ setBusy(false);
1710
+ }
1711
+ };
1712
+ return /* @__PURE__ */ jsxs15(AdminPage, { children: [
1713
+ /* @__PURE__ */ jsxs15(Panel, { title: copy.title, children: [
1714
+ /* @__PURE__ */ jsx18("p", { className: "muted", style: { margin: 0 }, children: copy.description }),
1715
+ /* @__PURE__ */ jsxs15("form", { onSubmit: (event) => void submit(event), style: { display: "grid", gap: 12, gridTemplateColumns: "minmax(220px,2fr) minmax(180px,1fr) minmax(160px,1fr)" }, children: [
1716
+ /* @__PURE__ */ jsxs15("label", { children: [
1717
+ copy.email,
1718
+ /* @__PURE__ */ jsx18("input", { required: true, type: "email", value: email, onInput: (event) => setEmail(event.currentTarget.value) })
1719
+ ] }),
1720
+ /* @__PURE__ */ jsxs15("label", { children: [
1721
+ copy.decision,
1722
+ /* @__PURE__ */ jsxs15("select", { value: decision, onChange: (event) => setDecision(event.currentTarget.value), children: [
1723
+ /* @__PURE__ */ jsx18("option", { value: "waive_interview", children: copy.waive }),
1724
+ /* @__PURE__ */ jsx18("option", { value: "require_interview", children: copy.require })
1725
+ ] })
1726
+ ] }),
1727
+ /* @__PURE__ */ jsxs15("label", { children: [
1728
+ copy.expires,
1729
+ /* @__PURE__ */ jsx18("input", { type: "date", value: expires, onInput: (event) => setExpires(event.currentTarget.value) })
1730
+ ] }),
1731
+ /* @__PURE__ */ jsxs15("label", { style: { gridColumn: "1 / -1" }, children: [
1732
+ copy.note,
1733
+ /* @__PURE__ */ jsx18("input", { value: note, maxLength: 2e3, onInput: (event) => setNote(event.currentTarget.value) })
1734
+ ] }),
1735
+ /* @__PURE__ */ jsx18("button", { className: "btn secondary", type: "submit", disabled: busy, children: copy.add })
1736
+ ] }),
1737
+ error ? /* @__PURE__ */ jsx18("p", { role: "alert", children: error }) : null
1738
+ ] }),
1739
+ /* @__PURE__ */ jsxs15(Panel, { title: copy.ledger, children: [
1740
+ resource.loading ? /* @__PURE__ */ jsx18("p", { className: "muted", children: copy.loading }) : resource.error ? /* @__PURE__ */ jsx18("p", { role: "alert", children: resource.error }) : null,
1741
+ /* @__PURE__ */ jsx18("div", { style: { display: "grid", gap: 10 }, children: (resource.data?.grants ?? []).map((grant) => {
1742
+ const state = grant.consumedAt ? copy.consumed : grant.revokedAt || !grant.active ? copy.revoked : grant.expiresAt && grant.expiresAt <= Date.now() ? copy.expired : copy.active;
1743
+ return /* @__PURE__ */ jsxs15("article", { className: "card", style: { padding: 14 }, children: [
1744
+ /* @__PURE__ */ jsx18("strong", { children: grant.email }),
1745
+ " \xB7 ",
1746
+ grant.decision === "waive_interview" ? copy.waive : copy.require,
1747
+ /* @__PURE__ */ jsxs15("p", { className: "muted", style: { margin: "6px 0" }, children: [
1748
+ grant.sourceScope === "local" ? copy.local : copy.parent,
1749
+ " \xB7 ",
1750
+ state,
1751
+ grant.note ? ` \xB7 ${grant.note}` : ""
1752
+ ] }),
1753
+ grant.sourceScope === "local" && state === copy.active ? /* @__PURE__ */ jsx18("button", { className: "btn secondary mini", disabled: busy, onClick: () => void revoke(grant), children: copy.revoke }) : null
1754
+ ] }, grant.id);
1755
+ }) })
1756
+ ] })
1757
+ ] });
1758
+ }
1759
+ function admissionGrantsWorkspace(label = "Admission") {
1760
+ return {
1761
+ id: "admission",
1762
+ label,
1763
+ defaultViewId: "grants",
1764
+ render: (ctx) => /* @__PURE__ */ jsx18(AdmissionGrantsWorkspace, { getToken: ctx.getToken })
1765
+ };
1766
+ }
1767
+
1664
1768
  // src/ui/admin-workspaces.tsx
1665
- import { jsx as jsx18 } from "preact/jsx-runtime";
1769
+ import { jsx as jsx19 } from "preact/jsx-runtime";
1666
1770
  var adminViewContext = (ctx, viewId, active) => {
1667
1771
  const route = {
1668
1772
  workspaceId: ctx.route.workspaceId,
@@ -1688,7 +1792,7 @@ function DashboardWorkspace({ chapter, ctx }) {
1688
1792
  const active = ctx.route.viewId === "billing" ? "billing" : "overview";
1689
1793
  const overview = dashboardSection({ id: "overview", label: copy.workspaces.overview });
1690
1794
  const billing = billingSection({ label: copy.workspaces.billing });
1691
- return /* @__PURE__ */ jsx18(
1795
+ return /* @__PURE__ */ jsx19(
1692
1796
  Tabs2,
1693
1797
  {
1694
1798
  ariaLabel: copy.workspaces.dashboardViewsLabel,
@@ -1716,7 +1820,7 @@ function SettingsWorkspace({ chapter, ctx }) {
1716
1820
  const active = ctx.route.viewId === "email" ? "email" : "calendar";
1717
1821
  const calendar = availabilitySection({ id: "calendar", label: copy.workspaces.calendar });
1718
1822
  const email = emailSection({ label: copy.workspaces.email });
1719
- return /* @__PURE__ */ jsx18(
1823
+ return /* @__PURE__ */ jsx19(
1720
1824
  Tabs2,
1721
1825
  {
1722
1826
  ariaLabel: copy.workspaces.settingsViewsLabel,
@@ -1744,7 +1848,7 @@ function PeopleWorkspace({ chapter, ctx }) {
1744
1848
  const fallback = types[0]?.[0] ?? "person";
1745
1849
  const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
1746
1850
  const networkSharing = chapter.network.targets.length > 0;
1747
- return /* @__PURE__ */ jsx18(
1851
+ return /* @__PURE__ */ jsx19(
1748
1852
  Tabs2,
1749
1853
  {
1750
1854
  ariaLabel: chapter.copy.admin.workspaces.collectionsLabel,
@@ -1774,8 +1878,8 @@ function PortfolioWorkspace({ chapter, ctx }) {
1774
1878
  const types = Object.entries(chapter.crm.config.types).filter(([, def]) => def.workspace === "portfolio");
1775
1879
  const fallback = types[0]?.[0] ?? "";
1776
1880
  const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
1777
- if (!active) return /* @__PURE__ */ jsx18(LeaderNetworkOverview, { ctx });
1778
- return /* @__PURE__ */ jsx18(
1881
+ if (!active) return /* @__PURE__ */ jsx19(LeaderNetworkOverview, { ctx });
1882
+ return /* @__PURE__ */ jsx19(
1779
1883
  Tabs2,
1780
1884
  {
1781
1885
  ariaLabel: copy.workspaces.portfolioViewsLabel,
@@ -1799,7 +1903,7 @@ function PortfolioWorkspace({ chapter, ctx }) {
1799
1903
  );
1800
1904
  }
1801
1905
  function LeaderDashboardWorkspace({ chapter, ctx }) {
1802
- return /* @__PURE__ */ jsx18(
1906
+ return /* @__PURE__ */ jsx19(
1803
1907
  Tabs2,
1804
1908
  {
1805
1909
  ariaLabel: chapter.copy.admin.workspaces.dashboardViewsLabel,
@@ -1809,14 +1913,14 @@ function LeaderDashboardWorkspace({ chapter, ctx }) {
1809
1913
  value: "overview",
1810
1914
  label: chapter.copy.admin.workspaces.overview,
1811
1915
  href: ctx.href({ viewId: "overview", recordId: null, detailTab: null }),
1812
- panel: /* @__PURE__ */ jsx18(LeaderNetworkOverview, { ctx: adminViewContext(ctx, "overview", true) })
1916
+ panel: /* @__PURE__ */ jsx19(LeaderNetworkOverview, { ctx: adminViewContext(ctx, "overview", true) })
1813
1917
  }]
1814
1918
  }
1815
1919
  );
1816
1920
  }
1817
1921
  function LeaderSettingsWorkspace({ chapter, ctx }) {
1818
1922
  const email = emailSection({ label: chapter.copy.admin.workspaces.email });
1819
- return /* @__PURE__ */ jsx18(
1923
+ return /* @__PURE__ */ jsx19(
1820
1924
  Tabs2,
1821
1925
  {
1822
1926
  ariaLabel: chapter.copy.admin.workspaces.settingsViewsLabel,
@@ -1837,7 +1941,7 @@ function defaultAdminWorkspaces(chapter) {
1837
1941
  id: "people",
1838
1942
  label: copy.workspaces.people,
1839
1943
  defaultViewId: Object.keys(chapter.crm.config.types)[0] ?? "person",
1840
- render: (ctx) => /* @__PURE__ */ jsx18(PeopleWorkspace, { chapter, ctx })
1944
+ render: (ctx) => /* @__PURE__ */ jsx19(PeopleWorkspace, { chapter, ctx })
1841
1945
  };
1842
1946
  if (chapter.mode === "hub" && chapter.network.targets.length === 0) return [people];
1843
1947
  if (chapter.mode === "hub") {
@@ -1847,7 +1951,7 @@ function defaultAdminWorkspaces(chapter) {
1847
1951
  id: "dashboard",
1848
1952
  label: copy.workspaces.dashboard,
1849
1953
  defaultViewId: "overview",
1850
- render: (ctx) => /* @__PURE__ */ jsx18(LeaderDashboardWorkspace, { chapter, ctx })
1954
+ render: (ctx) => /* @__PURE__ */ jsx19(LeaderDashboardWorkspace, { chapter, ctx })
1851
1955
  },
1852
1956
  networkRecordsWorkspace(chapter),
1853
1957
  people,
@@ -1855,13 +1959,13 @@ function defaultAdminWorkspaces(chapter) {
1855
1959
  id: "portfolio",
1856
1960
  label: copy.workspaces.portfolio,
1857
1961
  defaultViewId: portfolioTypes[0]?.[0],
1858
- render: (ctx) => /* @__PURE__ */ jsx18(PortfolioWorkspace, { chapter, ctx })
1962
+ render: (ctx) => /* @__PURE__ */ jsx19(PortfolioWorkspace, { chapter, ctx })
1859
1963
  },
1860
1964
  {
1861
1965
  id: "settings",
1862
1966
  label: copy.workspaces.settings,
1863
1967
  defaultViewId: "email",
1864
- render: (ctx) => /* @__PURE__ */ jsx18(LeaderSettingsWorkspace, { chapter, ctx })
1968
+ render: (ctx) => /* @__PURE__ */ jsx19(LeaderSettingsWorkspace, { chapter, ctx })
1865
1969
  }
1866
1970
  ];
1867
1971
  }
@@ -1870,24 +1974,25 @@ function defaultAdminWorkspaces(chapter) {
1870
1974
  id: "dashboard",
1871
1975
  label: copy.workspaces.dashboard,
1872
1976
  defaultViewId: "overview",
1873
- render: (ctx) => /* @__PURE__ */ jsx18(DashboardWorkspace, { chapter, ctx })
1977
+ render: (ctx) => /* @__PURE__ */ jsx19(DashboardWorkspace, { chapter, ctx })
1874
1978
  },
1875
1979
  people,
1980
+ admissionGrantsWorkspace(copy.workspaces.admission),
1876
1981
  {
1877
1982
  id: "settings",
1878
1983
  label: copy.workspaces.settings,
1879
1984
  defaultViewId: "calendar",
1880
- render: (ctx) => /* @__PURE__ */ jsx18(SettingsWorkspace, { chapter, ctx })
1985
+ render: (ctx) => /* @__PURE__ */ jsx19(SettingsWorkspace, { chapter, ctx })
1881
1986
  }
1882
1987
  ];
1883
1988
  }
1884
1989
 
1885
1990
  // src/ui/admin-frame.tsx
1886
1991
  import { ThemeScope as ThemeScope2 } from "@odla-ai/ui/components";
1887
- import { jsx as jsx19, jsxs as jsxs15 } from "preact/jsx-runtime";
1992
+ import { jsx as jsx20, jsxs as jsxs16 } from "preact/jsx-runtime";
1888
1993
  function AdminTheme(props) {
1889
1994
  const brand = props.chapter?.brand;
1890
- return /* @__PURE__ */ jsx19(ChapterCopyProvider, { copy: props.chapter?.copy, children: /* @__PURE__ */ jsxs15(
1995
+ return /* @__PURE__ */ jsx20(ChapterCopyProvider, { copy: props.chapter?.copy, children: /* @__PURE__ */ jsxs16(
1891
1996
  ThemeScope2,
1892
1997
  {
1893
1998
  ref: props.scopeRef,
@@ -1896,7 +2001,7 @@ function AdminTheme(props) {
1896
2001
  accent: brand?.accent,
1897
2002
  colorScheme: brand?.colorScheme ?? "light",
1898
2003
  children: [
1899
- /* @__PURE__ */ jsx19(BrandStyle, { brand, selector: "[data-chapter-admin]" }),
2004
+ /* @__PURE__ */ jsx20(BrandStyle, { brand, selector: "[data-chapter-admin]" }),
1900
2005
  props.children
1901
2006
  ]
1902
2007
  }
@@ -1916,10 +2021,10 @@ function signInRedirect(basePath, workspaces) {
1916
2021
  }
1917
2022
 
1918
2023
  // src/ui/admin-appearance.ts
1919
- import { useEffect as useEffect8, useState as useState13 } from "preact/hooks";
2024
+ import { useEffect as useEffect8, useState as useState14 } from "preact/hooks";
1920
2025
  import { clerkAppearanceFromTokens } from "@odla-ai/auth-clerk";
1921
2026
  function useScopedClerkAppearance(scope) {
1922
- const [appearance, setAppearance] = useState13();
2027
+ const [appearance, setAppearance] = useState14();
1923
2028
  useEffect8(() => {
1924
2029
  setAppearance(clerkAppearanceFromTokens(scope.current ?? void 0));
1925
2030
  }, [scope]);
@@ -1951,7 +2056,7 @@ async function loadChapterAdminUser(adapter, apiBase, getToken) {
1951
2056
  }
1952
2057
 
1953
2058
  // src/ui/admin.tsx
1954
- import { jsx as jsx20, jsxs as jsxs16 } from "preact/jsx-runtime";
2059
+ import { jsx as jsx21, jsxs as jsxs17 } from "preact/jsx-runtime";
1955
2060
  function Authed(props) {
1956
2061
  const copy = useChapterCopy().admin;
1957
2062
  const {
@@ -1978,7 +2083,7 @@ function Authed(props) {
1978
2083
  }),
1979
2084
  [getToken, crmBasePath]
1980
2085
  );
1981
- const [state, setState] = useState14({ status: "checking" });
2086
+ const [state, setState] = useState15({ status: "checking" });
1982
2087
  useEffect9(() => {
1983
2088
  let live = true;
1984
2089
  void (async () => {
@@ -1998,17 +2103,17 @@ function Authed(props) {
1998
2103
  live = false;
1999
2104
  };
2000
2105
  }, [getToken, apiBase, auth]);
2001
- if (state.status === "checking") return /* @__PURE__ */ jsx20(Gate, { brand, children: /* @__PURE__ */ jsx20("p", { style: S.muted, children: copy.auth.checking }) });
2106
+ if (state.status === "checking") return /* @__PURE__ */ jsx21(Gate, { brand, children: /* @__PURE__ */ jsx21("p", { style: S.muted, children: copy.auth.checking }) });
2002
2107
  if (state.status === "denied") {
2003
- return /* @__PURE__ */ jsx20(Gate, { brand, children: /* @__PURE__ */ jsxs16("div", { className: "card", style: S.card, children: [
2004
- /* @__PURE__ */ jsx20("h2", { style: { marginTop: 0 }, children: copy.auth.notAuthorized }),
2005
- /* @__PURE__ */ jsx20("p", { style: S.muted, children: formatChapterCopy(copy.auth.accountNotAuthorized, {
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, {
2006
2111
  account: state.email ?? copy.auth.thisAccount
2007
2112
  }) }),
2008
- /* @__PURE__ */ jsx20("button", { className: "btn secondary", onClick: () => signOut(), children: copy.auth.signOut })
2113
+ /* @__PURE__ */ jsx21("button", { className: "btn secondary", onClick: () => signOut(), children: copy.auth.signOut })
2009
2114
  ] }) });
2010
2115
  }
2011
- return /* @__PURE__ */ jsx20(
2116
+ return /* @__PURE__ */ jsx21(
2012
2117
  AdminShell,
2013
2118
  {
2014
2119
  workspaces,
@@ -2049,7 +2154,7 @@ function ChapterAdmin(props) {
2049
2154
  const chrome = props.chrome ?? "embedded";
2050
2155
  const auth = props.auth ?? DEFAULT_ADMIN_AUTH;
2051
2156
  const redirect = signInRedirect(basePath, workspaces);
2052
- const [publishableKey, setPublishableKey] = useState14(void 0);
2157
+ const [publishableKey, setPublishableKey] = useState15(void 0);
2053
2158
  const scopeRef = useRef(null);
2054
2159
  const appearance = useScopedClerkAppearance(scopeRef);
2055
2160
  useEffect9(() => {
@@ -2061,23 +2166,23 @@ function ChapterAdmin(props) {
2061
2166
  }, [apiBase, auth]);
2062
2167
  let content;
2063
2168
  if (publishableKey === void 0 || publishableKey && !appearance) {
2064
- content = /* @__PURE__ */ jsx20(Gate, { brand, children: /* @__PURE__ */ jsx20("p", { style: S.muted, children: copy.admin.auth.loading }) });
2169
+ content = /* @__PURE__ */ jsx21(Gate, { brand, children: /* @__PURE__ */ jsx21("p", { style: S.muted, children: copy.admin.auth.loading }) });
2065
2170
  } else if (!publishableKey) {
2066
- content = /* @__PURE__ */ jsx20(Gate, { brand, children: /* @__PURE__ */ jsxs16("div", { className: "card", style: S.card, children: [
2067
- /* @__PURE__ */ jsx20("h2", { style: { marginTop: 0 }, children: copy.admin.auth.signInNotConfigured }),
2068
- /* @__PURE__ */ jsx20("p", { style: S.muted, children: copy.admin.auth.missingPublishableKey })
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 })
2069
2174
  ] }) });
2070
2175
  } else if (workspaces.length === 0) {
2071
- content = /* @__PURE__ */ jsx20(Gate, { brand, children: /* @__PURE__ */ jsx20("p", { style: S.muted, children: copy.admin.auth.noWorkspaces }) });
2176
+ content = /* @__PURE__ */ jsx21(Gate, { brand, children: /* @__PURE__ */ jsx21("p", { style: S.muted, children: copy.admin.auth.noWorkspaces }) });
2072
2177
  } else {
2073
- content = /* @__PURE__ */ jsxs16(
2178
+ content = /* @__PURE__ */ jsxs17(
2074
2179
  ClerkGate,
2075
2180
  {
2076
2181
  publishableKey,
2077
2182
  appearance,
2078
2183
  afterSignOutUrl: "/",
2079
2184
  children: [
2080
- /* @__PURE__ */ jsx20(SignedOut, { children: /* @__PURE__ */ jsx20(Gate, { brand, tagline: copy.admin.auth.signInTagline, children: /* @__PURE__ */ jsx20(
2185
+ /* @__PURE__ */ jsx21(SignedOut, { children: /* @__PURE__ */ jsx21(Gate, { brand, tagline: copy.admin.auth.signInTagline, children: /* @__PURE__ */ jsx21(
2081
2186
  SignIn,
2082
2187
  {
2083
2188
  routing: "hash",
@@ -2085,7 +2190,7 @@ function ChapterAdmin(props) {
2085
2190
  signUpForceRedirectUrl: redirect
2086
2191
  }
2087
2192
  ) }) }),
2088
- /* @__PURE__ */ jsx20(SignedIn, { children: /* @__PURE__ */ jsx20(
2193
+ /* @__PURE__ */ jsx21(SignedIn, { children: /* @__PURE__ */ jsx21(
2089
2194
  Authed,
2090
2195
  {
2091
2196
  workspaces,
@@ -2105,7 +2210,7 @@ function ChapterAdmin(props) {
2105
2210
  }
2106
2211
  );
2107
2212
  }
2108
- return /* @__PURE__ */ jsx20(AdminTheme, { chapter: props.chapter, scopeRef, children: content });
2213
+ return /* @__PURE__ */ jsx21(AdminTheme, { chapter: props.chapter, scopeRef, children: content });
2109
2214
  }
2110
2215
 
2111
2216
  // src/ui/admin-defaults.ts
@@ -2114,17 +2219,17 @@ function defaultAdminSections(chapter) {
2114
2219
  }
2115
2220
 
2116
2221
  // src/ui/admin-meetings.tsx
2117
- import { useState as useState15 } from "preact/hooks";
2222
+ import { useState as useState16 } from "preact/hooks";
2118
2223
  import { Button as Button7 } from "@odla-ai/ui/components";
2119
- import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs17 } from "preact/jsx-runtime";
2224
+ import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs18 } from "preact/jsx-runtime";
2120
2225
  var when2 = (t) => new Date(t).toLocaleString([], { dateStyle: "medium", timeStyle: "short" });
2121
2226
  function MeetingsBody({ ctx }) {
2122
2227
  const copy = useChapterCopy().admin.meetings;
2123
2228
  const { data, loading, error, refresh } = useAdminResource(ctx.getToken, "/api/admin/meetings?all=1");
2124
- const [busy, setBusy] = useState15(null);
2125
- const [note, setNote] = useState15(null);
2126
- if (loading) return /* @__PURE__ */ jsx21(AdminNote, { children: copy.loading });
2127
- if (error || !data) return /* @__PURE__ */ jsxs17(AdminNote, { children: [
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: [
2128
2233
  copy.loadFailed,
2129
2234
  error ? `: ${error}` : "",
2130
2235
  "."
@@ -2155,32 +2260,32 @@ function MeetingsBody({ ctx }) {
2155
2260
  }
2156
2261
  void run(id, () => adminFetch(ctx.getToken, `/api/admin/meetings/${id}/reschedule`, { method: "POST", body: JSON.stringify({ startAt }) }));
2157
2262
  };
2158
- return /* @__PURE__ */ jsx21(AdminPage, { children: /* @__PURE__ */ jsx21(Panel, { title: /* @__PURE__ */ jsxs17(Fragment4, { children: [
2263
+ return /* @__PURE__ */ jsx22(AdminPage, { children: /* @__PURE__ */ jsx22(Panel, { title: /* @__PURE__ */ jsxs18(Fragment4, { children: [
2159
2264
  copy.agenda,
2160
2265
  " ",
2161
- /* @__PURE__ */ jsxs17("span", { className: "muted", style: { fontWeight: 400 }, children: [
2266
+ /* @__PURE__ */ jsxs18("span", { className: "muted", style: { fontWeight: 400 }, children: [
2162
2267
  "\xB7 ",
2163
2268
  data.timezone
2164
2269
  ] })
2165
- ] }), actions: note ? /* @__PURE__ */ jsx21("span", { className: "muted", children: note }) : void 0, children: data.meetings.length === 0 ? /* @__PURE__ */ jsx21("p", { className: "muted", style: { margin: 0 }, children: copy.empty }) : /* @__PURE__ */ jsx21("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 12 }, children: data.meetings.map((m) => /* @__PURE__ */ jsxs17("li", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap", opacity: m.status === "cancelled" ? 0.55 : 1 }, children: [
2166
- /* @__PURE__ */ jsx21("strong", { style: { minWidth: 170 }, children: when2(m.startAt) }),
2167
- /* @__PURE__ */ jsx21("span", { style: { flex: 1 }, children: m.applicant ? `${m.applicant.name} \xB7 ${m.applicant.email}` : copy.unknown }),
2168
- /* @__PURE__ */ jsx21("span", { className: "badge", children: m.status }),
2169
- m.drift && m.drift !== "none" ? /* @__PURE__ */ jsxs17("span", { className: "badge", children: [
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: [
2170
2275
  copy.drift,
2171
2276
  ": ",
2172
2277
  m.drift
2173
2278
  ] }) : null,
2174
- m.meetUrl ? /* @__PURE__ */ jsx21("a", { href: m.meetUrl, target: "_blank", rel: "noreferrer", children: copy.meet }) : null,
2175
- m.status === "scheduled" ? /* @__PURE__ */ jsxs17(Fragment4, { children: [
2176
- /* @__PURE__ */ jsx21(Button7, { variant: "secondary", mini: true, disabled: busy === m.id, onClick: () => reschedule(m.id), children: copy.reschedule }),
2177
- /* @__PURE__ */ jsx21(Button7, { variant: "danger", mini: true, disabled: busy === m.id, onClick: () => cancel(m.id), children: copy.cancel })
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 })
2178
2283
  ] }) : null
2179
2284
  ] }, m.id)) }) }) });
2180
2285
  }
2181
2286
  function meetingsSection(options = {}) {
2182
2287
  const { id = "meetings", label = "Meetings" } = options;
2183
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx21(MeetingsBody, { ctx }) };
2288
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx22(MeetingsBody, { ctx }) };
2184
2289
  }
2185
2290
 
2186
2291
  export {
@@ -2206,6 +2311,8 @@ export {
2206
2311
  NetworkRecordsWorkspace,
2207
2312
  networkRecordsWorkspace,
2208
2313
  LeaderNetworkOverview,
2314
+ AdmissionGrantsWorkspace,
2315
+ admissionGrantsWorkspace,
2209
2316
  defaultAdminWorkspaces,
2210
2317
  loadChapterAdminConfig,
2211
2318
  loadChapterAdminUser,
@@ -2213,4 +2320,4 @@ export {
2213
2320
  defaultAdminSections,
2214
2321
  meetingsSection
2215
2322
  };
2216
- //# sourceMappingURL=chunk-TXE5ZDI4.js.map
2323
+ //# sourceMappingURL=chunk-LWM32REV.js.map