@odla-ai/chapter 0.35.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.
- package/README.md +106 -0
- package/dist/{chunk-UJIVBGL5.js → chunk-BIYWPPH6.js} +535 -240
- package/dist/chunk-BIYWPPH6.js.map +1 -0
- package/dist/{chunk-JAWTIROV.js → chunk-IAWBE5PX.js} +55 -1
- package/dist/chunk-IAWBE5PX.js.map +1 -0
- package/dist/{chunk-TXE5ZDI4.js → chunk-SI3JHSEX.js} +319 -65
- package/dist/chunk-SI3JHSEX.js.map +1 -0
- package/dist/{copy-context-c1tqPXOR.d.ts → copy-context-Pbs3keLx.d.ts} +179 -29
- package/dist/index.cjs +1262 -326
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +439 -30
- package/dist/index.d.ts +439 -30
- package/dist/index.js +1262 -326
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +34 -3
- package/dist/ui/admin/index.js +10 -2
- package/dist/ui/index.d.ts +3 -3
- package/dist/ui/index.js +17 -3
- package/dist/ui/member/index.d.ts +111 -7
- package/dist/ui/member/index.js +8 -2
- package/dist/worker/index.cjs +2623 -917
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +251 -29
- package/dist/worker/index.d.ts +251 -29
- package/dist/worker/index.js +2657 -951
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
- package/runbooks/greenfield.md +27 -0
- package/dist/chunk-JAWTIROV.js.map +0 -1
- package/dist/chunk-TXE5ZDI4.js.map +0 -1
- package/dist/chunk-UJIVBGL5.js.map +0 -1
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
DEFAULT_CHAPTER_COPY,
|
|
5
5
|
formatChapterCopy,
|
|
6
6
|
useChapterCopy
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-IAWBE5PX.js";
|
|
8
8
|
|
|
9
9
|
// src/ui/admin.tsx
|
|
10
|
-
import { useEffect as
|
|
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)
|
|
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) {
|
|
@@ -1661,8 +1667,244 @@ function LeaderNetworkOverview({ ctx }) {
|
|
|
1661
1667
|
] });
|
|
1662
1668
|
}
|
|
1663
1669
|
|
|
1670
|
+
// src/ui/admin-admission.tsx
|
|
1671
|
+
import { useState as useState13 } from "preact/hooks";
|
|
1672
|
+
import { jsx as jsx18, jsxs as jsxs15 } from "preact/jsx-runtime";
|
|
1673
|
+
function AdmissionGrantsWorkspace(props) {
|
|
1674
|
+
const copy = useChapterCopy().admin.admission;
|
|
1675
|
+
const resource = useAdminResource(props.getToken, "/api/admin/admission-grants");
|
|
1676
|
+
const [email, setEmail] = useState13("");
|
|
1677
|
+
const [decision, setDecision] = useState13("waive_interview");
|
|
1678
|
+
const [note, setNote] = useState13("");
|
|
1679
|
+
const [expires, setExpires] = useState13("");
|
|
1680
|
+
const [busy, setBusy] = useState13(false);
|
|
1681
|
+
const [error, setError] = useState13(null);
|
|
1682
|
+
const submit = async (event) => {
|
|
1683
|
+
event.preventDefault();
|
|
1684
|
+
setBusy(true);
|
|
1685
|
+
setError(null);
|
|
1686
|
+
try {
|
|
1687
|
+
await adminFetch(props.getToken, "/api/admin/admission-grants", {
|
|
1688
|
+
method: "POST",
|
|
1689
|
+
body: JSON.stringify({
|
|
1690
|
+
email,
|
|
1691
|
+
decision,
|
|
1692
|
+
...note.trim() ? { note } : {},
|
|
1693
|
+
...expires ? { expiresAt: (/* @__PURE__ */ new Date(`${expires}T23:59:59Z`)).getTime() } : {}
|
|
1694
|
+
})
|
|
1695
|
+
});
|
|
1696
|
+
setEmail("");
|
|
1697
|
+
setNote("");
|
|
1698
|
+
setExpires("");
|
|
1699
|
+
resource.refresh();
|
|
1700
|
+
} catch (cause) {
|
|
1701
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
1702
|
+
} finally {
|
|
1703
|
+
setBusy(false);
|
|
1704
|
+
}
|
|
1705
|
+
};
|
|
1706
|
+
const revoke = async (grant) => {
|
|
1707
|
+
setBusy(true);
|
|
1708
|
+
setError(null);
|
|
1709
|
+
try {
|
|
1710
|
+
await adminFetch(props.getToken, `/api/admin/admission-grants/${encodeURIComponent(grant.id)}`, { method: "DELETE" });
|
|
1711
|
+
resource.refresh();
|
|
1712
|
+
} catch (cause) {
|
|
1713
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
1714
|
+
} finally {
|
|
1715
|
+
setBusy(false);
|
|
1716
|
+
}
|
|
1717
|
+
};
|
|
1718
|
+
return /* @__PURE__ */ jsxs15(AdminPage, { children: [
|
|
1719
|
+
/* @__PURE__ */ jsxs15(Panel, { title: copy.title, children: [
|
|
1720
|
+
/* @__PURE__ */ jsx18("p", { className: "muted", style: { margin: 0 }, children: copy.description }),
|
|
1721
|
+
/* @__PURE__ */ jsxs15("form", { onSubmit: (event) => void submit(event), style: { display: "grid", gap: 12, gridTemplateColumns: "minmax(220px,2fr) minmax(180px,1fr) minmax(160px,1fr)" }, children: [
|
|
1722
|
+
/* @__PURE__ */ jsxs15("label", { children: [
|
|
1723
|
+
copy.email,
|
|
1724
|
+
/* @__PURE__ */ jsx18("input", { required: true, type: "email", value: email, onInput: (event) => setEmail(event.currentTarget.value) })
|
|
1725
|
+
] }),
|
|
1726
|
+
/* @__PURE__ */ jsxs15("label", { children: [
|
|
1727
|
+
copy.decision,
|
|
1728
|
+
/* @__PURE__ */ jsxs15("select", { value: decision, onChange: (event) => setDecision(event.currentTarget.value), children: [
|
|
1729
|
+
/* @__PURE__ */ jsx18("option", { value: "waive_interview", children: copy.waive }),
|
|
1730
|
+
/* @__PURE__ */ jsx18("option", { value: "require_interview", children: copy.require })
|
|
1731
|
+
] })
|
|
1732
|
+
] }),
|
|
1733
|
+
/* @__PURE__ */ jsxs15("label", { children: [
|
|
1734
|
+
copy.expires,
|
|
1735
|
+
/* @__PURE__ */ jsx18("input", { type: "date", value: expires, onInput: (event) => setExpires(event.currentTarget.value) })
|
|
1736
|
+
] }),
|
|
1737
|
+
/* @__PURE__ */ jsxs15("label", { style: { gridColumn: "1 / -1" }, children: [
|
|
1738
|
+
copy.note,
|
|
1739
|
+
/* @__PURE__ */ jsx18("input", { value: note, maxLength: 2e3, onInput: (event) => setNote(event.currentTarget.value) })
|
|
1740
|
+
] }),
|
|
1741
|
+
/* @__PURE__ */ jsx18("button", { className: "btn secondary", type: "submit", disabled: busy, children: copy.add })
|
|
1742
|
+
] }),
|
|
1743
|
+
error ? /* @__PURE__ */ jsx18("p", { role: "alert", children: error }) : null
|
|
1744
|
+
] }),
|
|
1745
|
+
/* @__PURE__ */ jsxs15(Panel, { title: copy.ledger, children: [
|
|
1746
|
+
resource.loading ? /* @__PURE__ */ jsx18("p", { className: "muted", children: copy.loading }) : resource.error ? /* @__PURE__ */ jsx18("p", { role: "alert", children: resource.error }) : null,
|
|
1747
|
+
/* @__PURE__ */ jsx18("div", { style: { display: "grid", gap: 10 }, children: (resource.data?.grants ?? []).map((grant) => {
|
|
1748
|
+
const state = grant.consumedAt ? copy.consumed : grant.revokedAt || !grant.active ? copy.revoked : grant.expiresAt && grant.expiresAt <= Date.now() ? copy.expired : copy.active;
|
|
1749
|
+
return /* @__PURE__ */ jsxs15("article", { className: "card", style: { padding: 14 }, children: [
|
|
1750
|
+
/* @__PURE__ */ jsx18("strong", { children: grant.email }),
|
|
1751
|
+
" \xB7 ",
|
|
1752
|
+
grant.decision === "waive_interview" ? copy.waive : copy.require,
|
|
1753
|
+
/* @__PURE__ */ jsxs15("p", { className: "muted", style: { margin: "6px 0" }, children: [
|
|
1754
|
+
grant.sourceScope === "local" ? copy.local : copy.parent,
|
|
1755
|
+
" \xB7 ",
|
|
1756
|
+
state,
|
|
1757
|
+
grant.note ? ` \xB7 ${grant.note}` : ""
|
|
1758
|
+
] }),
|
|
1759
|
+
grant.sourceScope === "local" && state === copy.active ? /* @__PURE__ */ jsx18("button", { className: "btn secondary mini", disabled: busy, onClick: () => void revoke(grant), children: copy.revoke }) : null
|
|
1760
|
+
] }, grant.id);
|
|
1761
|
+
}) })
|
|
1762
|
+
] })
|
|
1763
|
+
] });
|
|
1764
|
+
}
|
|
1765
|
+
function admissionGrantsWorkspace(label = "Admission") {
|
|
1766
|
+
return {
|
|
1767
|
+
id: "admission",
|
|
1768
|
+
label,
|
|
1769
|
+
defaultViewId: "grants",
|
|
1770
|
+
render: (ctx) => /* @__PURE__ */ jsx18(AdmissionGrantsWorkspace, { getToken: ctx.getToken })
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
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
|
+
|
|
1664
1906
|
// src/ui/admin-workspaces.tsx
|
|
1665
|
-
import { jsx as
|
|
1907
|
+
import { jsx as jsx20 } from "preact/jsx-runtime";
|
|
1666
1908
|
var adminViewContext = (ctx, viewId, active) => {
|
|
1667
1909
|
const route = {
|
|
1668
1910
|
workspaceId: ctx.route.workspaceId,
|
|
@@ -1688,7 +1930,7 @@ function DashboardWorkspace({ chapter, ctx }) {
|
|
|
1688
1930
|
const active = ctx.route.viewId === "billing" ? "billing" : "overview";
|
|
1689
1931
|
const overview = dashboardSection({ id: "overview", label: copy.workspaces.overview });
|
|
1690
1932
|
const billing = billingSection({ label: copy.workspaces.billing });
|
|
1691
|
-
return /* @__PURE__ */
|
|
1933
|
+
return /* @__PURE__ */ jsx20(
|
|
1692
1934
|
Tabs2,
|
|
1693
1935
|
{
|
|
1694
1936
|
ariaLabel: copy.workspaces.dashboardViewsLabel,
|
|
@@ -1713,10 +1955,11 @@ function DashboardWorkspace({ chapter, ctx }) {
|
|
|
1713
1955
|
}
|
|
1714
1956
|
function SettingsWorkspace({ chapter, ctx }) {
|
|
1715
1957
|
const copy = chapter.copy.admin;
|
|
1716
|
-
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";
|
|
1717
1959
|
const calendar = availabilitySection({ id: "calendar", label: copy.workspaces.calendar });
|
|
1718
1960
|
const email = emailSection({ label: copy.workspaces.email });
|
|
1719
|
-
|
|
1961
|
+
const content = memberContentSection();
|
|
1962
|
+
return /* @__PURE__ */ jsx20(
|
|
1720
1963
|
Tabs2,
|
|
1721
1964
|
{
|
|
1722
1965
|
ariaLabel: copy.workspaces.settingsViewsLabel,
|
|
@@ -1734,7 +1977,13 @@ function SettingsWorkspace({ chapter, ctx }) {
|
|
|
1734
1977
|
label: copy.workspaces.email,
|
|
1735
1978
|
href: ctx.href({ viewId: "email", recordId: null, detailTab: null }),
|
|
1736
1979
|
panel: email.render(adminViewContext(ctx, "email", active === "email"))
|
|
1737
|
-
}
|
|
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
|
+
}] : []
|
|
1738
1987
|
]
|
|
1739
1988
|
}
|
|
1740
1989
|
);
|
|
@@ -1744,7 +1993,7 @@ function PeopleWorkspace({ chapter, ctx }) {
|
|
|
1744
1993
|
const fallback = types[0]?.[0] ?? "person";
|
|
1745
1994
|
const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
|
|
1746
1995
|
const networkSharing = chapter.network.targets.length > 0;
|
|
1747
|
-
return /* @__PURE__ */
|
|
1996
|
+
return /* @__PURE__ */ jsx20(
|
|
1748
1997
|
Tabs2,
|
|
1749
1998
|
{
|
|
1750
1999
|
ariaLabel: chapter.copy.admin.workspaces.collectionsLabel,
|
|
@@ -1774,8 +2023,8 @@ function PortfolioWorkspace({ chapter, ctx }) {
|
|
|
1774
2023
|
const types = Object.entries(chapter.crm.config.types).filter(([, def]) => def.workspace === "portfolio");
|
|
1775
2024
|
const fallback = types[0]?.[0] ?? "";
|
|
1776
2025
|
const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
|
|
1777
|
-
if (!active) return /* @__PURE__ */
|
|
1778
|
-
return /* @__PURE__ */
|
|
2026
|
+
if (!active) return /* @__PURE__ */ jsx20(LeaderNetworkOverview, { ctx });
|
|
2027
|
+
return /* @__PURE__ */ jsx20(
|
|
1779
2028
|
Tabs2,
|
|
1780
2029
|
{
|
|
1781
2030
|
ariaLabel: copy.workspaces.portfolioViewsLabel,
|
|
@@ -1799,7 +2048,7 @@ function PortfolioWorkspace({ chapter, ctx }) {
|
|
|
1799
2048
|
);
|
|
1800
2049
|
}
|
|
1801
2050
|
function LeaderDashboardWorkspace({ chapter, ctx }) {
|
|
1802
|
-
return /* @__PURE__ */
|
|
2051
|
+
return /* @__PURE__ */ jsx20(
|
|
1803
2052
|
Tabs2,
|
|
1804
2053
|
{
|
|
1805
2054
|
ariaLabel: chapter.copy.admin.workspaces.dashboardViewsLabel,
|
|
@@ -1809,14 +2058,14 @@ function LeaderDashboardWorkspace({ chapter, ctx }) {
|
|
|
1809
2058
|
value: "overview",
|
|
1810
2059
|
label: chapter.copy.admin.workspaces.overview,
|
|
1811
2060
|
href: ctx.href({ viewId: "overview", recordId: null, detailTab: null }),
|
|
1812
|
-
panel: /* @__PURE__ */
|
|
2061
|
+
panel: /* @__PURE__ */ jsx20(LeaderNetworkOverview, { ctx: adminViewContext(ctx, "overview", true) })
|
|
1813
2062
|
}]
|
|
1814
2063
|
}
|
|
1815
2064
|
);
|
|
1816
2065
|
}
|
|
1817
2066
|
function LeaderSettingsWorkspace({ chapter, ctx }) {
|
|
1818
2067
|
const email = emailSection({ label: chapter.copy.admin.workspaces.email });
|
|
1819
|
-
return /* @__PURE__ */
|
|
2068
|
+
return /* @__PURE__ */ jsx20(
|
|
1820
2069
|
Tabs2,
|
|
1821
2070
|
{
|
|
1822
2071
|
ariaLabel: chapter.copy.admin.workspaces.settingsViewsLabel,
|
|
@@ -1837,7 +2086,7 @@ function defaultAdminWorkspaces(chapter) {
|
|
|
1837
2086
|
id: "people",
|
|
1838
2087
|
label: copy.workspaces.people,
|
|
1839
2088
|
defaultViewId: Object.keys(chapter.crm.config.types)[0] ?? "person",
|
|
1840
|
-
render: (ctx) => /* @__PURE__ */
|
|
2089
|
+
render: (ctx) => /* @__PURE__ */ jsx20(PeopleWorkspace, { chapter, ctx })
|
|
1841
2090
|
};
|
|
1842
2091
|
if (chapter.mode === "hub" && chapter.network.targets.length === 0) return [people];
|
|
1843
2092
|
if (chapter.mode === "hub") {
|
|
@@ -1847,7 +2096,7 @@ function defaultAdminWorkspaces(chapter) {
|
|
|
1847
2096
|
id: "dashboard",
|
|
1848
2097
|
label: copy.workspaces.dashboard,
|
|
1849
2098
|
defaultViewId: "overview",
|
|
1850
|
-
render: (ctx) => /* @__PURE__ */
|
|
2099
|
+
render: (ctx) => /* @__PURE__ */ jsx20(LeaderDashboardWorkspace, { chapter, ctx })
|
|
1851
2100
|
},
|
|
1852
2101
|
networkRecordsWorkspace(chapter),
|
|
1853
2102
|
people,
|
|
@@ -1855,13 +2104,13 @@ function defaultAdminWorkspaces(chapter) {
|
|
|
1855
2104
|
id: "portfolio",
|
|
1856
2105
|
label: copy.workspaces.portfolio,
|
|
1857
2106
|
defaultViewId: portfolioTypes[0]?.[0],
|
|
1858
|
-
render: (ctx) => /* @__PURE__ */
|
|
2107
|
+
render: (ctx) => /* @__PURE__ */ jsx20(PortfolioWorkspace, { chapter, ctx })
|
|
1859
2108
|
},
|
|
1860
2109
|
{
|
|
1861
2110
|
id: "settings",
|
|
1862
2111
|
label: copy.workspaces.settings,
|
|
1863
2112
|
defaultViewId: "email",
|
|
1864
|
-
render: (ctx) => /* @__PURE__ */
|
|
2113
|
+
render: (ctx) => /* @__PURE__ */ jsx20(LeaderSettingsWorkspace, { chapter, ctx })
|
|
1865
2114
|
}
|
|
1866
2115
|
];
|
|
1867
2116
|
}
|
|
@@ -1870,24 +2119,25 @@ function defaultAdminWorkspaces(chapter) {
|
|
|
1870
2119
|
id: "dashboard",
|
|
1871
2120
|
label: copy.workspaces.dashboard,
|
|
1872
2121
|
defaultViewId: "overview",
|
|
1873
|
-
render: (ctx) => /* @__PURE__ */
|
|
2122
|
+
render: (ctx) => /* @__PURE__ */ jsx20(DashboardWorkspace, { chapter, ctx })
|
|
1874
2123
|
},
|
|
1875
2124
|
people,
|
|
2125
|
+
admissionGrantsWorkspace(copy.workspaces.admission),
|
|
1876
2126
|
{
|
|
1877
2127
|
id: "settings",
|
|
1878
2128
|
label: copy.workspaces.settings,
|
|
1879
2129
|
defaultViewId: "calendar",
|
|
1880
|
-
render: (ctx) => /* @__PURE__ */
|
|
2130
|
+
render: (ctx) => /* @__PURE__ */ jsx20(SettingsWorkspace, { chapter, ctx })
|
|
1881
2131
|
}
|
|
1882
2132
|
];
|
|
1883
2133
|
}
|
|
1884
2134
|
|
|
1885
2135
|
// src/ui/admin-frame.tsx
|
|
1886
2136
|
import { ThemeScope as ThemeScope2 } from "@odla-ai/ui/components";
|
|
1887
|
-
import { jsx as
|
|
2137
|
+
import { jsx as jsx21, jsxs as jsxs17 } from "preact/jsx-runtime";
|
|
1888
2138
|
function AdminTheme(props) {
|
|
1889
2139
|
const brand = props.chapter?.brand;
|
|
1890
|
-
return /* @__PURE__ */
|
|
2140
|
+
return /* @__PURE__ */ jsx21(ChapterCopyProvider, { copy: props.chapter?.copy, children: /* @__PURE__ */ jsxs17(
|
|
1891
2141
|
ThemeScope2,
|
|
1892
2142
|
{
|
|
1893
2143
|
ref: props.scopeRef,
|
|
@@ -1896,7 +2146,7 @@ function AdminTheme(props) {
|
|
|
1896
2146
|
accent: brand?.accent,
|
|
1897
2147
|
colorScheme: brand?.colorScheme ?? "light",
|
|
1898
2148
|
children: [
|
|
1899
|
-
/* @__PURE__ */
|
|
2149
|
+
/* @__PURE__ */ jsx21(BrandStyle, { brand, selector: "[data-chapter-admin]" }),
|
|
1900
2150
|
props.children
|
|
1901
2151
|
]
|
|
1902
2152
|
}
|
|
@@ -1916,11 +2166,11 @@ function signInRedirect(basePath, workspaces) {
|
|
|
1916
2166
|
}
|
|
1917
2167
|
|
|
1918
2168
|
// src/ui/admin-appearance.ts
|
|
1919
|
-
import { useEffect as
|
|
2169
|
+
import { useEffect as useEffect9, useState as useState15 } from "preact/hooks";
|
|
1920
2170
|
import { clerkAppearanceFromTokens } from "@odla-ai/auth-clerk";
|
|
1921
2171
|
function useScopedClerkAppearance(scope) {
|
|
1922
|
-
const [appearance, setAppearance] =
|
|
1923
|
-
|
|
2172
|
+
const [appearance, setAppearance] = useState15();
|
|
2173
|
+
useEffect9(() => {
|
|
1924
2174
|
setAppearance(clerkAppearanceFromTokens(scope.current ?? void 0));
|
|
1925
2175
|
}, [scope]);
|
|
1926
2176
|
return appearance;
|
|
@@ -1951,7 +2201,7 @@ async function loadChapterAdminUser(adapter, apiBase, getToken) {
|
|
|
1951
2201
|
}
|
|
1952
2202
|
|
|
1953
2203
|
// src/ui/admin.tsx
|
|
1954
|
-
import { jsx as
|
|
2204
|
+
import { jsx as jsx22, jsxs as jsxs18 } from "preact/jsx-runtime";
|
|
1955
2205
|
function Authed(props) {
|
|
1956
2206
|
const copy = useChapterCopy().admin;
|
|
1957
2207
|
const {
|
|
@@ -1978,8 +2228,8 @@ function Authed(props) {
|
|
|
1978
2228
|
}),
|
|
1979
2229
|
[getToken, crmBasePath]
|
|
1980
2230
|
);
|
|
1981
|
-
const [state, setState] =
|
|
1982
|
-
|
|
2231
|
+
const [state, setState] = useState16({ status: "checking" });
|
|
2232
|
+
useEffect10(() => {
|
|
1983
2233
|
let live = true;
|
|
1984
2234
|
void (async () => {
|
|
1985
2235
|
try {
|
|
@@ -1998,17 +2248,17 @@ function Authed(props) {
|
|
|
1998
2248
|
live = false;
|
|
1999
2249
|
};
|
|
2000
2250
|
}, [getToken, apiBase, auth]);
|
|
2001
|
-
if (state.status === "checking") return /* @__PURE__ */
|
|
2251
|
+
if (state.status === "checking") return /* @__PURE__ */ jsx22(Gate, { brand, children: /* @__PURE__ */ jsx22("p", { style: S.muted, children: copy.auth.checking }) });
|
|
2002
2252
|
if (state.status === "denied") {
|
|
2003
|
-
return /* @__PURE__ */
|
|
2004
|
-
/* @__PURE__ */
|
|
2005
|
-
/* @__PURE__ */
|
|
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, {
|
|
2006
2256
|
account: state.email ?? copy.auth.thisAccount
|
|
2007
2257
|
}) }),
|
|
2008
|
-
/* @__PURE__ */
|
|
2258
|
+
/* @__PURE__ */ jsx22("button", { className: "btn secondary", onClick: () => signOut(), children: copy.auth.signOut })
|
|
2009
2259
|
] }) });
|
|
2010
2260
|
}
|
|
2011
|
-
return /* @__PURE__ */
|
|
2261
|
+
return /* @__PURE__ */ jsx22(
|
|
2012
2262
|
AdminShell,
|
|
2013
2263
|
{
|
|
2014
2264
|
workspaces,
|
|
@@ -2049,10 +2299,10 @@ function ChapterAdmin(props) {
|
|
|
2049
2299
|
const chrome = props.chrome ?? "embedded";
|
|
2050
2300
|
const auth = props.auth ?? DEFAULT_ADMIN_AUTH;
|
|
2051
2301
|
const redirect = signInRedirect(basePath, workspaces);
|
|
2052
|
-
const [publishableKey, setPublishableKey] =
|
|
2302
|
+
const [publishableKey, setPublishableKey] = useState16(void 0);
|
|
2053
2303
|
const scopeRef = useRef(null);
|
|
2054
2304
|
const appearance = useScopedClerkAppearance(scopeRef);
|
|
2055
|
-
|
|
2305
|
+
useEffect10(() => {
|
|
2056
2306
|
let live = true;
|
|
2057
2307
|
void loadChapterAdminConfig(auth, apiBase).then((config) => live && setPublishableKey(config.publishableKey ?? null)).catch(() => live && setPublishableKey(null));
|
|
2058
2308
|
return () => {
|
|
@@ -2061,23 +2311,23 @@ function ChapterAdmin(props) {
|
|
|
2061
2311
|
}, [apiBase, auth]);
|
|
2062
2312
|
let content;
|
|
2063
2313
|
if (publishableKey === void 0 || publishableKey && !appearance) {
|
|
2064
|
-
content = /* @__PURE__ */
|
|
2314
|
+
content = /* @__PURE__ */ jsx22(Gate, { brand, children: /* @__PURE__ */ jsx22("p", { style: S.muted, children: copy.admin.auth.loading }) });
|
|
2065
2315
|
} else if (!publishableKey) {
|
|
2066
|
-
content = /* @__PURE__ */
|
|
2067
|
-
/* @__PURE__ */
|
|
2068
|
-
/* @__PURE__ */
|
|
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 })
|
|
2069
2319
|
] }) });
|
|
2070
2320
|
} else if (workspaces.length === 0) {
|
|
2071
|
-
content = /* @__PURE__ */
|
|
2321
|
+
content = /* @__PURE__ */ jsx22(Gate, { brand, children: /* @__PURE__ */ jsx22("p", { style: S.muted, children: copy.admin.auth.noWorkspaces }) });
|
|
2072
2322
|
} else {
|
|
2073
|
-
content = /* @__PURE__ */
|
|
2323
|
+
content = /* @__PURE__ */ jsxs18(
|
|
2074
2324
|
ClerkGate,
|
|
2075
2325
|
{
|
|
2076
2326
|
publishableKey,
|
|
2077
2327
|
appearance,
|
|
2078
2328
|
afterSignOutUrl: "/",
|
|
2079
2329
|
children: [
|
|
2080
|
-
/* @__PURE__ */
|
|
2330
|
+
/* @__PURE__ */ jsx22(SignedOut, { children: /* @__PURE__ */ jsx22(Gate, { brand, tagline: copy.admin.auth.signInTagline, children: /* @__PURE__ */ jsx22(
|
|
2081
2331
|
SignIn,
|
|
2082
2332
|
{
|
|
2083
2333
|
routing: "hash",
|
|
@@ -2085,7 +2335,7 @@ function ChapterAdmin(props) {
|
|
|
2085
2335
|
signUpForceRedirectUrl: redirect
|
|
2086
2336
|
}
|
|
2087
2337
|
) }) }),
|
|
2088
|
-
/* @__PURE__ */
|
|
2338
|
+
/* @__PURE__ */ jsx22(SignedIn, { children: /* @__PURE__ */ jsx22(
|
|
2089
2339
|
Authed,
|
|
2090
2340
|
{
|
|
2091
2341
|
workspaces,
|
|
@@ -2105,7 +2355,7 @@ function ChapterAdmin(props) {
|
|
|
2105
2355
|
}
|
|
2106
2356
|
);
|
|
2107
2357
|
}
|
|
2108
|
-
return /* @__PURE__ */
|
|
2358
|
+
return /* @__PURE__ */ jsx22(AdminTheme, { chapter: props.chapter, scopeRef, children: content });
|
|
2109
2359
|
}
|
|
2110
2360
|
|
|
2111
2361
|
// src/ui/admin-defaults.ts
|
|
@@ -2114,17 +2364,17 @@ function defaultAdminSections(chapter) {
|
|
|
2114
2364
|
}
|
|
2115
2365
|
|
|
2116
2366
|
// src/ui/admin-meetings.tsx
|
|
2117
|
-
import { useState as
|
|
2367
|
+
import { useState as useState17 } from "preact/hooks";
|
|
2118
2368
|
import { Button as Button7 } from "@odla-ai/ui/components";
|
|
2119
|
-
import { Fragment as Fragment4, jsx as
|
|
2369
|
+
import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs19 } from "preact/jsx-runtime";
|
|
2120
2370
|
var when2 = (t) => new Date(t).toLocaleString([], { dateStyle: "medium", timeStyle: "short" });
|
|
2121
2371
|
function MeetingsBody({ ctx }) {
|
|
2122
2372
|
const copy = useChapterCopy().admin.meetings;
|
|
2123
2373
|
const { data, loading, error, refresh } = useAdminResource(ctx.getToken, "/api/admin/meetings?all=1");
|
|
2124
|
-
const [busy, setBusy] =
|
|
2125
|
-
const [note, setNote] =
|
|
2126
|
-
if (loading) return /* @__PURE__ */
|
|
2127
|
-
if (error || !data) return /* @__PURE__ */
|
|
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: [
|
|
2128
2378
|
copy.loadFailed,
|
|
2129
2379
|
error ? `: ${error}` : "",
|
|
2130
2380
|
"."
|
|
@@ -2155,32 +2405,32 @@ function MeetingsBody({ ctx }) {
|
|
|
2155
2405
|
}
|
|
2156
2406
|
void run(id, () => adminFetch(ctx.getToken, `/api/admin/meetings/${id}/reschedule`, { method: "POST", body: JSON.stringify({ startAt }) }));
|
|
2157
2407
|
};
|
|
2158
|
-
return /* @__PURE__ */
|
|
2408
|
+
return /* @__PURE__ */ jsx23(AdminPage, { children: /* @__PURE__ */ jsx23(Panel, { title: /* @__PURE__ */ jsxs19(Fragment4, { children: [
|
|
2159
2409
|
copy.agenda,
|
|
2160
2410
|
" ",
|
|
2161
|
-
/* @__PURE__ */
|
|
2411
|
+
/* @__PURE__ */ jsxs19("span", { className: "muted", style: { fontWeight: 400 }, children: [
|
|
2162
2412
|
"\xB7 ",
|
|
2163
2413
|
data.timezone
|
|
2164
2414
|
] })
|
|
2165
|
-
] }), actions: note ? /* @__PURE__ */
|
|
2166
|
-
/* @__PURE__ */
|
|
2167
|
-
/* @__PURE__ */
|
|
2168
|
-
/* @__PURE__ */
|
|
2169
|
-
m.drift && m.drift !== "none" ? /* @__PURE__ */
|
|
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: [
|
|
2170
2420
|
copy.drift,
|
|
2171
2421
|
": ",
|
|
2172
2422
|
m.drift
|
|
2173
2423
|
] }) : null,
|
|
2174
|
-
m.meetUrl ? /* @__PURE__ */
|
|
2175
|
-
m.status === "scheduled" ? /* @__PURE__ */
|
|
2176
|
-
/* @__PURE__ */
|
|
2177
|
-
/* @__PURE__ */
|
|
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 })
|
|
2178
2428
|
] }) : null
|
|
2179
2429
|
] }, m.id)) }) }) });
|
|
2180
2430
|
}
|
|
2181
2431
|
function meetingsSection(options = {}) {
|
|
2182
2432
|
const { id = "meetings", label = "Meetings" } = options;
|
|
2183
|
-
return { id, label, render: (ctx) => /* @__PURE__ */
|
|
2433
|
+
return { id, label, render: (ctx) => /* @__PURE__ */ jsx23(MeetingsBody, { ctx }) };
|
|
2184
2434
|
}
|
|
2185
2435
|
|
|
2186
2436
|
export {
|
|
@@ -2206,6 +2456,10 @@ export {
|
|
|
2206
2456
|
NetworkRecordsWorkspace,
|
|
2207
2457
|
networkRecordsWorkspace,
|
|
2208
2458
|
LeaderNetworkOverview,
|
|
2459
|
+
AdmissionGrantsWorkspace,
|
|
2460
|
+
admissionGrantsWorkspace,
|
|
2461
|
+
MemberContentAdmin,
|
|
2462
|
+
memberContentSection,
|
|
2209
2463
|
defaultAdminWorkspaces,
|
|
2210
2464
|
loadChapterAdminConfig,
|
|
2211
2465
|
loadChapterAdminUser,
|
|
@@ -2213,4 +2467,4 @@ export {
|
|
|
2213
2467
|
defaultAdminSections,
|
|
2214
2468
|
meetingsSection
|
|
2215
2469
|
};
|
|
2216
|
-
//# sourceMappingURL=chunk-
|
|
2470
|
+
//# sourceMappingURL=chunk-SI3JHSEX.js.map
|