@odla-ai/chapter 0.4.0 → 0.7.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 +63 -28
- package/dist/index.cjs +169 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +136 -8
- package/dist/index.d.ts +136 -8
- package/dist/index.js +169 -14
- package/dist/index.js.map +1 -1
- package/dist/ui/index.d.ts +54 -3
- package/dist/ui/index.js +188 -93
- package/dist/ui/index.js.map +1 -1
- package/dist/worker/index.cjs +344 -17
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +60 -6
- package/dist/worker/index.d.ts +60 -6
- package/dist/worker/index.js +344 -17
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
package/dist/ui/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import { useCallback, useEffect, useState } from "react";
|
|
|
8
8
|
import { TopBar, TopBarLink } from "@odla-ai/ui/components";
|
|
9
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
var badgeText = (brand) => brand.badge ?? brand.name.slice(0, 3).toUpperCase();
|
|
11
|
+
var brandDisplay = (brand) => brand.wordmark ?? brand.name;
|
|
11
12
|
var S = {
|
|
12
13
|
gate: {
|
|
13
14
|
minHeight: "100vh",
|
|
@@ -66,7 +67,7 @@ function Gate(props) {
|
|
|
66
67
|
return /* @__PURE__ */ jsx("div", { style: S.gate, children: /* @__PURE__ */ jsxs("div", { style: S.gateInner, children: [
|
|
67
68
|
/* @__PURE__ */ jsxs("div", { style: S.brandBox, children: [
|
|
68
69
|
/* @__PURE__ */ jsx("div", { style: S.badge, children: badgeText(brand) }),
|
|
69
|
-
/* @__PURE__ */ jsx("h1", { style: S.h1, children: brand
|
|
70
|
+
/* @__PURE__ */ jsx("h1", { style: S.h1, children: brandDisplay(brand) }),
|
|
70
71
|
tagline ? /* @__PURE__ */ jsx("p", { style: { ...S.muted, margin: "8px 0 0", fontSize: 14 }, children: tagline }) : null
|
|
71
72
|
] }),
|
|
72
73
|
children
|
|
@@ -99,7 +100,7 @@ function AdminShell(props) {
|
|
|
99
100
|
/* @__PURE__ */ jsxs(TopBar, { children: [
|
|
100
101
|
/* @__PURE__ */ jsxs("a", { className: "topbar-brand", href: "/", style: { display: "inline-flex", alignItems: "center" }, children: [
|
|
101
102
|
/* @__PURE__ */ jsx("span", { style: S.badgeSm, children: badgeText(brand) }),
|
|
102
|
-
brand
|
|
103
|
+
brandDisplay(brand)
|
|
103
104
|
] }),
|
|
104
105
|
/* @__PURE__ */ jsx("nav", { className: "topbar-nav", "aria-label": "Admin navigation", children: sections.map((s) => /* @__PURE__ */ jsx(TopBarLink, { active: section === s.id, onClick: () => go(s.id), children: s.label }, s.id)) }),
|
|
105
106
|
/* @__PURE__ */ jsx("div", { className: "topbar-spacer" }),
|
|
@@ -212,8 +213,69 @@ function ChapterAdmin(props) {
|
|
|
212
213
|
] });
|
|
213
214
|
}
|
|
214
215
|
|
|
216
|
+
// src/ui/admin-people.tsx
|
|
217
|
+
import { useState as useState3 } from "react";
|
|
218
|
+
import { CrmList, RecordPanel, useCrmQuery, useCrmRecord } from "@odla-ai/crm/ui";
|
|
219
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
220
|
+
function PeopleBody(props) {
|
|
221
|
+
const { crm, client, type } = props;
|
|
222
|
+
const hookClient = client;
|
|
223
|
+
const query = useCrmQuery(hookClient, type);
|
|
224
|
+
const [openId, setOpenId] = useState3(null);
|
|
225
|
+
const record = useCrmRecord(hookClient, openId);
|
|
226
|
+
const [saving, setSaving] = useState3(false);
|
|
227
|
+
const saveFields = async (input) => {
|
|
228
|
+
if (!openId) return;
|
|
229
|
+
setSaving(true);
|
|
230
|
+
try {
|
|
231
|
+
await client.updateRecord(openId, { input });
|
|
232
|
+
record.refresh();
|
|
233
|
+
query.refresh();
|
|
234
|
+
} finally {
|
|
235
|
+
setSaving(false);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
const moveStage = async (to) => {
|
|
239
|
+
if (!openId) return;
|
|
240
|
+
await client.setStage(openId, to);
|
|
241
|
+
record.refresh();
|
|
242
|
+
query.refresh();
|
|
243
|
+
};
|
|
244
|
+
const addTag = async (tag) => {
|
|
245
|
+
if (openId) {
|
|
246
|
+
await client.addTag(openId, tag);
|
|
247
|
+
record.refresh();
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
const removeTag = async (tag) => {
|
|
251
|
+
if (openId) {
|
|
252
|
+
await client.removeTag(openId, tag);
|
|
253
|
+
record.refresh();
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
return /* @__PURE__ */ jsxs3("div", { className: "wrap", children: [
|
|
257
|
+
/* @__PURE__ */ jsx3(CrmList, { crm, type, query, onOpenRecord: (r) => setOpenId(r.id) }),
|
|
258
|
+
record.detail ? /* @__PURE__ */ jsx3(
|
|
259
|
+
RecordPanel,
|
|
260
|
+
{
|
|
261
|
+
crm,
|
|
262
|
+
detail: record.detail,
|
|
263
|
+
onSaveFields: saveFields,
|
|
264
|
+
onMoveStage: moveStage,
|
|
265
|
+
onAddTag: addTag,
|
|
266
|
+
onRemoveTag: removeTag,
|
|
267
|
+
saving
|
|
268
|
+
}
|
|
269
|
+
) : null
|
|
270
|
+
] });
|
|
271
|
+
}
|
|
272
|
+
function peopleSection(options) {
|
|
273
|
+
const { crm, id = "people", label = "People", type = "person" } = options;
|
|
274
|
+
return { id, label, render: (ctx) => /* @__PURE__ */ jsx3(PeopleBody, { crm, client: ctx.client, type }) };
|
|
275
|
+
}
|
|
276
|
+
|
|
215
277
|
// src/ui/slot-picker.tsx
|
|
216
|
-
import { useMemo as useMemo2, useState as
|
|
278
|
+
import { useMemo as useMemo2, useState as useState4 } from "react";
|
|
217
279
|
|
|
218
280
|
// src/ui/datetime.ts
|
|
219
281
|
function tzShort(tz) {
|
|
@@ -264,7 +326,7 @@ function groupSlotsByDay(slots, tz) {
|
|
|
264
326
|
}
|
|
265
327
|
|
|
266
328
|
// src/ui/slot-picker.tsx
|
|
267
|
-
import { Fragment as Fragment2, jsx as
|
|
329
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
268
330
|
var DEFAULT_CLASSES = {
|
|
269
331
|
days: "slot-days",
|
|
270
332
|
day: "slot-day",
|
|
@@ -275,13 +337,13 @@ function SlotPicker(props) {
|
|
|
275
337
|
const { slots, timezone, selectedStartAt, onPick, onDayChange, classes = DEFAULT_CLASSES } = props;
|
|
276
338
|
const byDay = useMemo2(() => groupSlotsByDay(slots, timezone), [slots, timezone]);
|
|
277
339
|
const dayKeys = [...byDay.keys()];
|
|
278
|
-
const [activeDay, setActiveDay] =
|
|
340
|
+
const [activeDay, setActiveDay] = useState4(dayKeys[0]);
|
|
279
341
|
const day = activeDay !== void 0 && byDay.has(activeDay) ? activeDay : dayKeys[0];
|
|
280
342
|
const times = (day !== void 0 ? byDay.get(day) : void 0) ?? [];
|
|
281
|
-
return /* @__PURE__ */
|
|
282
|
-
/* @__PURE__ */
|
|
343
|
+
return /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
344
|
+
/* @__PURE__ */ jsx4("div", { className: classes.days, children: dayKeys.map((key) => {
|
|
283
345
|
const first = byDay.get(key)?.[0];
|
|
284
|
-
return /* @__PURE__ */
|
|
346
|
+
return /* @__PURE__ */ jsx4(
|
|
285
347
|
"button",
|
|
286
348
|
{
|
|
287
349
|
type: "button",
|
|
@@ -296,7 +358,7 @@ function SlotPicker(props) {
|
|
|
296
358
|
key
|
|
297
359
|
);
|
|
298
360
|
}) }),
|
|
299
|
-
/* @__PURE__ */
|
|
361
|
+
/* @__PURE__ */ jsx4("div", { className: classes.times, children: times.map((s) => /* @__PURE__ */ jsx4(
|
|
300
362
|
"button",
|
|
301
363
|
{
|
|
302
364
|
type: "button",
|
|
@@ -311,18 +373,18 @@ function SlotPicker(props) {
|
|
|
311
373
|
}
|
|
312
374
|
|
|
313
375
|
// src/ui/members.tsx
|
|
314
|
-
import { useEffect as useEffect3, useState as
|
|
376
|
+
import { useEffect as useEffect3, useState as useState6 } from "react";
|
|
315
377
|
|
|
316
378
|
// src/ui/reschedule.tsx
|
|
317
|
-
import { useState as
|
|
318
|
-
import { jsx as
|
|
379
|
+
import { useState as useState5 } from "react";
|
|
380
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
319
381
|
function Rescheduler(props) {
|
|
320
382
|
const { api, applicationId, timezone, onRescheduled, label = "Change your time" } = props;
|
|
321
|
-
const [open, setOpen] =
|
|
322
|
-
const [slots, setSlots] =
|
|
323
|
-
const [tz, setTz] =
|
|
324
|
-
const [busy, setBusy] =
|
|
325
|
-
const [msg, setMsg] =
|
|
383
|
+
const [open, setOpen] = useState5(false);
|
|
384
|
+
const [slots, setSlots] = useState5(null);
|
|
385
|
+
const [tz, setTz] = useState5(timezone);
|
|
386
|
+
const [busy, setBusy] = useState5(false);
|
|
387
|
+
const [msg, setMsg] = useState5(null);
|
|
326
388
|
const start = async () => {
|
|
327
389
|
setOpen(true);
|
|
328
390
|
setSlots(null);
|
|
@@ -355,7 +417,7 @@ function Rescheduler(props) {
|
|
|
355
417
|
}
|
|
356
418
|
};
|
|
357
419
|
if (!open) {
|
|
358
|
-
return /* @__PURE__ */
|
|
420
|
+
return /* @__PURE__ */ jsx5("p", { className: "meeting-note", children: /* @__PURE__ */ jsx5(
|
|
359
421
|
"a",
|
|
360
422
|
{
|
|
361
423
|
href: "#",
|
|
@@ -367,8 +429,8 @@ function Rescheduler(props) {
|
|
|
367
429
|
}
|
|
368
430
|
) });
|
|
369
431
|
}
|
|
370
|
-
return /* @__PURE__ */
|
|
371
|
-
slots === null ? /* @__PURE__ */
|
|
432
|
+
return /* @__PURE__ */ jsxs5("div", { className: "msched", children: [
|
|
433
|
+
slots === null ? /* @__PURE__ */ jsx5("p", { className: "meeting-note", children: "Loading available times\u2026" }) : slots.length === 0 ? /* @__PURE__ */ jsx5("p", { className: "meeting-note", children: msg ?? "No open times right now. Please check back soon." }) : /* @__PURE__ */ jsx5(
|
|
372
434
|
SlotPicker,
|
|
373
435
|
{
|
|
374
436
|
slots,
|
|
@@ -377,9 +439,9 @@ function Rescheduler(props) {
|
|
|
377
439
|
onPick: (s) => void pick(s)
|
|
378
440
|
}
|
|
379
441
|
),
|
|
380
|
-
busy ? /* @__PURE__ */
|
|
381
|
-
msg && slots && slots.length > 0 ? /* @__PURE__ */
|
|
382
|
-
/* @__PURE__ */
|
|
442
|
+
busy ? /* @__PURE__ */ jsx5("p", { className: "meeting-note", children: "Rescheduling\u2026" }) : null,
|
|
443
|
+
msg && slots && slots.length > 0 ? /* @__PURE__ */ jsx5("p", { className: "meeting-note error", children: msg }) : null,
|
|
444
|
+
/* @__PURE__ */ jsx5("p", { className: "meeting-note", children: /* @__PURE__ */ jsx5(
|
|
383
445
|
"a",
|
|
384
446
|
{
|
|
385
447
|
href: "#",
|
|
@@ -394,12 +456,12 @@ function Rescheduler(props) {
|
|
|
394
456
|
}
|
|
395
457
|
|
|
396
458
|
// src/ui/members.tsx
|
|
397
|
-
import { Fragment as Fragment3, jsx as
|
|
459
|
+
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
398
460
|
function card(kicker, body) {
|
|
399
|
-
return /* @__PURE__ */
|
|
400
|
-
/* @__PURE__ */
|
|
401
|
-
/* @__PURE__ */
|
|
402
|
-
/* @__PURE__ */
|
|
461
|
+
return /* @__PURE__ */ jsxs6("div", { className: "card", children: [
|
|
462
|
+
/* @__PURE__ */ jsx6("div", { className: "card-label", children: "Your Application" }),
|
|
463
|
+
/* @__PURE__ */ jsxs6("div", { className: "meeting-block", children: [
|
|
464
|
+
/* @__PURE__ */ jsx6("div", { className: "meeting-kicker", children: kicker }),
|
|
403
465
|
body
|
|
404
466
|
] })
|
|
405
467
|
] });
|
|
@@ -409,16 +471,16 @@ function ProvisionalCard(props) {
|
|
|
409
471
|
if (!application) {
|
|
410
472
|
return card(
|
|
411
473
|
"One step remains",
|
|
412
|
-
/* @__PURE__ */
|
|
413
|
-
/* @__PURE__ */
|
|
414
|
-
/* @__PURE__ */
|
|
474
|
+
/* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
475
|
+
/* @__PURE__ */ jsx6("div", { className: "meeting-note", children: "Your account is ready, and the application that completes it takes a few minutes." }),
|
|
476
|
+
/* @__PURE__ */ jsx6("a", { className: "apply-link", href: applyHref, children: "Apply for membership" })
|
|
415
477
|
] })
|
|
416
478
|
);
|
|
417
479
|
}
|
|
418
480
|
if (application.status === "refunded") {
|
|
419
|
-
return card("Membership refunded", /* @__PURE__ */
|
|
481
|
+
return card("Membership refunded", /* @__PURE__ */ jsx6("div", { className: "meeting-note", children: "Your fee has been refunded in full and your membership is canceled." }));
|
|
420
482
|
}
|
|
421
|
-
const membership = application.paid ? /* @__PURE__ */
|
|
483
|
+
const membership = application.paid ? /* @__PURE__ */ jsxs6("div", { className: "meeting-note", children: [
|
|
422
484
|
"Your membership is active",
|
|
423
485
|
application.renewalAt ? ` and renews ${fmtDate(application.renewalAt)}` : "",
|
|
424
486
|
"."
|
|
@@ -426,28 +488,28 @@ function ProvisionalCard(props) {
|
|
|
426
488
|
if (application.meetingAt) {
|
|
427
489
|
return card(
|
|
428
490
|
"Your introduction call",
|
|
429
|
-
/* @__PURE__ */
|
|
430
|
-
/* @__PURE__ */
|
|
431
|
-
/* @__PURE__ */
|
|
432
|
-
application.meetUrl ? /* @__PURE__ */
|
|
433
|
-
/* @__PURE__ */
|
|
491
|
+
/* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
492
|
+
/* @__PURE__ */ jsx6("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
|
|
493
|
+
/* @__PURE__ */ jsx6("div", { className: "meeting-note", children: "A calendar invitation with the video call link is in your email." }),
|
|
494
|
+
application.meetUrl ? /* @__PURE__ */ jsx6("div", { className: "meeting-note", children: /* @__PURE__ */ jsx6("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: "Join the video call" }) }) : null,
|
|
495
|
+
/* @__PURE__ */ jsx6(Rescheduler, { api, applicationId: application.id, timezone: application.timezone, onRescheduled: onReschedule }),
|
|
434
496
|
membership
|
|
435
497
|
] })
|
|
436
498
|
);
|
|
437
499
|
}
|
|
438
500
|
return card(
|
|
439
501
|
"Book your introduction call",
|
|
440
|
-
/* @__PURE__ */
|
|
441
|
-
/* @__PURE__ */
|
|
442
|
-
/* @__PURE__ */
|
|
502
|
+
/* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
503
|
+
/* @__PURE__ */ jsx6("div", { className: "meeting-note", children: "Your application is in. Choose a time below, and a calendar invitation will reach your email." }),
|
|
504
|
+
/* @__PURE__ */ jsx6(Rescheduler, { api, applicationId: application.id, timezone: application.timezone, onRescheduled: onReschedule, label: "Choose a time" }),
|
|
443
505
|
membership
|
|
444
506
|
] })
|
|
445
507
|
);
|
|
446
508
|
}
|
|
447
509
|
function MembersArea(props) {
|
|
448
510
|
const { api, signOut, adminHref = "/admin/", applyHref = "/join.html", memberContent } = props;
|
|
449
|
-
const [me, setMe] =
|
|
450
|
-
const [error, setError] =
|
|
511
|
+
const [me, setMe] = useState6(null);
|
|
512
|
+
const [error, setError] = useState6(false);
|
|
451
513
|
const reload = async () => {
|
|
452
514
|
try {
|
|
453
515
|
setMe(await api("/api/me"));
|
|
@@ -458,30 +520,30 @@ function MembersArea(props) {
|
|
|
458
520
|
useEffect3(() => {
|
|
459
521
|
void reload();
|
|
460
522
|
}, []);
|
|
461
|
-
if (error) return /* @__PURE__ */
|
|
462
|
-
if (!me) return /* @__PURE__ */
|
|
523
|
+
if (error) return /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: "Sign in is briefly unavailable. Please refresh." });
|
|
524
|
+
if (!me) return /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: "Loading\u2026" });
|
|
463
525
|
const role = me.role || "provisional";
|
|
464
|
-
return /* @__PURE__ */
|
|
465
|
-
/* @__PURE__ */
|
|
466
|
-
/* @__PURE__ */
|
|
467
|
-
/* @__PURE__ */
|
|
468
|
-
/* @__PURE__ */
|
|
526
|
+
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
527
|
+
/* @__PURE__ */ jsxs6("div", { className: "card", children: [
|
|
528
|
+
/* @__PURE__ */ jsxs6("div", { className: "member-row", children: [
|
|
529
|
+
/* @__PURE__ */ jsx6("span", { className: "member-email", children: me.email }),
|
|
530
|
+
/* @__PURE__ */ jsx6("span", { className: "role-badge " + role, children: role })
|
|
469
531
|
] }),
|
|
470
|
-
/* @__PURE__ */
|
|
471
|
-
/* @__PURE__ */
|
|
472
|
-
role === "admin" ? /* @__PURE__ */
|
|
532
|
+
/* @__PURE__ */ jsxs6("div", { className: "account-actions", children: [
|
|
533
|
+
/* @__PURE__ */ jsx6("button", { className: "btn secondary mini", onClick: signOut, children: "Sign out" }),
|
|
534
|
+
role === "admin" ? /* @__PURE__ */ jsx6("a", { className: "admin-console-link", href: adminHref, children: "Admin console" }) : null
|
|
473
535
|
] })
|
|
474
536
|
] }),
|
|
475
|
-
role === "provisional" ? /* @__PURE__ */
|
|
537
|
+
role === "provisional" ? /* @__PURE__ */ jsx6(ProvisionalCard, { api, application: me.application, applyHref, onReschedule: reload }) : memberContent ?? /* @__PURE__ */ jsx6("div", { className: "card", children: /* @__PURE__ */ jsx6("div", { className: "card-label", children: "Welcome back." }) })
|
|
476
538
|
] });
|
|
477
539
|
}
|
|
478
540
|
|
|
479
541
|
// src/ui/join.tsx
|
|
480
|
-
import { useEffect as useEffect4, useState as
|
|
542
|
+
import { useEffect as useEffect4, useState as useState8 } from "react";
|
|
481
543
|
|
|
482
544
|
// src/ui/payment-step.tsx
|
|
483
|
-
import { useRef, useState as
|
|
484
|
-
import { jsx as
|
|
545
|
+
import { useRef, useState as useState7 } from "react";
|
|
546
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
485
547
|
var loader = null;
|
|
486
548
|
function loadStripe() {
|
|
487
549
|
const existing = globalThis.Stripe;
|
|
@@ -503,8 +565,8 @@ function loadStripe() {
|
|
|
503
565
|
}
|
|
504
566
|
function PaymentStep(props) {
|
|
505
567
|
const { applicationId, refundPolicyText, onPaid } = props;
|
|
506
|
-
const [status, setStatus] =
|
|
507
|
-
const [error, setError] =
|
|
568
|
+
const [status, setStatus] = useState7("idle");
|
|
569
|
+
const [error, setError] = useState7(null);
|
|
508
570
|
const mountRef = useRef(null);
|
|
509
571
|
const stripeRef = useRef(null);
|
|
510
572
|
const elementsRef = useRef(null);
|
|
@@ -551,9 +613,9 @@ function PaymentStep(props) {
|
|
|
551
613
|
setStatus("ready");
|
|
552
614
|
}
|
|
553
615
|
};
|
|
554
|
-
return /* @__PURE__ */
|
|
555
|
-
/* @__PURE__ */
|
|
556
|
-
/* @__PURE__ */
|
|
616
|
+
return /* @__PURE__ */ jsxs7("div", { className: "join-pay", children: [
|
|
617
|
+
/* @__PURE__ */ jsxs7("label", { className: "compliance-box", children: [
|
|
618
|
+
/* @__PURE__ */ jsx7(
|
|
557
619
|
"input",
|
|
558
620
|
{
|
|
559
621
|
type: "checkbox",
|
|
@@ -563,23 +625,23 @@ function PaymentStep(props) {
|
|
|
563
625
|
}
|
|
564
626
|
}
|
|
565
627
|
),
|
|
566
|
-
/* @__PURE__ */
|
|
628
|
+
/* @__PURE__ */ jsx7("span", { children: refundPolicyText })
|
|
567
629
|
] }),
|
|
568
|
-
status === "loading" ? /* @__PURE__ */
|
|
569
|
-
/* @__PURE__ */
|
|
570
|
-
status === "ready" || status === "confirming" ? /* @__PURE__ */
|
|
571
|
-
error ? /* @__PURE__ */
|
|
630
|
+
status === "loading" ? /* @__PURE__ */ jsx7("p", { className: "pay-status", children: "Preparing secure payment\u2026" }) : null,
|
|
631
|
+
/* @__PURE__ */ jsx7("div", { ref: mountRef, hidden: status === "idle" || status === "loading" }),
|
|
632
|
+
status === "ready" || status === "confirming" ? /* @__PURE__ */ jsx7("button", { className: "submit-btn", disabled: status === "confirming", onClick: () => void pay(), children: status === "confirming" ? "Processing\u2026" : "Pay and continue" }) : null,
|
|
633
|
+
error ? /* @__PURE__ */ jsx7("p", { className: "pay-error", children: error }) : null
|
|
572
634
|
] });
|
|
573
635
|
}
|
|
574
636
|
|
|
575
637
|
// src/ui/join.tsx
|
|
576
|
-
import { jsx as
|
|
638
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
577
639
|
function JoinBooking(props) {
|
|
578
640
|
const { applicationId, onBooked } = props;
|
|
579
|
-
const [state, setState] =
|
|
580
|
-
const [msg, setMsg] =
|
|
581
|
-
const [busy, setBusy] =
|
|
582
|
-
const [selected, setSelected] =
|
|
641
|
+
const [state, setState] = useState8(null);
|
|
642
|
+
const [msg, setMsg] = useState8(null);
|
|
643
|
+
const [busy, setBusy] = useState8(false);
|
|
644
|
+
const [selected, setSelected] = useState8(null);
|
|
583
645
|
const load = async () => {
|
|
584
646
|
setMsg(null);
|
|
585
647
|
try {
|
|
@@ -623,9 +685,9 @@ function JoinBooking(props) {
|
|
|
623
685
|
setBusy(false);
|
|
624
686
|
}
|
|
625
687
|
};
|
|
626
|
-
if (!state) return /* @__PURE__ */
|
|
627
|
-
return /* @__PURE__ */
|
|
628
|
-
/* @__PURE__ */
|
|
688
|
+
if (!state) return /* @__PURE__ */ jsx8("p", { className: "slots-status", children: msg ?? "Loading available times\u2026" });
|
|
689
|
+
return /* @__PURE__ */ jsxs8("div", { className: "join-book", children: [
|
|
690
|
+
/* @__PURE__ */ jsx8(
|
|
629
691
|
SlotPicker,
|
|
630
692
|
{
|
|
631
693
|
slots: state.slots,
|
|
@@ -635,19 +697,19 @@ function JoinBooking(props) {
|
|
|
635
697
|
onDayChange: () => setSelected(null)
|
|
636
698
|
}
|
|
637
699
|
),
|
|
638
|
-
/* @__PURE__ */
|
|
639
|
-
/* @__PURE__ */
|
|
640
|
-
msg ? /* @__PURE__ */
|
|
700
|
+
/* @__PURE__ */ jsxs8("div", { className: "slot-confirm", hidden: !selected, children: [
|
|
701
|
+
/* @__PURE__ */ jsx8("button", { className: "submit-btn", disabled: busy, onClick: () => void book(), children: busy ? "Booking\u2026" : "Book this time" }),
|
|
702
|
+
msg ? /* @__PURE__ */ jsx8("p", { className: "step2-note", children: msg }) : null
|
|
641
703
|
] })
|
|
642
704
|
] });
|
|
643
705
|
}
|
|
644
706
|
function JoinIsland(props) {
|
|
645
707
|
const { config, children, membersHref = "/members/" } = props;
|
|
646
|
-
const [step, setStep] =
|
|
647
|
-
const [applicationId, setApplicationId] =
|
|
648
|
-
const [error, setError] =
|
|
649
|
-
const [submitting, setSubmitting] =
|
|
650
|
-
const [booked, setBooked] =
|
|
708
|
+
const [step, setStep] = useState8("form");
|
|
709
|
+
const [applicationId, setApplicationId] = useState8(null);
|
|
710
|
+
const [error, setError] = useState8(null);
|
|
711
|
+
const [submitting, setSubmitting] = useState8(false);
|
|
712
|
+
const [booked, setBooked] = useState8(null);
|
|
651
713
|
const submit = async (e) => {
|
|
652
714
|
e.preventDefault();
|
|
653
715
|
setSubmitting(true);
|
|
@@ -672,15 +734,15 @@ function JoinIsland(props) {
|
|
|
672
734
|
}
|
|
673
735
|
};
|
|
674
736
|
if (step === "done" && booked) {
|
|
675
|
-
return /* @__PURE__ */
|
|
676
|
-
/* @__PURE__ */
|
|
677
|
-
/* @__PURE__ */
|
|
678
|
-
/* @__PURE__ */
|
|
679
|
-
/* @__PURE__ */
|
|
737
|
+
return /* @__PURE__ */ jsxs8("div", { className: "join-done card", children: [
|
|
738
|
+
/* @__PURE__ */ jsx8("div", { className: "card-label", children: "You're booked" }),
|
|
739
|
+
/* @__PURE__ */ jsx8("p", { className: "meeting-date", children: fullLabel(booked.startAt, booked.timezone) }),
|
|
740
|
+
/* @__PURE__ */ jsx8("p", { className: "meeting-note", children: "A calendar invitation with the video call link is on its way to your email." }),
|
|
741
|
+
/* @__PURE__ */ jsx8("a", { className: "apply-link", href: membersHref, children: "Go to your member area" })
|
|
680
742
|
] });
|
|
681
743
|
}
|
|
682
744
|
if (step === "book" && applicationId) {
|
|
683
|
-
return /* @__PURE__ */
|
|
745
|
+
return /* @__PURE__ */ jsx8(
|
|
684
746
|
JoinBooking,
|
|
685
747
|
{
|
|
686
748
|
applicationId,
|
|
@@ -692,15 +754,47 @@ function JoinIsland(props) {
|
|
|
692
754
|
);
|
|
693
755
|
}
|
|
694
756
|
if (step === "pay" && applicationId) {
|
|
695
|
-
return /* @__PURE__ */
|
|
757
|
+
return /* @__PURE__ */ jsx8(PaymentStep, { applicationId, refundPolicyText: config.refundPolicyText ?? "", onPaid: () => setStep("book") });
|
|
696
758
|
}
|
|
697
|
-
return /* @__PURE__ */
|
|
759
|
+
return /* @__PURE__ */ jsxs8("form", { className: "join-form", onSubmit: (e) => void submit(e), children: [
|
|
698
760
|
children,
|
|
699
|
-
error ? /* @__PURE__ */
|
|
700
|
-
/* @__PURE__ */
|
|
761
|
+
error ? /* @__PURE__ */ jsx8("p", { className: "join-error", children: error }) : null,
|
|
762
|
+
/* @__PURE__ */ jsx8("button", { className: "submit-btn", type: "submit", disabled: submitting, children: submitting ? "Submitting\u2026" : "Submit application" })
|
|
701
763
|
] });
|
|
702
764
|
}
|
|
765
|
+
|
|
766
|
+
// src/brand.ts
|
|
767
|
+
function paletteVar(key) {
|
|
768
|
+
return key.startsWith("--") ? key : `--${key}`;
|
|
769
|
+
}
|
|
770
|
+
function cleanValue(value) {
|
|
771
|
+
return value.replace(/[<>{};]/g, "").trim();
|
|
772
|
+
}
|
|
773
|
+
function brandTokens(brand) {
|
|
774
|
+
if (!brand) return "";
|
|
775
|
+
const decls = [];
|
|
776
|
+
for (const [key, value] of Object.entries(brand.palette ?? {})) {
|
|
777
|
+
if (typeof value === "string" && value.trim()) decls.push(`${paletteVar(key)}: ${cleanValue(value)};`);
|
|
778
|
+
}
|
|
779
|
+
const fonts = brand.fonts;
|
|
780
|
+
if (fonts?.display) decls.push(`--ui-font-display: ${cleanValue(fonts.display)};`);
|
|
781
|
+
if (fonts?.body) decls.push(`--ui-font-sans: ${cleanValue(fonts.body)};`);
|
|
782
|
+
if (fonts?.numeral) decls.push(`--ui-font-numeral: ${cleanValue(fonts.numeral)};`);
|
|
783
|
+
return decls.length ? `:root {
|
|
784
|
+
${decls.join("\n ")}
|
|
785
|
+
}
|
|
786
|
+
` : "";
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// src/ui/brand-style.tsx
|
|
790
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
791
|
+
function BrandStyle(props) {
|
|
792
|
+
const css = brandTokens(props.brand);
|
|
793
|
+
if (!css) return null;
|
|
794
|
+
return /* @__PURE__ */ jsx9("style", { children: css });
|
|
795
|
+
}
|
|
703
796
|
export {
|
|
797
|
+
BrandStyle,
|
|
704
798
|
ChapterAdmin,
|
|
705
799
|
JoinIsland,
|
|
706
800
|
MembersArea,
|
|
@@ -713,6 +807,7 @@ export {
|
|
|
713
807
|
fmtMoney,
|
|
714
808
|
fullLabel,
|
|
715
809
|
groupSlotsByDay,
|
|
810
|
+
peopleSection,
|
|
716
811
|
timeLabel,
|
|
717
812
|
tzShort
|
|
718
813
|
};
|