@odla-ai/chapter 0.62.0 → 0.63.1
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 +61 -0
- package/dist/{chunk-7CVP6VSO.js → chunk-OXYMVK2O.js} +145 -1
- package/dist/chunk-OXYMVK2O.js.map +1 -0
- package/dist/{chunk-MUUBATZJ.js → chunk-S6VPJFHL.js} +474 -200
- package/dist/chunk-S6VPJFHL.js.map +1 -0
- package/dist/{chunk-ZIYK3OV2.js → chunk-XFD66VFP.js} +697 -338
- package/dist/chunk-XFD66VFP.js.map +1 -0
- package/dist/{copy-context-BJUkVUjE.d.ts → copy-context-BNKK7ZDm.d.ts} +6 -0
- package/dist/index.cjs +419 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +196 -6
- package/dist/index.d.ts +196 -6
- package/dist/index.js +419 -73
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +2 -2
- package/dist/ui/admin/index.js +2 -2
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.js +53 -11
- package/dist/ui/member/index.d.ts +175 -3
- package/dist/ui/member/index.js +52 -10
- package/dist/worker/index.cjs +3722 -2903
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +6 -0
- package/dist/worker/index.d.ts +6 -0
- package/dist/worker/index.js +3729 -2910
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-7CVP6VSO.js.map +0 -1
- package/dist/chunk-MUUBATZJ.js.map +0 -1
- package/dist/chunk-ZIYK3OV2.js.map +0 -1
|
@@ -2,12 +2,13 @@ import {
|
|
|
2
2
|
BrandStyle,
|
|
3
3
|
ChapterCopyProvider,
|
|
4
4
|
DEFAULT_CHAPTER_COPY,
|
|
5
|
+
fmtMoney,
|
|
5
6
|
formatChapterCopy,
|
|
6
7
|
useChapterCopy
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-OXYMVK2O.js";
|
|
8
9
|
|
|
9
10
|
// src/ui/admin.tsx
|
|
10
|
-
import { useEffect as
|
|
11
|
+
import { useEffect as useEffect14, useMemo as useMemo3, useRef as useRef3, useState as useState31 } from "preact/hooks";
|
|
11
12
|
import { ClerkGate, SignedIn, SignedOut, SignIn, useClerkAuth } from "@odla-ai/auth-clerk";
|
|
12
13
|
import { CrmClient } from "@odla-ai/crm";
|
|
13
14
|
|
|
@@ -3008,13 +3009,283 @@ function memberContentSection() {
|
|
|
3008
3009
|
}
|
|
3009
3010
|
|
|
3010
3011
|
// src/ui/admin-member-portal.tsx
|
|
3011
|
-
import { useState as
|
|
3012
|
+
import { useState as useState29 } from "preact/hooks";
|
|
3013
|
+
|
|
3014
|
+
// src/ui/admin-member-course.tsx
|
|
3015
|
+
import { useEffect as useEffect12, useState as useState27 } from "preact/hooks";
|
|
3012
3016
|
import { jsx as jsx32, jsxs as jsxs30 } from "preact/jsx-runtime";
|
|
3017
|
+
var EXAMPLE = { title: "", timezone: "America/Denver", capacity: 20, signupClosesAt: 0, content: {}, sessions: [], toolkit: [], guides: [] };
|
|
3018
|
+
function CourseAdminPanel({ ctx, courseId }) {
|
|
3019
|
+
const path = `/api/admin/courses/${encodeURIComponent(courseId)}`;
|
|
3020
|
+
const view = useAdminResource(ctx.getToken, path);
|
|
3021
|
+
const [draft, setDraft] = useState27("");
|
|
3022
|
+
const [status, setStatus] = useState27(null);
|
|
3023
|
+
useEffect12(() => {
|
|
3024
|
+
const course2 = view.data?.course;
|
|
3025
|
+
const { enrolledCount: _e, revision: _r, updatedAt: _u, updatedBy: _b, calendarEventId: _c, meetUrl: _m, ...settings } = course2 ?? EXAMPLE;
|
|
3026
|
+
setDraft(JSON.stringify(settings, null, 2));
|
|
3027
|
+
}, [view.data?.course?.revision]);
|
|
3028
|
+
const run = async (target, init, done) => {
|
|
3029
|
+
try {
|
|
3030
|
+
await adminFetch(ctx.getToken, target, init);
|
|
3031
|
+
setStatus(done);
|
|
3032
|
+
view.refresh();
|
|
3033
|
+
} catch (error) {
|
|
3034
|
+
const errors = error.errors;
|
|
3035
|
+
setStatus(errors?.length ? errors.join("; ") : error instanceof Error ? error.message : String(error));
|
|
3036
|
+
}
|
|
3037
|
+
};
|
|
3038
|
+
const save = () => {
|
|
3039
|
+
let course2;
|
|
3040
|
+
try {
|
|
3041
|
+
course2 = JSON.parse(draft);
|
|
3042
|
+
} catch {
|
|
3043
|
+
setStatus("Settings must be valid JSON");
|
|
3044
|
+
return;
|
|
3045
|
+
}
|
|
3046
|
+
void run(path, { method: "PUT", body: JSON.stringify({ course: course2, expectedRevision: Number(view.data?.course?.revision ?? 0) }) }, "Saved");
|
|
3047
|
+
};
|
|
3048
|
+
const download = async () => {
|
|
3049
|
+
const token = await ctx.getToken();
|
|
3050
|
+
const res = await fetch(`${path}/roster.csv`, { headers: token ? { authorization: `Bearer ${token}` } : {} });
|
|
3051
|
+
if (!res.ok) {
|
|
3052
|
+
setStatus("Export failed");
|
|
3053
|
+
return;
|
|
3054
|
+
}
|
|
3055
|
+
const url = URL.createObjectURL(await res.blob());
|
|
3056
|
+
Object.assign(document.createElement("a"), { href: url, download: `${courseId}-roster.csv` }).click();
|
|
3057
|
+
URL.revokeObjectURL(url);
|
|
3058
|
+
};
|
|
3059
|
+
const course = view.data?.course;
|
|
3060
|
+
const move = (memberId, action, label) => /* @__PURE__ */ jsx32(
|
|
3061
|
+
"button",
|
|
3062
|
+
{
|
|
3063
|
+
className: "btn secondary mini",
|
|
3064
|
+
type: "button",
|
|
3065
|
+
onClick: () => void run(`${path}/roster/${encodeURIComponent(String(memberId))}/${action}`, { method: "POST" }, `${label} done`),
|
|
3066
|
+
children: label
|
|
3067
|
+
}
|
|
3068
|
+
);
|
|
3069
|
+
return /* @__PURE__ */ jsxs30(Panel, { children: [
|
|
3070
|
+
/* @__PURE__ */ jsxs30("div", { className: "card-label", children: [
|
|
3071
|
+
"Course \xB7 ",
|
|
3072
|
+
courseId
|
|
3073
|
+
] }),
|
|
3074
|
+
status ? /* @__PURE__ */ jsx32("p", { role: "status", children: status }) : null,
|
|
3075
|
+
course ? /* @__PURE__ */ jsxs30("p", { className: "meeting-note", children: [
|
|
3076
|
+
String(course.title),
|
|
3077
|
+
" \xB7 ",
|
|
3078
|
+
view.data?.seatsLeft,
|
|
3079
|
+
" of ",
|
|
3080
|
+
String(course.capacity),
|
|
3081
|
+
" seats left \xB7",
|
|
3082
|
+
course.calendarEventId ? " calendar event created" : " no calendar event yet"
|
|
3083
|
+
] }) : /* @__PURE__ */ jsx32("p", { className: "meeting-note", children: "No settings saved yet." }),
|
|
3084
|
+
course && !course.calendarEventId ? /* @__PURE__ */ jsx32("button", { className: "btn primary mini", type: "button", onClick: () => void run(`${path}/calendar-event`, { method: "POST" }, "Calendar event created"), children: "Create calendar event" }) : null,
|
|
3085
|
+
course ? /* @__PURE__ */ jsx32("button", { className: "btn secondary mini", type: "button", onClick: () => void download(), children: "Export roster (CSV)" }) : null,
|
|
3086
|
+
/* @__PURE__ */ jsx32("h3", { children: "Enrolled" }),
|
|
3087
|
+
/* @__PURE__ */ jsx32("ul", { children: (view.data?.enrolled ?? []).map((row) => /* @__PURE__ */ jsxs30("li", { children: [
|
|
3088
|
+
String(row.email),
|
|
3089
|
+
" ",
|
|
3090
|
+
row.status === "pending" ? "(inviting)" : "",
|
|
3091
|
+
" ",
|
|
3092
|
+
move(row.memberId, "remove", "Remove")
|
|
3093
|
+
] }, String(row.id))) }),
|
|
3094
|
+
/* @__PURE__ */ jsx32("h3", { children: "Waitlist" }),
|
|
3095
|
+
/* @__PURE__ */ jsx32("ol", { children: (view.data?.waitlist ?? []).map((row) => /* @__PURE__ */ jsxs30("li", { children: [
|
|
3096
|
+
String(row.email),
|
|
3097
|
+
" ",
|
|
3098
|
+
move(row.memberId, "promote", "Move up"),
|
|
3099
|
+
" ",
|
|
3100
|
+
move(row.memberId, "remove", "Remove")
|
|
3101
|
+
] }, String(row.id))) }),
|
|
3102
|
+
/* @__PURE__ */ jsx32("h3", { children: "Settings" }),
|
|
3103
|
+
/* @__PURE__ */ jsx32("p", { className: "meeting-note", children: "Sessions, materials (a material without a link stays hidden), toolkit, guides, seat count and sign-up close. Capacity cannot drop below seats taken." }),
|
|
3104
|
+
/* @__PURE__ */ jsxs30("label", { className: "field", children: [
|
|
3105
|
+
/* @__PURE__ */ jsx32("span", { children: "Course settings (JSON)" }),
|
|
3106
|
+
/* @__PURE__ */ jsx32("textarea", { rows: 18, value: draft, onInput: (event) => setDraft(event.currentTarget.value) })
|
|
3107
|
+
] }),
|
|
3108
|
+
/* @__PURE__ */ jsx32("button", { className: "btn primary mini", type: "button", onClick: save, children: "Save settings" })
|
|
3109
|
+
] });
|
|
3110
|
+
}
|
|
3111
|
+
function CoursesAdminPanel({ ctx }) {
|
|
3112
|
+
const list = useAdminResource(ctx.getToken, "/api/admin/courses");
|
|
3113
|
+
const [newId, setNewId] = useState27("");
|
|
3114
|
+
const [open, setOpen] = useState27(null);
|
|
3115
|
+
const ids = [.../* @__PURE__ */ new Set([...(list.data?.courses ?? []).map((row) => String(row.id)), ...open ? [open] : []])];
|
|
3116
|
+
return /* @__PURE__ */ jsxs30("div", { className: "chapter-admin-stack", "data-courses-admin": true, children: [
|
|
3117
|
+
ids.map((id) => /* @__PURE__ */ jsx32(CourseAdminPanel, { ctx, courseId: id }, id)),
|
|
3118
|
+
/* @__PURE__ */ jsxs30(Panel, { children: [
|
|
3119
|
+
/* @__PURE__ */ jsx32("div", { className: "card-label", children: "New course" }),
|
|
3120
|
+
/* @__PURE__ */ jsxs30("label", { className: "field", children: [
|
|
3121
|
+
/* @__PURE__ */ jsx32("span", { children: "Course id (lowercase slug)" }),
|
|
3122
|
+
/* @__PURE__ */ jsx32("input", { value: newId, onInput: (event) => setNewId(event.currentTarget.value.trim()) })
|
|
3123
|
+
] }),
|
|
3124
|
+
/* @__PURE__ */ jsx32("button", { className: "btn secondary mini", type: "button", disabled: !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(newId), onClick: () => setOpen(newId), children: "Start" })
|
|
3125
|
+
] })
|
|
3126
|
+
] });
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
// src/ui/admin-member-referrals.tsx
|
|
3130
|
+
import { useState as useState28 } from "preact/hooks";
|
|
3131
|
+
import { Select as Select11 } from "@odla-ai/ui/components";
|
|
3132
|
+
import { jsx as jsx33, jsxs as jsxs31 } from "preact/jsx-runtime";
|
|
3133
|
+
function ReferralsAdminPanel({ ctx }) {
|
|
3134
|
+
const view = useAdminResource(ctx.getToken, "/api/admin/referrals");
|
|
3135
|
+
const [status, setStatus] = useState28(null);
|
|
3136
|
+
const run = async (path, done) => {
|
|
3137
|
+
try {
|
|
3138
|
+
await adminFetch(ctx.getToken, path, { method: "POST" });
|
|
3139
|
+
setStatus(done);
|
|
3140
|
+
view.refresh();
|
|
3141
|
+
} catch (error) {
|
|
3142
|
+
setStatus(error instanceof Error ? error.message : String(error));
|
|
3143
|
+
}
|
|
3144
|
+
};
|
|
3145
|
+
const data = view.data;
|
|
3146
|
+
return /* @__PURE__ */ jsxs31(Panel, { children: [
|
|
3147
|
+
/* @__PURE__ */ jsx33("div", { className: "card-label", children: "Referrals" }),
|
|
3148
|
+
status ? /* @__PURE__ */ jsx33("p", { role: "status", children: status }) : null,
|
|
3149
|
+
/* @__PURE__ */ jsx33("button", { className: "btn secondary mini", type: "button", onClick: () => void run("/api/admin/referrals/reconcile", "Reconciled approvals and lapses"), children: "Reconcile credit" }),
|
|
3150
|
+
/* @__PURE__ */ jsx33("h3", { children: "Top referrers" }),
|
|
3151
|
+
/* @__PURE__ */ jsx33("ol", { children: (data?.topReferrers ?? []).map((row) => /* @__PURE__ */ jsxs31("li", { children: [
|
|
3152
|
+
row.name ?? row.memberId,
|
|
3153
|
+
": ",
|
|
3154
|
+
row.joins,
|
|
3155
|
+
" joined, ",
|
|
3156
|
+
row.applications,
|
|
3157
|
+
" applied"
|
|
3158
|
+
] }, row.memberId)) }),
|
|
3159
|
+
/* @__PURE__ */ jsxs31("table", { children: [
|
|
3160
|
+
/* @__PURE__ */ jsx33("thead", { children: /* @__PURE__ */ jsxs31("tr", { children: [
|
|
3161
|
+
/* @__PURE__ */ jsx33("th", { children: "Member" }),
|
|
3162
|
+
/* @__PURE__ */ jsx33("th", { children: "Codes" }),
|
|
3163
|
+
/* @__PURE__ */ jsx33("th", { children: "Clicks" }),
|
|
3164
|
+
/* @__PURE__ */ jsx33("th", { children: "Applied" }),
|
|
3165
|
+
/* @__PURE__ */ jsx33("th", { children: "Joined" }),
|
|
3166
|
+
/* @__PURE__ */ jsx33("th", {})
|
|
3167
|
+
] }) }),
|
|
3168
|
+
/* @__PURE__ */ jsx33("tbody", { children: (data?.referrers ?? []).map((row) => /* @__PURE__ */ jsxs31("tr", { children: [
|
|
3169
|
+
/* @__PURE__ */ jsx33("td", { children: row.name ?? row.memberId }),
|
|
3170
|
+
/* @__PURE__ */ jsx33("td", { children: row.codes.join(", ") }),
|
|
3171
|
+
/* @__PURE__ */ jsx33("td", { children: row.clicks }),
|
|
3172
|
+
/* @__PURE__ */ jsx33("td", { children: row.applications }),
|
|
3173
|
+
/* @__PURE__ */ jsx33("td", { children: row.joins }),
|
|
3174
|
+
/* @__PURE__ */ jsx33("td", { children: /* @__PURE__ */ jsx33(
|
|
3175
|
+
"button",
|
|
3176
|
+
{
|
|
3177
|
+
className: "btn secondary mini",
|
|
3178
|
+
type: "button",
|
|
3179
|
+
onClick: () => void run(`/api/admin/referrals/${encodeURIComponent(row.memberId)}/reissue`, `Issued a new code for ${row.name ?? row.memberId}`),
|
|
3180
|
+
children: "Deactivate and reissue"
|
|
3181
|
+
}
|
|
3182
|
+
) })
|
|
3183
|
+
] }, row.memberId)) })
|
|
3184
|
+
] }),
|
|
3185
|
+
/* @__PURE__ */ jsx33("h3", { children: "How people found us" }),
|
|
3186
|
+
/* @__PURE__ */ jsxs31("table", { children: [
|
|
3187
|
+
/* @__PURE__ */ jsx33("thead", { children: /* @__PURE__ */ jsxs31("tr", { children: [
|
|
3188
|
+
/* @__PURE__ */ jsx33("th", { children: "Person" }),
|
|
3189
|
+
/* @__PURE__ */ jsx33("th", { children: "Referred by" }),
|
|
3190
|
+
/* @__PURE__ */ jsx33("th", { children: "Introduced by" })
|
|
3191
|
+
] }) }),
|
|
3192
|
+
/* @__PURE__ */ jsx33("tbody", { children: (data?.people ?? []).map((row) => {
|
|
3193
|
+
const referred = row.referredBy;
|
|
3194
|
+
const introduced = row.introducedBy;
|
|
3195
|
+
return /* @__PURE__ */ jsxs31("tr", { children: [
|
|
3196
|
+
/* @__PURE__ */ jsx33("td", { children: String(row.name ?? row.memberId) }),
|
|
3197
|
+
/* @__PURE__ */ jsx33("td", { children: referred?.name ?? "" }),
|
|
3198
|
+
/* @__PURE__ */ jsx33("td", { children: introduced ? `${introduced.text}${introduced.name ? ` (matched: ${introduced.name})` : " (unmatched)"}` : "" })
|
|
3199
|
+
] }, String(row.memberId));
|
|
3200
|
+
}) })
|
|
3201
|
+
] })
|
|
3202
|
+
] });
|
|
3203
|
+
}
|
|
3204
|
+
function CreditLedgerPanel({ ctx }) {
|
|
3205
|
+
const view = useAdminResource(ctx.getToken, "/api/admin/referral-ledger");
|
|
3206
|
+
const [form, setForm] = useState28({ referrerMemberId: "", status: "void", valueCents: "", reason: "" });
|
|
3207
|
+
const [status, setStatus] = useState28(null);
|
|
3208
|
+
const add = async () => {
|
|
3209
|
+
try {
|
|
3210
|
+
await adminFetch(ctx.getToken, "/api/admin/referral-ledger", { method: "POST", body: JSON.stringify({ ...form, valueCents: Math.round(Number(form.valueCents) * 100) }) });
|
|
3211
|
+
setStatus("Row added");
|
|
3212
|
+
setForm({ ...form, valueCents: "", reason: "" });
|
|
3213
|
+
view.refresh();
|
|
3214
|
+
} catch (error) {
|
|
3215
|
+
setStatus(error instanceof Error ? error.message : String(error));
|
|
3216
|
+
}
|
|
3217
|
+
};
|
|
3218
|
+
const money6 = (cents) => typeof cents === "number" ? fmtMoney(cents) : "";
|
|
3219
|
+
const set = (key) => (event) => setForm({ ...form, [key]: event.currentTarget.value });
|
|
3220
|
+
return /* @__PURE__ */ jsxs31(Panel, { children: [
|
|
3221
|
+
/* @__PURE__ */ jsx33("div", { className: "card-label", children: "Credit ledger" }),
|
|
3222
|
+
/* @__PURE__ */ jsxs31("table", { children: [
|
|
3223
|
+
/* @__PURE__ */ jsx33("thead", { children: /* @__PURE__ */ jsxs31("tr", { children: [
|
|
3224
|
+
/* @__PURE__ */ jsx33("th", { children: "Member" }),
|
|
3225
|
+
/* @__PURE__ */ jsx33("th", { children: "Earned" }),
|
|
3226
|
+
/* @__PURE__ */ jsx33("th", { children: "Applied" }),
|
|
3227
|
+
/* @__PURE__ */ jsx33("th", { children: "Carried forward" }),
|
|
3228
|
+
/* @__PURE__ */ jsx33("th", { children: "Void" }),
|
|
3229
|
+
/* @__PURE__ */ jsx33("th", { children: "Balance" }),
|
|
3230
|
+
/* @__PURE__ */ jsx33("th", { children: "Next year's dues" })
|
|
3231
|
+
] }) }),
|
|
3232
|
+
/* @__PURE__ */ jsx33("tbody", { children: (view.data?.members ?? []).map((row) => /* @__PURE__ */ jsxs31("tr", { children: [
|
|
3233
|
+
/* @__PURE__ */ jsx33("td", { children: row.name ?? row.memberId }),
|
|
3234
|
+
/* @__PURE__ */ jsx33("td", { children: money6(row.totals.earnedCents) }),
|
|
3235
|
+
/* @__PURE__ */ jsx33("td", { children: money6(row.totals.appliedCents) }),
|
|
3236
|
+
/* @__PURE__ */ jsx33("td", { children: money6(row.totals.carriedForwardCents) }),
|
|
3237
|
+
/* @__PURE__ */ jsx33("td", { children: money6(row.totals.voidedCents) }),
|
|
3238
|
+
/* @__PURE__ */ jsx33("td", { children: money6(row.totals.balanceCents) }),
|
|
3239
|
+
/* @__PURE__ */ jsx33("td", { children: row.projectedDuesCents === null ? "" : `${money6(row.projectedDuesCents)} (of ${money6(row.renewalCents)})` })
|
|
3240
|
+
] }, row.memberId)) })
|
|
3241
|
+
] }),
|
|
3242
|
+
/* @__PURE__ */ jsx33("h3", { children: "Add a row" }),
|
|
3243
|
+
/* @__PURE__ */ jsx33("p", { className: "meeting-note", children: "Rows are never edited. Void or adjust by adding a row with a reason." }),
|
|
3244
|
+
/* @__PURE__ */ jsxs31("label", { className: "field", children: [
|
|
3245
|
+
/* @__PURE__ */ jsx33("span", { children: "Member id" }),
|
|
3246
|
+
/* @__PURE__ */ jsx33("input", { value: form.referrerMemberId, onInput: set("referrerMemberId") })
|
|
3247
|
+
] }),
|
|
3248
|
+
/* @__PURE__ */ jsxs31("label", { className: "field", children: [
|
|
3249
|
+
/* @__PURE__ */ jsx33("span", { children: "Kind" }),
|
|
3250
|
+
/* @__PURE__ */ jsxs31(Select11, { value: form.status, onChange: set("status"), children: [
|
|
3251
|
+
/* @__PURE__ */ jsx33("option", { value: "void", children: "Void" }),
|
|
3252
|
+
/* @__PURE__ */ jsx33("option", { value: "earned", children: "Credit (adjustment)" }),
|
|
3253
|
+
/* @__PURE__ */ jsx33("option", { value: "applied", children: "Applied" }),
|
|
3254
|
+
/* @__PURE__ */ jsx33("option", { value: "carried_forward", children: "Carried forward" })
|
|
3255
|
+
] })
|
|
3256
|
+
] }),
|
|
3257
|
+
/* @__PURE__ */ jsxs31("label", { className: "field", children: [
|
|
3258
|
+
/* @__PURE__ */ jsx33("span", { children: "Amount" }),
|
|
3259
|
+
/* @__PURE__ */ jsx33("input", { inputMode: "decimal", value: form.valueCents, onInput: set("valueCents") })
|
|
3260
|
+
] }),
|
|
3261
|
+
/* @__PURE__ */ jsxs31("label", { className: "field", children: [
|
|
3262
|
+
/* @__PURE__ */ jsx33("span", { children: "Reason" }),
|
|
3263
|
+
/* @__PURE__ */ jsx33("input", { value: form.reason, onInput: set("reason") })
|
|
3264
|
+
] }),
|
|
3265
|
+
/* @__PURE__ */ jsx33("button", { className: "btn primary mini", type: "button", disabled: !form.reason.trim() || !form.referrerMemberId, onClick: () => void add(), children: "Add row" }),
|
|
3266
|
+
status ? /* @__PURE__ */ jsx33("p", { role: "status", children: status }) : null,
|
|
3267
|
+
/* @__PURE__ */ jsx33("h3", { children: "Rows" }),
|
|
3268
|
+
/* @__PURE__ */ jsx33("ul", { className: "meeting-note", children: (view.data?.rows ?? []).map((row) => /* @__PURE__ */ jsxs31("li", { children: [
|
|
3269
|
+
new Date(Number(row.at)).toLocaleDateString("en-US"),
|
|
3270
|
+
" \xB7 ",
|
|
3271
|
+
String(row.referrerMemberId),
|
|
3272
|
+
" \xB7 ",
|
|
3273
|
+
String(row.status),
|
|
3274
|
+
" ",
|
|
3275
|
+
money6(Number(row.valueCents)),
|
|
3276
|
+
row.reason ? ` \xB7 ${String(row.reason)}` : "",
|
|
3277
|
+
row.actor ? ` \xB7 ${String(row.actor)}` : ""
|
|
3278
|
+
] }, String(row.id))) })
|
|
3279
|
+
] });
|
|
3280
|
+
}
|
|
3281
|
+
|
|
3282
|
+
// src/ui/admin-member-portal.tsx
|
|
3283
|
+
import { jsx as jsx34, jsxs as jsxs32 } from "preact/jsx-runtime";
|
|
3013
3284
|
var when2 = (at) => typeof at === "number" ? new Date(at).toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric" }) : "";
|
|
3014
3285
|
function HubRosterPanel({ ctx }) {
|
|
3015
3286
|
const roster = useAdminResource(ctx.getToken, "/api/admin/hub-members");
|
|
3016
|
-
const [email, setEmail] =
|
|
3017
|
-
const [status, setStatus] =
|
|
3287
|
+
const [email, setEmail] = useState29("");
|
|
3288
|
+
const [status, setStatus] = useState29(null);
|
|
3018
3289
|
const act = async (path, init, done) => {
|
|
3019
3290
|
try {
|
|
3020
3291
|
await adminFetch(ctx.getToken, path, init);
|
|
@@ -3024,39 +3295,39 @@ function HubRosterPanel({ ctx }) {
|
|
|
3024
3295
|
setStatus(error instanceof Error ? error.message : String(error));
|
|
3025
3296
|
}
|
|
3026
3297
|
};
|
|
3027
|
-
return /* @__PURE__ */
|
|
3028
|
-
/* @__PURE__ */
|
|
3029
|
-
/* @__PURE__ */
|
|
3030
|
-
/* @__PURE__ */
|
|
3298
|
+
return /* @__PURE__ */ jsxs32(Panel, { children: [
|
|
3299
|
+
/* @__PURE__ */ jsx34("div", { className: "card-label", children: "Hub members" }),
|
|
3300
|
+
/* @__PURE__ */ jsx34("p", { className: "meeting-note", children: "Members see the portal and its all-members pages. Granting membership never grants admin access." }),
|
|
3301
|
+
/* @__PURE__ */ jsxs32("form", { onSubmit: (event) => {
|
|
3031
3302
|
event.preventDefault();
|
|
3032
3303
|
void act("/api/admin/hub-members", { method: "POST", body: JSON.stringify({ email }) }, `Granted ${email}`).then(() => setEmail(""));
|
|
3033
3304
|
}, children: [
|
|
3034
|
-
/* @__PURE__ */
|
|
3035
|
-
/* @__PURE__ */
|
|
3036
|
-
/* @__PURE__ */
|
|
3305
|
+
/* @__PURE__ */ jsxs32("label", { className: "field", children: [
|
|
3306
|
+
/* @__PURE__ */ jsx34("span", { children: "Email" }),
|
|
3307
|
+
/* @__PURE__ */ jsx34("input", { type: "email", required: true, value: email, onInput: (event) => setEmail(event.currentTarget.value) })
|
|
3037
3308
|
] }),
|
|
3038
|
-
/* @__PURE__ */
|
|
3309
|
+
/* @__PURE__ */ jsx34("button", { className: "btn primary", type: "submit", children: "Grant member access" })
|
|
3039
3310
|
] }),
|
|
3040
|
-
status ? /* @__PURE__ */
|
|
3041
|
-
/* @__PURE__ */
|
|
3042
|
-
/* @__PURE__ */
|
|
3043
|
-
/* @__PURE__ */
|
|
3044
|
-
/* @__PURE__ */
|
|
3045
|
-
/* @__PURE__ */
|
|
3046
|
-
/* @__PURE__ */
|
|
3311
|
+
status ? /* @__PURE__ */ jsx34("p", { role: "status", children: status }) : null,
|
|
3312
|
+
/* @__PURE__ */ jsxs32("table", { children: [
|
|
3313
|
+
/* @__PURE__ */ jsx34("thead", { children: /* @__PURE__ */ jsxs32("tr", { children: [
|
|
3314
|
+
/* @__PURE__ */ jsx34("th", { children: "Email" }),
|
|
3315
|
+
/* @__PURE__ */ jsx34("th", { children: "Status" }),
|
|
3316
|
+
/* @__PURE__ */ jsx34("th", { children: "Granted" }),
|
|
3317
|
+
/* @__PURE__ */ jsx34("th", {})
|
|
3047
3318
|
] }) }),
|
|
3048
|
-
/* @__PURE__ */
|
|
3049
|
-
/* @__PURE__ */
|
|
3050
|
-
/* @__PURE__ */
|
|
3319
|
+
/* @__PURE__ */ jsx34("tbody", { children: (roster.data?.members ?? []).map((member) => /* @__PURE__ */ jsxs32("tr", { children: [
|
|
3320
|
+
/* @__PURE__ */ jsx34("td", { children: String(member.email) }),
|
|
3321
|
+
/* @__PURE__ */ jsxs32("td", { children: [
|
|
3051
3322
|
String(member.status),
|
|
3052
3323
|
member.revokedBy ? ` by ${String(member.revokedBy)}` : ""
|
|
3053
3324
|
] }),
|
|
3054
|
-
/* @__PURE__ */
|
|
3325
|
+
/* @__PURE__ */ jsxs32("td", { children: [
|
|
3055
3326
|
when2(member.grantedAt),
|
|
3056
3327
|
" by ",
|
|
3057
3328
|
String(member.grantedBy)
|
|
3058
3329
|
] }),
|
|
3059
|
-
/* @__PURE__ */
|
|
3330
|
+
/* @__PURE__ */ jsx34("td", { children: member.status === "active" ? /* @__PURE__ */ jsx34("button", { className: "btn secondary mini", type: "button", onClick: () => void act(`/api/admin/hub-members/${encodeURIComponent(String(member.id))}`, { method: "DELETE" }, `Revoked ${String(member.email)}`), children: "Revoke" }) : /* @__PURE__ */ jsx34("button", { className: "btn secondary mini", type: "button", onClick: () => void act("/api/admin/hub-members", { method: "POST", body: JSON.stringify({ email: member.email }) }, `Granted ${String(member.email)}`), children: "Grant again" }) })
|
|
3060
3331
|
] }, String(member.id))) })
|
|
3061
3332
|
] })
|
|
3062
3333
|
] });
|
|
@@ -3069,8 +3340,8 @@ var KIND_LABELS = {
|
|
|
3069
3340
|
};
|
|
3070
3341
|
function PortalReviewPanel({ ctx }) {
|
|
3071
3342
|
const queue = useAdminResource(ctx.getToken, "/api/admin/portal-review");
|
|
3072
|
-
const [decisions, setDecisions] =
|
|
3073
|
-
const [status, setStatus] =
|
|
3343
|
+
const [decisions, setDecisions] = useState29({});
|
|
3344
|
+
const [status, setStatus] = useState29(null);
|
|
3074
3345
|
const resolve2 = async (id) => {
|
|
3075
3346
|
try {
|
|
3076
3347
|
await adminFetch(ctx.getToken, `/api/admin/portal-review/${encodeURIComponent(id)}`, { method: "POST", body: JSON.stringify({ decision: decisions[id] ?? "" }) });
|
|
@@ -3081,29 +3352,29 @@ function PortalReviewPanel({ ctx }) {
|
|
|
3081
3352
|
}
|
|
3082
3353
|
};
|
|
3083
3354
|
const items = queue.data?.items ?? [];
|
|
3084
|
-
return /* @__PURE__ */
|
|
3085
|
-
/* @__PURE__ */
|
|
3355
|
+
return /* @__PURE__ */ jsxs32(Panel, { children: [
|
|
3356
|
+
/* @__PURE__ */ jsxs32("div", { className: "card-label", children: [
|
|
3086
3357
|
"Review queue \xB7 ",
|
|
3087
3358
|
items.length,
|
|
3088
3359
|
" open"
|
|
3089
3360
|
] }),
|
|
3090
|
-
status ? /* @__PURE__ */
|
|
3091
|
-
items.length === 0 ? /* @__PURE__ */
|
|
3361
|
+
status ? /* @__PURE__ */ jsx34("p", { role: "status", children: status }) : null,
|
|
3362
|
+
items.length === 0 ? /* @__PURE__ */ jsx34("p", { className: "meeting-note", children: "Nothing to review." }) : items.map((item) => {
|
|
3092
3363
|
const id = String(item.id);
|
|
3093
|
-
return /* @__PURE__ */
|
|
3094
|
-
/* @__PURE__ */
|
|
3095
|
-
/* @__PURE__ */
|
|
3096
|
-
/* @__PURE__ */
|
|
3364
|
+
return /* @__PURE__ */ jsxs32("div", { className: "card", "data-review-item": id, children: [
|
|
3365
|
+
/* @__PURE__ */ jsx34("strong", { children: KIND_LABELS[String(item.kind)] ?? String(item.kind) }),
|
|
3366
|
+
/* @__PURE__ */ jsx34("pre", { style: { whiteSpace: "pre-wrap" }, children: JSON.stringify(item.detail) }),
|
|
3367
|
+
/* @__PURE__ */ jsxs32("div", { className: "meeting-note", children: [
|
|
3097
3368
|
"Member ",
|
|
3098
3369
|
String(item.memberId ?? ""),
|
|
3099
3370
|
" \xB7 ",
|
|
3100
3371
|
when2(item.createdAt)
|
|
3101
3372
|
] }),
|
|
3102
|
-
/* @__PURE__ */
|
|
3103
|
-
/* @__PURE__ */
|
|
3104
|
-
/* @__PURE__ */
|
|
3373
|
+
/* @__PURE__ */ jsxs32("label", { className: "field", children: [
|
|
3374
|
+
/* @__PURE__ */ jsx34("span", { children: "Decision" }),
|
|
3375
|
+
/* @__PURE__ */ jsx34("input", { value: decisions[id] ?? "", onInput: (event) => setDecisions({ ...decisions, [id]: event.currentTarget.value }) })
|
|
3105
3376
|
] }),
|
|
3106
|
-
/* @__PURE__ */
|
|
3377
|
+
/* @__PURE__ */ jsx34("button", { className: "btn primary mini", type: "button", disabled: !(decisions[id] ?? "").trim(), onClick: () => void resolve2(id), children: "Resolve" })
|
|
3107
3378
|
] }, id);
|
|
3108
3379
|
})
|
|
3109
3380
|
] });
|
|
@@ -3112,15 +3383,18 @@ function memberPortalSection(chapter) {
|
|
|
3112
3383
|
return {
|
|
3113
3384
|
id: "member-portal",
|
|
3114
3385
|
label: "Member portal",
|
|
3115
|
-
render: (ctx) => /* @__PURE__ */
|
|
3116
|
-
chapter.mode === "hub" ? /* @__PURE__ */
|
|
3117
|
-
chapter.memberPortal ? /* @__PURE__ */
|
|
3386
|
+
render: (ctx) => /* @__PURE__ */ jsxs32("div", { className: "chapter-admin-stack", children: [
|
|
3387
|
+
chapter.mode === "hub" ? /* @__PURE__ */ jsx34(HubRosterPanel, { ctx }) : null,
|
|
3388
|
+
chapter.memberPortal ? /* @__PURE__ */ jsx34(PortalReviewPanel, { ctx }) : null,
|
|
3389
|
+
chapter.memberPortal?.courses ? /* @__PURE__ */ jsx34(CoursesAdminPanel, { ctx }) : null,
|
|
3390
|
+
chapter.memberPortal?.referrals ? /* @__PURE__ */ jsx34(ReferralsAdminPanel, { ctx }) : null,
|
|
3391
|
+
chapter.memberPortal?.referrals?.creditCents ? /* @__PURE__ */ jsx34(CreditLedgerPanel, { ctx }) : null
|
|
3118
3392
|
] })
|
|
3119
3393
|
};
|
|
3120
3394
|
}
|
|
3121
3395
|
|
|
3122
3396
|
// src/ui/admin-settings-workspace.tsx
|
|
3123
|
-
import { jsx as
|
|
3397
|
+
import { jsx as jsx35 } from "preact/jsx-runtime";
|
|
3124
3398
|
var viewContext = (ctx, viewId, active) => {
|
|
3125
3399
|
const route = { workspaceId: ctx.route.workspaceId, viewId, ...active && ctx.route.recordId ? { recordId: ctx.route.recordId } : {}, ...active && ctx.route.detailTab ? { detailTab: ctx.route.detailTab } : {} };
|
|
3126
3400
|
const targetFromView = (target) => {
|
|
@@ -3138,7 +3412,7 @@ function SettingsWorkspace({ chapter, ctx }) {
|
|
|
3138
3412
|
const email = emailSection({ label: copy.workspaces.email });
|
|
3139
3413
|
const content = memberContentSection();
|
|
3140
3414
|
const library = builderLibrarySection();
|
|
3141
|
-
return /* @__PURE__ */
|
|
3415
|
+
return /* @__PURE__ */ jsx35(Tabs2, { ariaLabel: copy.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
|
|
3142
3416
|
{ value: "calendar", label: copy.workspaces.calendar, href: ctx.href({ viewId: "calendar", recordId: null, detailTab: null }), panel: calendar.render(viewContext(ctx, "calendar", active === "calendar")) },
|
|
3143
3417
|
{ value: "email", label: copy.workspaces.email, href: ctx.href({ viewId: "email", recordId: null, detailTab: null }), panel: email.render(viewContext(ctx, "email", active === "email")) },
|
|
3144
3418
|
...chapter.memberContent ? [{ value: "member-content", label: "Member content", href: ctx.href({ viewId: "member-content", recordId: null, detailTab: null }), panel: content.render(viewContext(ctx, "member-content", active === "member-content")) }] : [],
|
|
@@ -3157,7 +3431,7 @@ function LeaderSettingsWorkspace({ chapter, ctx }) {
|
|
|
3157
3431
|
const library = builderLibrarySection();
|
|
3158
3432
|
const members = Boolean(chapter.memberPortal || chapter.memberContent);
|
|
3159
3433
|
const active = ctx.route.viewId === "builder-library" && chapter.builderLibrary ? "builder-library" : ctx.route.viewId === "member-content" && chapter.memberContent ? "member-content" : ctx.route.viewId === "member-portal" && members ? "member-portal" : "email";
|
|
3160
|
-
return /* @__PURE__ */
|
|
3434
|
+
return /* @__PURE__ */ jsx35(Tabs2, { ariaLabel: chapter.copy.admin.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
|
|
3161
3435
|
{ value: "email", label: chapter.copy.admin.workspaces.email, href: ctx.href({ viewId: "email", recordId: null, detailTab: null }), panel: email.render(viewContext(ctx, "email", active === "email")) },
|
|
3162
3436
|
...chapter.memberContent ? [{ value: "member-content", label: "Member content", href: ctx.href({ viewId: "member-content", recordId: null, detailTab: null }), panel: memberContentSection().render(viewContext(ctx, "member-content", active === "member-content")) }] : [],
|
|
3163
3437
|
...members ? [portalTab(chapter, ctx, active)] : [],
|
|
@@ -3166,7 +3440,7 @@ function LeaderSettingsWorkspace({ chapter, ctx }) {
|
|
|
3166
3440
|
}
|
|
3167
3441
|
|
|
3168
3442
|
// src/ui/admin-workspaces.tsx
|
|
3169
|
-
import { jsx as
|
|
3443
|
+
import { jsx as jsx36 } from "preact/jsx-runtime";
|
|
3170
3444
|
var adminViewContext = (ctx, viewId, active) => {
|
|
3171
3445
|
const route = {
|
|
3172
3446
|
workspaceId: ctx.route.workspaceId,
|
|
@@ -3192,7 +3466,7 @@ function DashboardWorkspace({ chapter, ctx }) {
|
|
|
3192
3466
|
const active = ctx.route.viewId === "billing" ? "billing" : "overview";
|
|
3193
3467
|
const overview = dashboardSection({ id: "overview", label: copy.workspaces.overview });
|
|
3194
3468
|
const billing = billingSection({ label: copy.workspaces.billing });
|
|
3195
|
-
return /* @__PURE__ */
|
|
3469
|
+
return /* @__PURE__ */ jsx36(
|
|
3196
3470
|
Tabs3,
|
|
3197
3471
|
{
|
|
3198
3472
|
ariaLabel: copy.workspaces.dashboardViewsLabel,
|
|
@@ -3220,7 +3494,7 @@ function PeopleWorkspace({ chapter, ctx }) {
|
|
|
3220
3494
|
const fallback = types[0]?.[0] ?? "person";
|
|
3221
3495
|
const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
|
|
3222
3496
|
const networkSharing = chapter.network.targets.length > 0;
|
|
3223
|
-
return /* @__PURE__ */
|
|
3497
|
+
return /* @__PURE__ */ jsx36(
|
|
3224
3498
|
Tabs3,
|
|
3225
3499
|
{
|
|
3226
3500
|
ariaLabel: chapter.copy.admin.workspaces.collectionsLabel,
|
|
@@ -3251,8 +3525,8 @@ function PortfolioWorkspace({ chapter, ctx }) {
|
|
|
3251
3525
|
const types = Object.entries(chapter.crm.config.types).filter(([, def]) => def.workspace === "portfolio");
|
|
3252
3526
|
const fallback = types[0]?.[0] ?? "";
|
|
3253
3527
|
const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
|
|
3254
|
-
if (!active) return /* @__PURE__ */
|
|
3255
|
-
return /* @__PURE__ */
|
|
3528
|
+
if (!active) return /* @__PURE__ */ jsx36(LeaderNetworkOverview, { ctx });
|
|
3529
|
+
return /* @__PURE__ */ jsx36(
|
|
3256
3530
|
Tabs3,
|
|
3257
3531
|
{
|
|
3258
3532
|
ariaLabel: copy.workspaces.portfolioViewsLabel,
|
|
@@ -3276,7 +3550,7 @@ function PortfolioWorkspace({ chapter, ctx }) {
|
|
|
3276
3550
|
);
|
|
3277
3551
|
}
|
|
3278
3552
|
function LeaderDashboardWorkspace({ chapter, ctx }) {
|
|
3279
|
-
return /* @__PURE__ */
|
|
3553
|
+
return /* @__PURE__ */ jsx36(
|
|
3280
3554
|
Tabs3,
|
|
3281
3555
|
{
|
|
3282
3556
|
ariaLabel: chapter.copy.admin.workspaces.dashboardViewsLabel,
|
|
@@ -3286,7 +3560,7 @@ function LeaderDashboardWorkspace({ chapter, ctx }) {
|
|
|
3286
3560
|
value: "overview",
|
|
3287
3561
|
label: chapter.copy.admin.workspaces.overview,
|
|
3288
3562
|
href: ctx.href({ viewId: "overview", recordId: null, detailTab: null }),
|
|
3289
|
-
panel: /* @__PURE__ */
|
|
3563
|
+
panel: /* @__PURE__ */ jsx36(LeaderNetworkOverview, { ctx: adminViewContext(ctx, "overview", true) })
|
|
3290
3564
|
}]
|
|
3291
3565
|
}
|
|
3292
3566
|
);
|
|
@@ -3297,7 +3571,7 @@ function defaultAdminWorkspaces(chapter) {
|
|
|
3297
3571
|
id: "people",
|
|
3298
3572
|
label: copy.workspaces.people,
|
|
3299
3573
|
defaultViewId: Object.keys(chapter.crm.config.types)[0] ?? "person",
|
|
3300
|
-
render: (ctx) => /* @__PURE__ */
|
|
3574
|
+
render: (ctx) => /* @__PURE__ */ jsx36(PeopleWorkspace, { chapter, ctx })
|
|
3301
3575
|
};
|
|
3302
3576
|
if (chapter.mode === "hub" && chapter.network.targets.length === 0) return [people];
|
|
3303
3577
|
if (chapter.mode === "hub") {
|
|
@@ -3307,7 +3581,7 @@ function defaultAdminWorkspaces(chapter) {
|
|
|
3307
3581
|
id: "dashboard",
|
|
3308
3582
|
label: copy.workspaces.dashboard,
|
|
3309
3583
|
defaultViewId: "overview",
|
|
3310
|
-
render: (ctx) => /* @__PURE__ */
|
|
3584
|
+
render: (ctx) => /* @__PURE__ */ jsx36(LeaderDashboardWorkspace, { chapter, ctx })
|
|
3311
3585
|
},
|
|
3312
3586
|
networkRecordsWorkspace(chapter),
|
|
3313
3587
|
people,
|
|
@@ -3315,13 +3589,13 @@ function defaultAdminWorkspaces(chapter) {
|
|
|
3315
3589
|
id: "portfolio",
|
|
3316
3590
|
label: copy.workspaces.portfolio,
|
|
3317
3591
|
defaultViewId: portfolioTypes[0]?.[0],
|
|
3318
|
-
render: (ctx) => /* @__PURE__ */
|
|
3592
|
+
render: (ctx) => /* @__PURE__ */ jsx36(PortfolioWorkspace, { chapter, ctx })
|
|
3319
3593
|
},
|
|
3320
3594
|
{
|
|
3321
3595
|
id: "settings",
|
|
3322
3596
|
label: copy.workspaces.settings,
|
|
3323
3597
|
defaultViewId: "email",
|
|
3324
|
-
render: (ctx) => /* @__PURE__ */
|
|
3598
|
+
render: (ctx) => /* @__PURE__ */ jsx36(LeaderSettingsWorkspace, { chapter, ctx })
|
|
3325
3599
|
}
|
|
3326
3600
|
];
|
|
3327
3601
|
}
|
|
@@ -3330,7 +3604,7 @@ function defaultAdminWorkspaces(chapter) {
|
|
|
3330
3604
|
id: "dashboard",
|
|
3331
3605
|
label: copy.workspaces.dashboard,
|
|
3332
3606
|
defaultViewId: "overview",
|
|
3333
|
-
render: (ctx) => /* @__PURE__ */
|
|
3607
|
+
render: (ctx) => /* @__PURE__ */ jsx36(DashboardWorkspace, { chapter, ctx })
|
|
3334
3608
|
},
|
|
3335
3609
|
people,
|
|
3336
3610
|
admissionGrantsWorkspace(copy.workspaces.admission),
|
|
@@ -3338,17 +3612,17 @@ function defaultAdminWorkspaces(chapter) {
|
|
|
3338
3612
|
id: "settings",
|
|
3339
3613
|
label: copy.workspaces.settings,
|
|
3340
3614
|
defaultViewId: "calendar",
|
|
3341
|
-
render: (ctx) => /* @__PURE__ */
|
|
3615
|
+
render: (ctx) => /* @__PURE__ */ jsx36(SettingsWorkspace, { chapter, ctx })
|
|
3342
3616
|
}
|
|
3343
3617
|
];
|
|
3344
3618
|
}
|
|
3345
3619
|
|
|
3346
3620
|
// src/ui/admin-frame.tsx
|
|
3347
3621
|
import { ThemeScope as ThemeScope2 } from "@odla-ai/ui/components";
|
|
3348
|
-
import { jsx as
|
|
3622
|
+
import { jsx as jsx37, jsxs as jsxs33 } from "preact/jsx-runtime";
|
|
3349
3623
|
function AdminTheme(props) {
|
|
3350
3624
|
const brand = props.chapter?.brand;
|
|
3351
|
-
return /* @__PURE__ */
|
|
3625
|
+
return /* @__PURE__ */ jsx37(ChapterCopyProvider, { copy: props.chapter?.copy, children: /* @__PURE__ */ jsxs33(
|
|
3352
3626
|
ThemeScope2,
|
|
3353
3627
|
{
|
|
3354
3628
|
ref: props.scopeRef,
|
|
@@ -3357,7 +3631,7 @@ function AdminTheme(props) {
|
|
|
3357
3631
|
accent: brand?.accent,
|
|
3358
3632
|
colorScheme: brand?.colorScheme ?? "light",
|
|
3359
3633
|
children: [
|
|
3360
|
-
/* @__PURE__ */
|
|
3634
|
+
/* @__PURE__ */ jsx37(BrandStyle, { brand, selector: "[data-chapter-admin]" }),
|
|
3361
3635
|
props.children
|
|
3362
3636
|
]
|
|
3363
3637
|
}
|
|
@@ -3377,11 +3651,11 @@ function signInRedirect(basePath, workspaces) {
|
|
|
3377
3651
|
}
|
|
3378
3652
|
|
|
3379
3653
|
// src/ui/admin-appearance.ts
|
|
3380
|
-
import { useEffect as
|
|
3654
|
+
import { useEffect as useEffect13, useState as useState30 } from "preact/hooks";
|
|
3381
3655
|
import { clerkAppearanceFromTokens } from "@odla-ai/auth-clerk";
|
|
3382
3656
|
function useScopedClerkAppearance(scope) {
|
|
3383
|
-
const [appearance, setAppearance] =
|
|
3384
|
-
|
|
3657
|
+
const [appearance, setAppearance] = useState30();
|
|
3658
|
+
useEffect13(() => {
|
|
3385
3659
|
setAppearance(clerkAppearanceFromTokens(scope.current ?? void 0));
|
|
3386
3660
|
}, [scope]);
|
|
3387
3661
|
return appearance;
|
|
@@ -3412,7 +3686,7 @@ async function loadChapterAdminUser(adapter, apiBase, getToken) {
|
|
|
3412
3686
|
}
|
|
3413
3687
|
|
|
3414
3688
|
// src/ui/admin.tsx
|
|
3415
|
-
import { jsx as
|
|
3689
|
+
import { jsx as jsx38, jsxs as jsxs34 } from "preact/jsx-runtime";
|
|
3416
3690
|
function Authed(props) {
|
|
3417
3691
|
const copy = useChapterCopy().admin;
|
|
3418
3692
|
const {
|
|
@@ -3440,8 +3714,8 @@ function Authed(props) {
|
|
|
3440
3714
|
}),
|
|
3441
3715
|
[getToken, crmBasePath]
|
|
3442
3716
|
);
|
|
3443
|
-
const [state, setState] =
|
|
3444
|
-
|
|
3717
|
+
const [state, setState] = useState31({ status: "checking" });
|
|
3718
|
+
useEffect14(() => {
|
|
3445
3719
|
let live = true;
|
|
3446
3720
|
void (async () => {
|
|
3447
3721
|
try {
|
|
@@ -3460,17 +3734,17 @@ function Authed(props) {
|
|
|
3460
3734
|
live = false;
|
|
3461
3735
|
};
|
|
3462
3736
|
}, [getToken, apiBase, auth]);
|
|
3463
|
-
if (state.status === "checking") return /* @__PURE__ */
|
|
3737
|
+
if (state.status === "checking") return /* @__PURE__ */ jsx38(Gate, { brand, children: /* @__PURE__ */ jsx38("p", { style: S.muted, children: copy.auth.checking }) });
|
|
3464
3738
|
if (state.status === "denied") {
|
|
3465
|
-
return /* @__PURE__ */
|
|
3466
|
-
/* @__PURE__ */
|
|
3467
|
-
/* @__PURE__ */
|
|
3739
|
+
return /* @__PURE__ */ jsx38(Gate, { brand, children: /* @__PURE__ */ jsxs34("div", { className: "card", style: S.card, children: [
|
|
3740
|
+
/* @__PURE__ */ jsx38("h2", { style: { marginTop: 0 }, children: copy.auth.notAuthorized }),
|
|
3741
|
+
/* @__PURE__ */ jsx38("p", { style: S.muted, children: formatChapterCopy(copy.auth.accountNotAuthorized, {
|
|
3468
3742
|
account: state.email ?? copy.auth.thisAccount
|
|
3469
3743
|
}) }),
|
|
3470
|
-
/* @__PURE__ */
|
|
3744
|
+
/* @__PURE__ */ jsx38("button", { className: "btn secondary", onClick: () => signOut(), children: copy.auth.signOut })
|
|
3471
3745
|
] }) });
|
|
3472
3746
|
}
|
|
3473
|
-
return /* @__PURE__ */
|
|
3747
|
+
return /* @__PURE__ */ jsx38(
|
|
3474
3748
|
AdminShell,
|
|
3475
3749
|
{
|
|
3476
3750
|
workspaces,
|
|
@@ -3512,10 +3786,10 @@ function ChapterAdmin(props) {
|
|
|
3512
3786
|
const chrome = props.chrome ?? "embedded";
|
|
3513
3787
|
const auth = props.auth ?? DEFAULT_ADMIN_AUTH;
|
|
3514
3788
|
const redirect = signInRedirect(basePath, workspaces);
|
|
3515
|
-
const [publishableKey, setPublishableKey] =
|
|
3789
|
+
const [publishableKey, setPublishableKey] = useState31(void 0);
|
|
3516
3790
|
const scopeRef = useRef3(null);
|
|
3517
3791
|
const appearance = useScopedClerkAppearance(scopeRef);
|
|
3518
|
-
|
|
3792
|
+
useEffect14(() => {
|
|
3519
3793
|
let live = true;
|
|
3520
3794
|
void loadChapterAdminConfig(auth, apiBase).then((config) => live && setPublishableKey(config.publishableKey ?? null)).catch(() => live && setPublishableKey(null));
|
|
3521
3795
|
return () => {
|
|
@@ -3524,23 +3798,23 @@ function ChapterAdmin(props) {
|
|
|
3524
3798
|
}, [apiBase, auth]);
|
|
3525
3799
|
let content;
|
|
3526
3800
|
if (publishableKey === void 0 || publishableKey && !appearance) {
|
|
3527
|
-
content = /* @__PURE__ */
|
|
3801
|
+
content = /* @__PURE__ */ jsx38(Gate, { brand, children: /* @__PURE__ */ jsx38("p", { style: S.muted, children: copy.admin.auth.loading }) });
|
|
3528
3802
|
} else if (!publishableKey) {
|
|
3529
|
-
content = /* @__PURE__ */
|
|
3530
|
-
/* @__PURE__ */
|
|
3531
|
-
/* @__PURE__ */
|
|
3803
|
+
content = /* @__PURE__ */ jsx38(Gate, { brand, children: /* @__PURE__ */ jsxs34("div", { className: "card", style: S.card, children: [
|
|
3804
|
+
/* @__PURE__ */ jsx38("h2", { style: { marginTop: 0 }, children: copy.admin.auth.signInNotConfigured }),
|
|
3805
|
+
/* @__PURE__ */ jsx38("p", { style: S.muted, children: copy.admin.auth.missingPublishableKey })
|
|
3532
3806
|
] }) });
|
|
3533
3807
|
} else if (workspaces.length === 0) {
|
|
3534
|
-
content = /* @__PURE__ */
|
|
3808
|
+
content = /* @__PURE__ */ jsx38(Gate, { brand, children: /* @__PURE__ */ jsx38("p", { style: S.muted, children: copy.admin.auth.noWorkspaces }) });
|
|
3535
3809
|
} else {
|
|
3536
|
-
content = /* @__PURE__ */
|
|
3810
|
+
content = /* @__PURE__ */ jsxs34(
|
|
3537
3811
|
ClerkGate,
|
|
3538
3812
|
{
|
|
3539
3813
|
publishableKey,
|
|
3540
3814
|
appearance,
|
|
3541
3815
|
afterSignOutUrl: "/",
|
|
3542
3816
|
children: [
|
|
3543
|
-
/* @__PURE__ */
|
|
3817
|
+
/* @__PURE__ */ jsx38(SignedOut, { children: /* @__PURE__ */ jsx38(Gate, { brand, tagline: copy.admin.auth.signInTagline, children: /* @__PURE__ */ jsx38(
|
|
3544
3818
|
SignIn,
|
|
3545
3819
|
{
|
|
3546
3820
|
routing: "hash",
|
|
@@ -3548,7 +3822,7 @@ function ChapterAdmin(props) {
|
|
|
3548
3822
|
signUpForceRedirectUrl: redirect
|
|
3549
3823
|
}
|
|
3550
3824
|
) }) }),
|
|
3551
|
-
/* @__PURE__ */
|
|
3825
|
+
/* @__PURE__ */ jsx38(SignedIn, { children: /* @__PURE__ */ jsx38(
|
|
3552
3826
|
Authed,
|
|
3553
3827
|
{
|
|
3554
3828
|
workspaces,
|
|
@@ -3569,7 +3843,7 @@ function ChapterAdmin(props) {
|
|
|
3569
3843
|
}
|
|
3570
3844
|
);
|
|
3571
3845
|
}
|
|
3572
|
-
return /* @__PURE__ */
|
|
3846
|
+
return /* @__PURE__ */ jsx38(AdminTheme, { chapter: props.chapter, scopeRef, children: content });
|
|
3573
3847
|
}
|
|
3574
3848
|
|
|
3575
3849
|
// src/ui/admin-defaults.ts
|
|
@@ -3578,17 +3852,17 @@ function defaultAdminSections(chapter) {
|
|
|
3578
3852
|
}
|
|
3579
3853
|
|
|
3580
3854
|
// src/ui/admin-meetings.tsx
|
|
3581
|
-
import { useState as
|
|
3855
|
+
import { useState as useState32 } from "preact/hooks";
|
|
3582
3856
|
import { Button as Button17 } from "@odla-ai/ui/components";
|
|
3583
|
-
import { Fragment as Fragment13, jsx as
|
|
3857
|
+
import { Fragment as Fragment13, jsx as jsx39, jsxs as jsxs35 } from "preact/jsx-runtime";
|
|
3584
3858
|
var when3 = (t) => new Date(t).toLocaleString([], { dateStyle: "medium", timeStyle: "short" });
|
|
3585
3859
|
function MeetingsBody({ ctx }) {
|
|
3586
3860
|
const copy = useChapterCopy().admin.meetings;
|
|
3587
3861
|
const { data, loading, error, refresh } = useAdminResource(ctx.getToken, "/api/admin/meetings?all=1");
|
|
3588
|
-
const [busy, setBusy] =
|
|
3589
|
-
const [note, setNote] =
|
|
3590
|
-
if (loading) return /* @__PURE__ */
|
|
3591
|
-
if (error || !data) return /* @__PURE__ */
|
|
3862
|
+
const [busy, setBusy] = useState32(null);
|
|
3863
|
+
const [note, setNote] = useState32(null);
|
|
3864
|
+
if (loading) return /* @__PURE__ */ jsx39(AdminNote, { children: copy.loading });
|
|
3865
|
+
if (error || !data) return /* @__PURE__ */ jsxs35(AdminNote, { children: [
|
|
3592
3866
|
copy.loadFailed,
|
|
3593
3867
|
error ? `: ${error}` : "",
|
|
3594
3868
|
"."
|
|
@@ -3619,43 +3893,43 @@ function MeetingsBody({ ctx }) {
|
|
|
3619
3893
|
}
|
|
3620
3894
|
void run(id, () => adminFetch(ctx.getToken, `/api/admin/meetings/${id}/reschedule`, { method: "POST", body: JSON.stringify({ startAt }) }));
|
|
3621
3895
|
};
|
|
3622
|
-
return /* @__PURE__ */
|
|
3896
|
+
return /* @__PURE__ */ jsx39(AdminPage, { children: /* @__PURE__ */ jsx39(Panel, { title: /* @__PURE__ */ jsxs35(Fragment13, { children: [
|
|
3623
3897
|
copy.agenda,
|
|
3624
3898
|
" ",
|
|
3625
|
-
/* @__PURE__ */
|
|
3899
|
+
/* @__PURE__ */ jsxs35("span", { className: "muted", style: { fontWeight: 400 }, children: [
|
|
3626
3900
|
"\xB7 ",
|
|
3627
3901
|
data.timezone
|
|
3628
3902
|
] })
|
|
3629
|
-
] }), actions: note ? /* @__PURE__ */
|
|
3630
|
-
/* @__PURE__ */
|
|
3631
|
-
/* @__PURE__ */
|
|
3632
|
-
/* @__PURE__ */
|
|
3633
|
-
m.drift && m.drift !== "none" ? /* @__PURE__ */
|
|
3903
|
+
] }), actions: note ? /* @__PURE__ */ jsx39("span", { className: "muted", children: note }) : void 0, children: data.meetings.length === 0 ? /* @__PURE__ */ jsx39("p", { className: "muted", style: { margin: 0 }, children: copy.empty }) : /* @__PURE__ */ jsx39("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 12 }, children: data.meetings.map((m) => /* @__PURE__ */ jsxs35("li", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap", opacity: m.status === "cancelled" ? 0.55 : 1 }, children: [
|
|
3904
|
+
/* @__PURE__ */ jsx39("strong", { style: { minWidth: 170 }, children: when3(m.startAt) }),
|
|
3905
|
+
/* @__PURE__ */ jsx39("span", { style: { flex: 1 }, children: m.applicant ? `${m.applicant.name} \xB7 ${m.applicant.email}` : copy.unknown }),
|
|
3906
|
+
/* @__PURE__ */ jsx39("span", { className: "badge", children: m.status }),
|
|
3907
|
+
m.drift && m.drift !== "none" ? /* @__PURE__ */ jsxs35("span", { className: "badge", children: [
|
|
3634
3908
|
copy.drift,
|
|
3635
3909
|
": ",
|
|
3636
3910
|
m.drift
|
|
3637
3911
|
] }) : null,
|
|
3638
|
-
m.meetUrl ? /* @__PURE__ */
|
|
3639
|
-
m.status === "scheduled" ? /* @__PURE__ */
|
|
3640
|
-
/* @__PURE__ */
|
|
3641
|
-
/* @__PURE__ */
|
|
3912
|
+
m.meetUrl ? /* @__PURE__ */ jsx39("a", { href: m.meetUrl, target: "_blank", rel: "noreferrer", children: copy.meet }) : null,
|
|
3913
|
+
m.status === "scheduled" ? /* @__PURE__ */ jsxs35(Fragment13, { children: [
|
|
3914
|
+
/* @__PURE__ */ jsx39(Button17, { variant: "secondary", mini: true, disabled: busy === m.id, onClick: () => reschedule(m.id), children: copy.reschedule }),
|
|
3915
|
+
/* @__PURE__ */ jsx39(Button17, { variant: "danger", mini: true, disabled: busy === m.id, onClick: () => cancel(m.id), children: copy.cancel })
|
|
3642
3916
|
] }) : null
|
|
3643
3917
|
] }, m.id)) }) }) });
|
|
3644
3918
|
}
|
|
3645
3919
|
function meetingsSection(options = {}) {
|
|
3646
3920
|
const { id = "meetings", label = "Meetings" } = options;
|
|
3647
|
-
return { id, label, render: (ctx) => /* @__PURE__ */
|
|
3921
|
+
return { id, label, render: (ctx) => /* @__PURE__ */ jsx39(MeetingsBody, { ctx }) };
|
|
3648
3922
|
}
|
|
3649
3923
|
|
|
3650
3924
|
// src/ui/admin-network-record-editor.tsx
|
|
3651
|
-
import { Button as Button18, Field as Field14, Select as
|
|
3652
|
-
import { useRef as useRef4, useState as
|
|
3653
|
-
import { Fragment as Fragment14, jsx as
|
|
3925
|
+
import { Button as Button18, Field as Field14, Select as Select12 } from "@odla-ai/ui/components";
|
|
3926
|
+
import { useRef as useRef4, useState as useState33 } from "preact/hooks";
|
|
3927
|
+
import { Fragment as Fragment14, jsx as jsx40, jsxs as jsxs36 } from "preact/jsx-runtime";
|
|
3654
3928
|
function NetworkRecordEditor(props) {
|
|
3655
3929
|
const { ctx, record } = props;
|
|
3656
|
-
const [stage, setStage] =
|
|
3657
|
-
const [busy, setBusy] =
|
|
3658
|
-
const [error, setError] =
|
|
3930
|
+
const [stage, setStage] = useState33("");
|
|
3931
|
+
const [busy, setBusy] = useState33(false);
|
|
3932
|
+
const [error, setError] = useState33(null);
|
|
3659
3933
|
const attempt = useRef4(null);
|
|
3660
3934
|
const pending = record.edit?.pendingAction;
|
|
3661
3935
|
const superAdmin = ctx.currentUser?.superAdmin === true;
|
|
@@ -3688,11 +3962,11 @@ function NetworkRecordEditor(props) {
|
|
|
3688
3962
|
setBusy(false);
|
|
3689
3963
|
}
|
|
3690
3964
|
};
|
|
3691
|
-
return /* @__PURE__ */
|
|
3692
|
-
superAdmin && record.edit ? /* @__PURE__ */
|
|
3693
|
-
/* @__PURE__ */
|
|
3694
|
-
/* @__PURE__ */
|
|
3695
|
-
/* @__PURE__ */
|
|
3965
|
+
return /* @__PURE__ */ jsxs36("div", { style: { display: "grid", gap: 24 }, children: [
|
|
3966
|
+
superAdmin && record.edit ? /* @__PURE__ */ jsxs36(Fragment14, { children: [
|
|
3967
|
+
/* @__PURE__ */ jsxs36("section", { children: [
|
|
3968
|
+
/* @__PURE__ */ jsx40("h3", { children: "Chapter profile" }),
|
|
3969
|
+
/* @__PURE__ */ jsx40(
|
|
3696
3970
|
OperationalProfileForm,
|
|
3697
3971
|
{
|
|
3698
3972
|
fields: record.edit.fields,
|
|
@@ -3702,27 +3976,27 @@ function NetworkRecordEditor(props) {
|
|
|
3702
3976
|
`${record.id}:${record.revision}`
|
|
3703
3977
|
)
|
|
3704
3978
|
] }),
|
|
3705
|
-
/* @__PURE__ */
|
|
3706
|
-
/* @__PURE__ */
|
|
3707
|
-
pending ? /* @__PURE__ */
|
|
3979
|
+
/* @__PURE__ */ jsxs36("section", { style: { display: "grid", gap: 12 }, children: [
|
|
3980
|
+
/* @__PURE__ */ jsx40("h3", { children: "Membership actions" }),
|
|
3981
|
+
pending ? /* @__PURE__ */ jsxs36("p", { children: [
|
|
3708
3982
|
"An application action is pending: ",
|
|
3709
3983
|
pending.stage.replaceAll("_", " "),
|
|
3710
3984
|
". ",
|
|
3711
3985
|
ownPending ? "Retry reconciles the same operation." : "The original operator must reconcile it."
|
|
3712
|
-
] }) : record.edit.allowedStages.length ? /* @__PURE__ */
|
|
3713
|
-
/* @__PURE__ */
|
|
3714
|
-
record.edit.allowedStages.map((action) => /* @__PURE__ */
|
|
3715
|
-
] }) }) : /* @__PURE__ */
|
|
3716
|
-
pending || record.edit.allowedStages.length ? /* @__PURE__ */
|
|
3717
|
-
error ? /* @__PURE__ */
|
|
3986
|
+
] }) : record.edit.allowedStages.length ? /* @__PURE__ */ jsx40(Field14, { label: "Action", children: /* @__PURE__ */ jsxs36(Select12, { "aria-label": "Action", value: stage, disabled: busy, onChange: (event) => setStage(event.currentTarget.value), children: [
|
|
3987
|
+
/* @__PURE__ */ jsx40("option", { value: "", children: "Choose an action" }),
|
|
3988
|
+
record.edit.allowedStages.map((action) => /* @__PURE__ */ jsx40("option", { value: action.id, children: action.label }, action.id))
|
|
3989
|
+
] }) }) : /* @__PURE__ */ jsx40("p", { children: "No membership action is currently allowed." }),
|
|
3990
|
+
pending || record.edit.allowedStages.length ? /* @__PURE__ */ jsx40("div", { children: /* @__PURE__ */ jsx40(Button18, { disabled: busy || !ownPending || !pending && !stage, onClick: () => void move(), children: busy ? "Applying\u2026" : pending ? "Retry pending action" : "Apply action" }) }) : null,
|
|
3991
|
+
error ? /* @__PURE__ */ jsx40("p", { role: "alert", children: error }) : null
|
|
3718
3992
|
] })
|
|
3719
3993
|
] }) : null,
|
|
3720
|
-
superAdmin && props.admissionGrants ? /* @__PURE__ */
|
|
3721
|
-
/* @__PURE__ */
|
|
3722
|
-
/* @__PURE__ */
|
|
3723
|
-
/* @__PURE__ */
|
|
3994
|
+
superAdmin && props.admissionGrants ? /* @__PURE__ */ jsxs36("section", { children: [
|
|
3995
|
+
/* @__PURE__ */ jsx40("h3", { children: "Next invitation" }),
|
|
3996
|
+
/* @__PURE__ */ jsx40("p", { children: "This setting applies to the next eligible signup; it does not replace approval of an existing application." }),
|
|
3997
|
+
/* @__PURE__ */ jsx40(LeaderAdmissionAction, { getToken: ctx.getToken, targetId: props.targetId, sourceRecordId: record.id })
|
|
3724
3998
|
] }) : null,
|
|
3725
|
-
/* @__PURE__ */
|
|
3999
|
+
/* @__PURE__ */ jsx40(
|
|
3726
4000
|
NetworkRecordDetail,
|
|
3727
4001
|
{
|
|
3728
4002
|
ctx,
|
|
@@ -3737,29 +4011,29 @@ function NetworkRecordEditor(props) {
|
|
|
3737
4011
|
}
|
|
3738
4012
|
|
|
3739
4013
|
// src/ui/network-seat-billing.tsx
|
|
3740
|
-
import { useState as
|
|
4014
|
+
import { useState as useState34 } from "preact/hooks";
|
|
3741
4015
|
import { Button as Button19, DataTable as DataTable4 } from "@odla-ai/ui/components";
|
|
3742
|
-
import { jsx as
|
|
4016
|
+
import { jsx as jsx41, jsxs as jsxs37 } from "preact/jsx-runtime";
|
|
3743
4017
|
var money3 = (row, cents) => row.currency ? new Intl.NumberFormat("en-US", {
|
|
3744
4018
|
style: "currency",
|
|
3745
4019
|
currency: row.currency
|
|
3746
4020
|
}).format(cents / 100) : "Unknown";
|
|
3747
4021
|
var columns2 = (refund, busy) => [
|
|
3748
|
-
{ key: "seatId", header: "Seat", cell: (row) => /* @__PURE__ */
|
|
4022
|
+
{ key: "seatId", header: "Seat", cell: (row) => /* @__PURE__ */ jsx41("code", { children: row.seatId }) },
|
|
3749
4023
|
{ key: "sourceKey", header: "Chapter / runtime", cell: (row) => row.sourceKey },
|
|
3750
4024
|
{ key: "status", header: "Payment", cell: (row) => row.status ?? "Unknown" },
|
|
3751
4025
|
{ key: "amountReceivedCents", header: "Collected", cell: (row) => money3(row, row.amountReceivedCents) },
|
|
3752
4026
|
{ key: "refundedCents", header: "Refunded", cell: (row) => money3(row, row.refundedCents) },
|
|
3753
|
-
{ key: "membershipId", header: "Primary membership", cell: (row) => /* @__PURE__ */
|
|
3754
|
-
{ key: "paymentIntentId", header: "Stripe payment", cell: (row) => /* @__PURE__ */
|
|
3755
|
-
{ key: "subscriptionItemId", header: "Renewal item", cell: (row) => row.subscriptionItemId ? /* @__PURE__ */
|
|
4027
|
+
{ key: "membershipId", header: "Primary membership", cell: (row) => /* @__PURE__ */ jsx41("code", { children: row.membershipId }) },
|
|
4028
|
+
{ key: "paymentIntentId", header: "Stripe payment", cell: (row) => /* @__PURE__ */ jsx41("code", { children: row.paymentIntentId }) },
|
|
4029
|
+
{ key: "subscriptionItemId", header: "Renewal item", cell: (row) => row.subscriptionItemId ? /* @__PURE__ */ jsx41("code", { children: row.subscriptionItemId }) : "Awaiting provider linkage" },
|
|
3756
4030
|
{ key: "currentPeriodEnd", header: "Paid through", cell: (row) => row.currentPeriodEnd ? new Date(row.currentPeriodEnd * 1e3).toLocaleDateString() : "Awaiting provider linkage" },
|
|
3757
|
-
{ key: "refund", header: "Refund", cell: (row) => row.refundedCents < row.amountReceivedCents ? /* @__PURE__ */
|
|
4031
|
+
{ key: "refund", header: "Refund", cell: (row) => row.refundedCents < row.amountReceivedCents ? /* @__PURE__ */ jsx41(Button19, { variant: "danger", mini: true, disabled: busy !== null, onClick: () => refund(row), children: busy === row.seatId ? "Refunding\u2026" : "Refund seat" }) : "Refunded" }
|
|
3758
4032
|
];
|
|
3759
4033
|
function NetworkSeatBilling(props) {
|
|
3760
4034
|
const { data, loading, error, refresh } = useAdminResource(props.getToken, "/api/admin/network-commercial-read-model");
|
|
3761
|
-
const [busy, setBusy] =
|
|
3762
|
-
const [note, setNote] =
|
|
4035
|
+
const [busy, setBusy] = useState34(null);
|
|
4036
|
+
const [note, setNote] = useState34(null);
|
|
3763
4037
|
const refund = async (row) => {
|
|
3764
4038
|
setBusy(row.seatId);
|
|
3765
4039
|
setNote(null);
|
|
@@ -3777,20 +4051,20 @@ function NetworkSeatBilling(props) {
|
|
|
3777
4051
|
setBusy(null);
|
|
3778
4052
|
}
|
|
3779
4053
|
};
|
|
3780
|
-
return /* @__PURE__ */
|
|
3781
|
-
/* @__PURE__ */
|
|
3782
|
-
loading ? /* @__PURE__ */
|
|
4054
|
+
return /* @__PURE__ */ jsxs37(Panel, { title: "Additional membership seats", children: [
|
|
4055
|
+
/* @__PURE__ */ jsx41("p", { children: "Seat payments are included in the network totals. Renewal items share the primary subscription\u2019s term. An unaccepted seat is never refunded automatically." }),
|
|
4056
|
+
loading ? /* @__PURE__ */ jsx41("p", { children: "Loading seats\u2026" }) : error ? /* @__PURE__ */ jsxs37("p", { role: "alert", children: [
|
|
3783
4057
|
"Seats could not be loaded: ",
|
|
3784
4058
|
error
|
|
3785
|
-
] }) : /* @__PURE__ */
|
|
3786
|
-
note ? /* @__PURE__ */
|
|
4059
|
+
] }) : /* @__PURE__ */ jsx41(DataTable4, { rows: data?.seats ?? [], columns: columns2((row) => void refund(row), busy), rowKey: (row) => `${row.sourceKey}:${row.seatId}` }),
|
|
4060
|
+
note ? /* @__PURE__ */ jsx41("p", { role: "status", children: note }) : null
|
|
3787
4061
|
] });
|
|
3788
4062
|
}
|
|
3789
4063
|
|
|
3790
4064
|
// src/ui/membership-disputes.tsx
|
|
3791
|
-
import { useState as
|
|
4065
|
+
import { useState as useState35 } from "preact/hooks";
|
|
3792
4066
|
import { Button as Button20, DataTable as DataTable5 } from "@odla-ai/ui/components";
|
|
3793
|
-
import { jsx as
|
|
4067
|
+
import { jsx as jsx42, jsxs as jsxs38 } from "preact/jsx-runtime";
|
|
3794
4068
|
var money4 = (row, cents) => new Intl.NumberFormat("en-US", { style: "currency", currency: row.currency }).format(cents / 100);
|
|
3795
4069
|
var day = (at) => at ? new Date(at).toLocaleDateString() : "\u2014";
|
|
3796
4070
|
var DISPUTE_STATUS_WORDS = {
|
|
@@ -3804,35 +4078,35 @@ var DISPUTE_STATUS_WORDS = {
|
|
|
3804
4078
|
recharged: "re-charged"
|
|
3805
4079
|
};
|
|
3806
4080
|
var columns3 = (begin, busy) => [
|
|
3807
|
-
{ key: "member", header: "Member", cell: (row) => row.kind === "seat" ? /* @__PURE__ */
|
|
4081
|
+
{ key: "member", header: "Member", cell: (row) => row.kind === "seat" ? /* @__PURE__ */ jsxs38("span", { children: [
|
|
3808
4082
|
"Seat for ",
|
|
3809
4083
|
row.recipientName ?? "the named recipient",
|
|
3810
4084
|
" \xB7 ",
|
|
3811
|
-
/* @__PURE__ */
|
|
3812
|
-
] }) : /* @__PURE__ */
|
|
4085
|
+
/* @__PURE__ */ jsx42("code", { children: row.applicationId })
|
|
4086
|
+
] }) : /* @__PURE__ */ jsxs38("span", { children: [
|
|
3813
4087
|
row.memberNumber ? `#${row.memberNumber} \xB7 ` : "",
|
|
3814
|
-
/* @__PURE__ */
|
|
4088
|
+
/* @__PURE__ */ jsx42("code", { children: row.applicationId })
|
|
3815
4089
|
] }) },
|
|
3816
4090
|
{ key: "chapter", header: "Chapter / runtime", cell: (row) => `${row.chapterId} / ${row.runtime}` },
|
|
3817
4091
|
{ key: "status", header: "Record", cell: (row) => row.status === "payment_disputed" ? `${row.kind === "seat" ? "seat" : "membership"} suspended by dispute` : row.status },
|
|
3818
|
-
{ key: "dispute", header: "Dispute", cell: (row) => /* @__PURE__ */
|
|
4092
|
+
{ key: "dispute", header: "Dispute", cell: (row) => /* @__PURE__ */ jsxs38("span", { children: [
|
|
3819
4093
|
DISPUTE_STATUS_WORDS[row.disputeStatus] ?? row.disputeStatus,
|
|
3820
4094
|
row.disputeReason ? ` \xB7 ${row.disputeReason}` : ""
|
|
3821
4095
|
] }) },
|
|
3822
4096
|
{ key: "amount", header: "Amount", cell: (row) => money4(row, row.disputeAmountCents ?? row.amountCents) },
|
|
3823
4097
|
{ key: "opened", header: "Opened", cell: (row) => day(row.disputedAt) },
|
|
3824
4098
|
{ key: "closed", header: "Closed", cell: (row) => day(row.disputeClosedAt) },
|
|
3825
|
-
{ key: "recharge", header: "Re-charge", cell: (row) => row.rechargePaymentIntentId ? /* @__PURE__ */
|
|
4099
|
+
{ key: "recharge", header: "Re-charge", cell: (row) => row.rechargePaymentIntentId ? /* @__PURE__ */ jsxs38("span", { children: [
|
|
3826
4100
|
day(row.rechargedAt),
|
|
3827
4101
|
" \xB7 ",
|
|
3828
|
-
/* @__PURE__ */
|
|
3829
|
-
] }) : row.status === "payment_disputed" && row.disputeStatus === "lost" ? /* @__PURE__ */
|
|
4102
|
+
/* @__PURE__ */ jsx42("code", { children: row.rechargePaymentIntentId })
|
|
4103
|
+
] }) : row.status === "payment_disputed" && row.disputeStatus === "lost" ? /* @__PURE__ */ jsx42(Button20, { mini: true, disabled: busy !== null, onClick: () => begin(row), children: busy === row.id ? "Charging\u2026" : "Charge again" }) : row.status === "payment_disputed" ? "Respond to the dispute in Stripe" : "\u2014" }
|
|
3830
4104
|
];
|
|
3831
4105
|
function MembershipDisputes(props) {
|
|
3832
4106
|
const { data, loading, error, refresh } = useAdminResource(props.getToken, "/api/admin/membership-disputes");
|
|
3833
|
-
const [busy, setBusy] =
|
|
3834
|
-
const [confirming, setConfirming] =
|
|
3835
|
-
const [note, setNote] =
|
|
4107
|
+
const [busy, setBusy] = useState35(null);
|
|
4108
|
+
const [confirming, setConfirming] = useState35(null);
|
|
4109
|
+
const [note, setNote] = useState35(null);
|
|
3836
4110
|
const recharge = async (row) => {
|
|
3837
4111
|
setBusy(row.id);
|
|
3838
4112
|
setNote(null);
|
|
@@ -3853,33 +4127,33 @@ function MembershipDisputes(props) {
|
|
|
3853
4127
|
}
|
|
3854
4128
|
};
|
|
3855
4129
|
const rows = data?.disputes ?? [];
|
|
3856
|
-
return /* @__PURE__ */
|
|
3857
|
-
/* @__PURE__ */
|
|
3858
|
-
loading ? /* @__PURE__ */
|
|
4130
|
+
return /* @__PURE__ */ jsxs38(Panel, { title: "Card disputes", children: [
|
|
4131
|
+
/* @__PURE__ */ jsx42("p", { children: "A chargeback suspends the membership until the dispute is won or the member clears it with their bank. Re-charging collects the disputed amount again on the saved card, only after a lost dispute and only when you ask." }),
|
|
4132
|
+
loading ? /* @__PURE__ */ jsx42("p", { children: "Loading disputes\u2026" }) : error ? /* @__PURE__ */ jsxs38("p", { role: "alert", children: [
|
|
3859
4133
|
"Disputes could not be loaded: ",
|
|
3860
4134
|
error
|
|
3861
|
-
] }) : rows.length ? /* @__PURE__ */
|
|
3862
|
-
data?.truncated ? /* @__PURE__ */
|
|
3863
|
-
confirming ? /* @__PURE__ */
|
|
3864
|
-
/* @__PURE__ */
|
|
4135
|
+
] }) : rows.length ? /* @__PURE__ */ jsx42(DataTable5, { rows, columns: columns3(setConfirming, busy), rowKey: (row) => row.id }) : /* @__PURE__ */ jsx42("p", { children: "No membership carries a dispute." }),
|
|
4136
|
+
data?.truncated ? /* @__PURE__ */ jsx42("p", { role: "alert", children: "Only the most recent memberships were checked; older disputes may exist." }) : null,
|
|
4137
|
+
confirming ? /* @__PURE__ */ jsxs38("div", { role: "group", "aria-label": "Confirm re-charge", children: [
|
|
4138
|
+
/* @__PURE__ */ jsxs38("p", { children: [
|
|
3865
4139
|
"Charge ",
|
|
3866
4140
|
money4(confirming, confirming.disputeAmountCents ?? confirming.amountCents),
|
|
3867
4141
|
" again to the card on file for ",
|
|
3868
4142
|
confirming.kind === "seat" ? `the seat for ${confirming.recipientName ?? "the recipient"}` : confirming.applicationId,
|
|
3869
4143
|
"?"
|
|
3870
4144
|
] }),
|
|
3871
|
-
/* @__PURE__ */
|
|
4145
|
+
/* @__PURE__ */ jsx42(Button20, { mini: true, onClick: () => void recharge(confirming), children: "Yes, charge the card" }),
|
|
3872
4146
|
" ",
|
|
3873
|
-
/* @__PURE__ */
|
|
4147
|
+
/* @__PURE__ */ jsx42(Button20, { mini: true, onClick: () => setConfirming(null), children: "Cancel" })
|
|
3874
4148
|
] }) : null,
|
|
3875
|
-
note ? /* @__PURE__ */
|
|
4149
|
+
note ? /* @__PURE__ */ jsx42("p", { role: "status", children: note }) : null
|
|
3876
4150
|
] });
|
|
3877
4151
|
}
|
|
3878
4152
|
|
|
3879
4153
|
// src/ui/membership-policy-versions.tsx
|
|
3880
4154
|
import { Button as Button21, DataTable as DataTable6 } from "@odla-ai/ui/components";
|
|
3881
|
-
import { useState as
|
|
3882
|
-
import { Fragment as Fragment15, jsx as
|
|
4155
|
+
import { useState as useState36 } from "preact/hooks";
|
|
4156
|
+
import { Fragment as Fragment15, jsx as jsx43, jsxs as jsxs39 } from "preact/jsx-runtime";
|
|
3883
4157
|
var PATH = "/api/admin/membership-policy-versions";
|
|
3884
4158
|
var RETERM = "/api/admin/membership-discount/reterm";
|
|
3885
4159
|
var day2 = (ms) => new Date(ms).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", timeZone: "UTC" });
|
|
@@ -3891,50 +4165,50 @@ var MECHANISM = {
|
|
|
3891
4165
|
stripe_coupon_forever: "Stripe coupon, applied while active",
|
|
3892
4166
|
stripe_coupon_term_bound: "Stripe coupon, applied once; issuance refuses unless the offering's fixed term ends on the same date"
|
|
3893
4167
|
};
|
|
3894
|
-
var State = ({ row }) => /* @__PURE__ */
|
|
4168
|
+
var State = ({ row }) => /* @__PURE__ */ jsx43("span", { className: row.state === "active" ? "badge" : "muted", children: STATE[row.state] });
|
|
3895
4169
|
var superseded = (row) => row.supersededAt === void 0 ? "\u2014" : day2(row.supersededAt);
|
|
3896
|
-
var Source = ({ row }) => /* @__PURE__ */
|
|
3897
|
-
row.source ?? /* @__PURE__ */
|
|
3898
|
-
row.actor ? /* @__PURE__ */
|
|
4170
|
+
var Source = ({ row }) => /* @__PURE__ */ jsxs39("span", { children: [
|
|
4171
|
+
row.source ?? /* @__PURE__ */ jsx43("span", { className: "muted", children: "Unrecorded" }),
|
|
4172
|
+
row.actor ? /* @__PURE__ */ jsxs39(Fragment15, { children: [
|
|
3899
4173
|
" \xB7 ",
|
|
3900
|
-
/* @__PURE__ */
|
|
4174
|
+
/* @__PURE__ */ jsx43("code", { children: row.actor })
|
|
3901
4175
|
] }) : null,
|
|
3902
|
-
row.recordedAt !== void 0 ? /* @__PURE__ */
|
|
4176
|
+
row.recordedAt !== void 0 ? /* @__PURE__ */ jsxs39(Fragment15, { children: [
|
|
3903
4177
|
" \xB7 ",
|
|
3904
4178
|
day2(row.recordedAt)
|
|
3905
4179
|
] }) : null
|
|
3906
4180
|
] });
|
|
3907
4181
|
var offeringColumns = [
|
|
3908
|
-
{ key: "version", header: "Version", cell: (row) => /* @__PURE__ */
|
|
3909
|
-
/* @__PURE__ */
|
|
4182
|
+
{ key: "version", header: "Version", cell: (row) => /* @__PURE__ */ jsxs39(Fragment15, { children: [
|
|
4183
|
+
/* @__PURE__ */ jsxs39("code", { children: [
|
|
3910
4184
|
"v",
|
|
3911
4185
|
row.version
|
|
3912
4186
|
] }),
|
|
3913
4187
|
" ",
|
|
3914
|
-
/* @__PURE__ */
|
|
4188
|
+
/* @__PURE__ */ jsx43(State, { row })
|
|
3915
4189
|
] }), sortAs: "number", sortValue: (row) => row.version },
|
|
3916
|
-
{ key: "sku", header: "SKU", cell: (row) => /* @__PURE__ */
|
|
4190
|
+
{ key: "sku", header: "SKU", cell: (row) => /* @__PURE__ */ jsx43("code", { children: row.baseSkuId }) },
|
|
3917
4191
|
{ key: "list", header: "List price", cell: (row) => `${money5(row.basePriceCents, row.currency)} / ${row.interval}` },
|
|
3918
4192
|
{ key: "term", header: "Term", cell: (row) => row.term.kind === "fixed_end" ? `Ends ${day2(row.term.endsAt)}` : `Rolling ${row.term.months} months` },
|
|
3919
4193
|
{ key: "seat", header: "Seat", cell: (row) => `${row.seatPriceCents === 0 ? "Included" : money5(row.seatPriceCents, row.currency)} \xB7 ${row.seatPurchaseWindowCalendarMonths === void 0 ? "no window" : `${row.seatPurchaseWindowCalendarMonths}-month window`}` },
|
|
3920
4194
|
{ key: "effectiveFrom", header: "Effective from", cell: (row) => day2(row.effectiveFrom), sortAs: "number", sortValue: (row) => row.effectiveFrom },
|
|
3921
4195
|
{ key: "effectiveUntil", header: "Effective until", cell: (row) => row.effectiveUntil === void 0 ? "Open" : day2(row.effectiveUntil) },
|
|
3922
4196
|
{ key: "supersededAt", header: "Superseded", cell: superseded },
|
|
3923
|
-
{ key: "source", header: "Source", cell: (row) => /* @__PURE__ */
|
|
4197
|
+
{ key: "source", header: "Source", cell: (row) => /* @__PURE__ */ jsx43(Source, { row }) }
|
|
3924
4198
|
];
|
|
3925
4199
|
var policyColumns = (getToken) => [
|
|
3926
|
-
{ key: "version", header: "Version", cell: (row) => /* @__PURE__ */
|
|
3927
|
-
/* @__PURE__ */
|
|
4200
|
+
{ key: "version", header: "Version", cell: (row) => /* @__PURE__ */ jsxs39(Fragment15, { children: [
|
|
4201
|
+
/* @__PURE__ */ jsxs39("code", { children: [
|
|
3928
4202
|
"v",
|
|
3929
4203
|
row.version
|
|
3930
4204
|
] }),
|
|
3931
4205
|
" ",
|
|
3932
|
-
/* @__PURE__ */
|
|
4206
|
+
/* @__PURE__ */ jsx43(State, { row })
|
|
3933
4207
|
] }), sortAs: "number", sortValue: (row) => row.version },
|
|
3934
|
-
{ key: "cohort", header: "Cohort", cell: (row) => /* @__PURE__ */
|
|
4208
|
+
{ key: "cohort", header: "Cohort", cell: (row) => /* @__PURE__ */ jsxs39(Fragment15, { children: [
|
|
3935
4209
|
row.cohortLabel,
|
|
3936
4210
|
" ",
|
|
3937
|
-
/* @__PURE__ */
|
|
4211
|
+
/* @__PURE__ */ jsxs39("span", { className: "muted", children: [
|
|
3938
4212
|
"\xB7 soft target ",
|
|
3939
4213
|
row.softTarget
|
|
3940
4214
|
] })
|
|
@@ -3945,8 +4219,8 @@ var policyColumns = (getToken) => [
|
|
|
3945
4219
|
{ key: "benefit", header: "Benefit duration", cell: (row) => row.benefitDuration.kind === "fixed_end" ? `Until ${day2(row.benefitDuration.endsAt)}` : row.benefitDuration.kind === "first_term" ? "First term" : "While active" },
|
|
3946
4220
|
{ key: "mechanism", header: "Provider mechanism", cell: (row) => MECHANISM[row.mechanism] },
|
|
3947
4221
|
{ key: "supersededAt", header: "Superseded", cell: superseded },
|
|
3948
|
-
{ key: "source", header: "Source", cell: (row) => /* @__PURE__ */
|
|
3949
|
-
{ key: "members", header: "Existing members", cell: (row) => /* @__PURE__ */
|
|
4222
|
+
{ key: "source", header: "Source", cell: (row) => /* @__PURE__ */ jsx43(Source, { row }) },
|
|
4223
|
+
{ key: "members", header: "Existing members", cell: (row) => /* @__PURE__ */ jsx43(RetermAction, { row, getToken }) }
|
|
3950
4224
|
];
|
|
3951
4225
|
var summary = (receipt) => {
|
|
3952
4226
|
const skipped = receipt.skipped.reduce((acc, item) => ({ ...acc, [item.reason]: (acc[item.reason] ?? 0) + 1 }), {});
|
|
@@ -3958,9 +4232,9 @@ var summary = (receipt) => {
|
|
|
3958
4232
|
return `${parts.join(" \xB7 ")}${receipt.more ? " \xB7 more remain, run again" : ""}`;
|
|
3959
4233
|
};
|
|
3960
4234
|
function RetermAction({ row, getToken }) {
|
|
3961
|
-
const [busy, setBusy] =
|
|
3962
|
-
const [result, setResult] =
|
|
3963
|
-
if (row.state !== "active" || row.mechanism !== "stripe_coupon_forever") return /* @__PURE__ */
|
|
4235
|
+
const [busy, setBusy] = useState36(false);
|
|
4236
|
+
const [result, setResult] = useState36(null);
|
|
4237
|
+
if (row.state !== "active" || row.mechanism !== "stripe_coupon_forever") return /* @__PURE__ */ jsx43("span", { className: "muted", children: row.state !== "active" ? "Not the active version" : "Benefit is not while-active" });
|
|
3964
4238
|
const run = async () => {
|
|
3965
4239
|
if (!globalThis.confirm?.(`Move every paid ${row.cohortLabel} member of ${row.chapterId} onto v${row.version}? Their next renewal invoice carries ${row.percentOffBps / 100}% off while they stay active. A member whose renewal this would raise is left alone.`)) return;
|
|
3966
4240
|
setBusy(true);
|
|
@@ -3974,28 +4248,28 @@ function RetermAction({ row, getToken }) {
|
|
|
3974
4248
|
setBusy(false);
|
|
3975
4249
|
}
|
|
3976
4250
|
};
|
|
3977
|
-
return /* @__PURE__ */
|
|
3978
|
-
/* @__PURE__ */
|
|
3979
|
-
result ? /* @__PURE__ */
|
|
4251
|
+
return /* @__PURE__ */ jsxs39("span", { style: { display: "inline-flex", flexDirection: "column", gap: 4 }, children: [
|
|
4252
|
+
/* @__PURE__ */ jsx43(Button21, { mini: true, disabled: busy, onClick: run, children: busy ? "Moving\u2026" : "Move members to this benefit" }),
|
|
4253
|
+
result ? /* @__PURE__ */ jsx43("span", { role: result.tone === "good" ? "status" : "alert", className: result.tone === "danger" ? "danger" : "muted", children: result.text }) : null
|
|
3980
4254
|
] });
|
|
3981
4255
|
}
|
|
3982
4256
|
function MembershipPolicyVersions(props) {
|
|
3983
4257
|
const path = props.chapterId ? `${PATH}?chapterId=${encodeURIComponent(props.chapterId)}` : PATH;
|
|
3984
4258
|
const { data, loading, error } = useAdminResource(props.getToken, path);
|
|
3985
4259
|
const scope = props.chapterId ? `chapter ${props.chapterId}` : "any chapter";
|
|
3986
|
-
if (loading) return /* @__PURE__ */
|
|
3987
|
-
if (error || !data) return /* @__PURE__ */
|
|
4260
|
+
if (loading) return /* @__PURE__ */ jsx43(Panel, { title: "Membership offering versions", children: /* @__PURE__ */ jsx43("p", { role: "status", children: "Loading offering versions\u2026" }) });
|
|
4261
|
+
if (error || !data) return /* @__PURE__ */ jsx43(Panel, { title: "Membership offering versions", children: /* @__PURE__ */ jsxs39("p", { role: "alert", children: [
|
|
3988
4262
|
"Offering versions could not be loaded: ",
|
|
3989
4263
|
error ?? "empty response"
|
|
3990
4264
|
] }) });
|
|
3991
|
-
return /* @__PURE__ */
|
|
3992
|
-
/* @__PURE__ */
|
|
3993
|
-
/* @__PURE__ */
|
|
4265
|
+
return /* @__PURE__ */ jsxs39(Fragment15, { children: [
|
|
4266
|
+
/* @__PURE__ */ jsxs39(Panel, { title: "Membership offering versions", actions: data.truncated ? /* @__PURE__ */ jsx43("span", { className: "badge", children: "Truncated" }) : void 0, children: [
|
|
4267
|
+
/* @__PURE__ */ jsxs39("p", { className: "muted", children: [
|
|
3994
4268
|
"The list price a card shows comes from the active offering; the payable price applies the active discount policy. State is judged as of ",
|
|
3995
4269
|
day2(data.now),
|
|
3996
4270
|
", exactly as checkout issuance judges it."
|
|
3997
4271
|
] }),
|
|
3998
|
-
/* @__PURE__ */
|
|
4272
|
+
/* @__PURE__ */ jsx43(
|
|
3999
4273
|
DataTable6,
|
|
4000
4274
|
{
|
|
4001
4275
|
rows: data.offerings,
|
|
@@ -4006,8 +4280,8 @@ function MembershipPolicyVersions(props) {
|
|
|
4006
4280
|
}
|
|
4007
4281
|
)
|
|
4008
4282
|
] }),
|
|
4009
|
-
/* @__PURE__ */
|
|
4010
|
-
/* @__PURE__ */
|
|
4283
|
+
/* @__PURE__ */ jsxs39(Panel, { title: "Discount policy versions", children: [
|
|
4284
|
+
/* @__PURE__ */ jsx43(
|
|
4011
4285
|
DataTable6,
|
|
4012
4286
|
{
|
|
4013
4287
|
rows: data.discountPolicies,
|
|
@@ -4017,7 +4291,7 @@ function MembershipPolicyVersions(props) {
|
|
|
4017
4291
|
emptyState: `No discount policy versions are recorded for ${scope}.`
|
|
4018
4292
|
}
|
|
4019
4293
|
),
|
|
4020
|
-
data.invalid.length ? /* @__PURE__ */
|
|
4294
|
+
data.invalid.length ? /* @__PURE__ */ jsxs39("p", { role: "alert", children: [
|
|
4021
4295
|
data.invalid.length,
|
|
4022
4296
|
" recorded version",
|
|
4023
4297
|
data.invalid.length === 1 ? " no longer normalizes and blocks" : "s no longer normalize and block",
|
|
@@ -4077,4 +4351,4 @@ export {
|
|
|
4077
4351
|
MembershipDisputes,
|
|
4078
4352
|
MembershipPolicyVersions
|
|
4079
4353
|
};
|
|
4080
|
-
//# sourceMappingURL=chunk-
|
|
4354
|
+
//# sourceMappingURL=chunk-S6VPJFHL.js.map
|