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