@odla-ai/chapter 0.41.0 → 0.42.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 +18 -8
- package/dist/{chunk-IAWBE5PX.js → chunk-JXFYOUDL.js} +8 -2
- package/dist/chunk-JXFYOUDL.js.map +1 -0
- package/dist/{chunk-O22RRPBT.js → chunk-MMDWXTJU.js} +2 -2
- package/dist/{chunk-JLLRZO7B.js → chunk-S7CND3R5.js} +348 -281
- package/dist/chunk-S7CND3R5.js.map +1 -0
- package/dist/{copy-context-B14OOiYq.d.ts → copy-context-DuJkH4U9.d.ts} +1 -1
- package/dist/index.cjs +7 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +7 -1
- 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 +5 -3
- package/dist/ui/member/index.d.ts +38 -10
- package/dist/ui/member/index.js +4 -2
- package/dist/worker/index.cjs +69 -12
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +1 -1
- package/dist/worker/index.d.ts +1 -1
- package/dist/worker/index.js +69 -12
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-IAWBE5PX.js.map +0 -1
- package/dist/chunk-JLLRZO7B.js.map +0 -1
- /package/dist/{chunk-O22RRPBT.js.map → chunk-MMDWXTJU.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
formatChapterCopy,
|
|
3
3
|
useChapterCopy
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JXFYOUDL.js";
|
|
5
5
|
import {
|
|
6
6
|
collectFormFields
|
|
7
7
|
} from "./chunk-IVXVECKR.js";
|
|
@@ -27,7 +27,12 @@ function dayLabel(ms, tz) {
|
|
|
27
27
|
return new Date(ms).toLocaleDateString(void 0, { timeZone: tz, weekday: "short", month: "short", day: "numeric" });
|
|
28
28
|
}
|
|
29
29
|
function timeLabel(ms, tz) {
|
|
30
|
-
return new Date(ms).toLocaleTimeString(void 0, {
|
|
30
|
+
return new Date(ms).toLocaleTimeString(void 0, {
|
|
31
|
+
timeZone: tz,
|
|
32
|
+
hour: "numeric",
|
|
33
|
+
minute: "2-digit",
|
|
34
|
+
timeZoneName: "short"
|
|
35
|
+
});
|
|
31
36
|
}
|
|
32
37
|
function fullLabel(ms, tz) {
|
|
33
38
|
return new Date(ms).toLocaleString(void 0, {
|
|
@@ -105,7 +110,7 @@ function SlotPicker(props) {
|
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
// src/ui/members.tsx
|
|
108
|
-
import { useEffect as useEffect3, useState as
|
|
113
|
+
import { useEffect as useEffect3, useState as useState6 } from "preact/hooks";
|
|
109
114
|
|
|
110
115
|
// src/ui/reschedule.tsx
|
|
111
116
|
import { useState as useState2 } from "preact/hooks";
|
|
@@ -190,7 +195,7 @@ function Rescheduler(props) {
|
|
|
190
195
|
}
|
|
191
196
|
|
|
192
197
|
// src/ui/member-gifts.tsx
|
|
193
|
-
import { useEffect, useRef as useRef2, useState as
|
|
198
|
+
import { useEffect, useRef as useRef2, useState as useState4 } from "preact/hooks";
|
|
194
199
|
|
|
195
200
|
// src/ui/gift-offer-cards.tsx
|
|
196
201
|
import { jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
@@ -208,78 +213,9 @@ function GiftOfferCards(props) {
|
|
|
208
213
|
] }, offer.id)) });
|
|
209
214
|
}
|
|
210
215
|
|
|
211
|
-
// src/ui/gift-code-redeemer.tsx
|
|
212
|
-
import { InlineActionField } from "@odla-ai/ui/components";
|
|
213
|
-
import { useState as useState3 } from "preact/hooks";
|
|
214
|
-
import { jsx as jsx4 } from "preact/jsx-runtime";
|
|
215
|
-
function GiftCodeRedeemer({ api, copy, id, onRedeemed }) {
|
|
216
|
-
const [code, setCode] = useState3("");
|
|
217
|
-
const [loading, setLoading] = useState3(false);
|
|
218
|
-
const [message, setMessage] = useState3("");
|
|
219
|
-
const [messageTone, setMessageTone] = useState3("neutral");
|
|
220
|
-
const normalizedCode = code.trim();
|
|
221
|
-
const redeem = async () => {
|
|
222
|
-
if (!normalizedCode || loading) return;
|
|
223
|
-
setLoading(true);
|
|
224
|
-
setMessage("");
|
|
225
|
-
setMessageTone("neutral");
|
|
226
|
-
try {
|
|
227
|
-
await api("/api/gifts/redeem", {
|
|
228
|
-
method: "POST",
|
|
229
|
-
headers: { "content-type": "application/json" },
|
|
230
|
-
body: JSON.stringify({ code: normalizedCode })
|
|
231
|
-
});
|
|
232
|
-
setCode("");
|
|
233
|
-
setMessage(copy.redeemed);
|
|
234
|
-
setMessageTone("success");
|
|
235
|
-
try {
|
|
236
|
-
await onRedeemed?.();
|
|
237
|
-
} catch {
|
|
238
|
-
}
|
|
239
|
-
} catch {
|
|
240
|
-
setMessage(copy.redeemFailed);
|
|
241
|
-
setMessageTone("error");
|
|
242
|
-
} finally {
|
|
243
|
-
setLoading(false);
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
return /* @__PURE__ */ jsx4(
|
|
247
|
-
InlineActionField,
|
|
248
|
-
{
|
|
249
|
-
id,
|
|
250
|
-
className: "gift-code-redeemer",
|
|
251
|
-
label: copy.code,
|
|
252
|
-
value: code,
|
|
253
|
-
code: true,
|
|
254
|
-
actionLabel: copy.redeem,
|
|
255
|
-
loadingLabel: `${copy.redeem}\u2026`,
|
|
256
|
-
loading,
|
|
257
|
-
actionDisabled: !normalizedCode,
|
|
258
|
-
message,
|
|
259
|
-
messageTone,
|
|
260
|
-
inputProps: {
|
|
261
|
-
name: "giftCode",
|
|
262
|
-
maxLength: 64,
|
|
263
|
-
autoComplete: "one-time-code",
|
|
264
|
-
autoCapitalize: "none",
|
|
265
|
-
autocorrect: "off",
|
|
266
|
-
spellcheck: false
|
|
267
|
-
},
|
|
268
|
-
onValueChange: (value) => {
|
|
269
|
-
setCode(value);
|
|
270
|
-
if (message) {
|
|
271
|
-
setMessage("");
|
|
272
|
-
setMessageTone("neutral");
|
|
273
|
-
}
|
|
274
|
-
},
|
|
275
|
-
onAction: () => void redeem()
|
|
276
|
-
}
|
|
277
|
-
);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
216
|
// src/ui/payment-step.tsx
|
|
281
|
-
import { useRef, useState as
|
|
282
|
-
import { jsx as
|
|
217
|
+
import { useRef, useState as useState3 } from "preact/hooks";
|
|
218
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
|
|
283
219
|
var loader = null;
|
|
284
220
|
function loadStripe() {
|
|
285
221
|
const existing = globalThis.Stripe;
|
|
@@ -313,9 +249,9 @@ function PaymentStep(props) {
|
|
|
313
249
|
simulation
|
|
314
250
|
} = props;
|
|
315
251
|
const copy = props.copy ?? inheritedCopy.join.payment;
|
|
316
|
-
const [status, setStatus] =
|
|
317
|
-
const [error, setError] =
|
|
318
|
-
const [lineItems, setLineItems] =
|
|
252
|
+
const [status, setStatus] = useState3("idle");
|
|
253
|
+
const [error, setError] = useState3(null);
|
|
254
|
+
const [lineItems, setLineItems] = useState3(null);
|
|
319
255
|
const mountRef = useRef(null);
|
|
320
256
|
const stripeRef = useRef(null);
|
|
321
257
|
const elementsRef = useRef(null);
|
|
@@ -391,10 +327,10 @@ function PaymentStep(props) {
|
|
|
391
327
|
};
|
|
392
328
|
return /* @__PURE__ */ jsxs4("div", { className: "join-pay", children: [
|
|
393
329
|
/* @__PURE__ */ jsxs4("div", { className: "compliance-box", children: [
|
|
394
|
-
merchantDisclosureText ? /* @__PURE__ */
|
|
395
|
-
/* @__PURE__ */
|
|
330
|
+
merchantDisclosureText ? /* @__PURE__ */ jsx4("p", { className: "compliance-merchant", children: merchantDisclosureText }) : null,
|
|
331
|
+
/* @__PURE__ */ jsx4("p", { className: "compliance-policy", children: refundPolicyText }),
|
|
396
332
|
/* @__PURE__ */ jsxs4("label", { className: "compliance-check", children: [
|
|
397
|
-
/* @__PURE__ */
|
|
333
|
+
/* @__PURE__ */ jsx4(
|
|
398
334
|
"input",
|
|
399
335
|
{
|
|
400
336
|
type: "checkbox",
|
|
@@ -404,41 +340,41 @@ function PaymentStep(props) {
|
|
|
404
340
|
}
|
|
405
341
|
}
|
|
406
342
|
),
|
|
407
|
-
copy.consent ? /* @__PURE__ */
|
|
343
|
+
copy.consent ? /* @__PURE__ */ jsx4("span", { children: copy.consent }) : null
|
|
408
344
|
] })
|
|
409
345
|
] }),
|
|
410
|
-
status === "loading" ? /* @__PURE__ */
|
|
346
|
+
status === "loading" ? /* @__PURE__ */ jsx4("p", { className: "pay-status", children: copy.preparing }) : null,
|
|
411
347
|
lineItems && renderPriceLines ? renderPriceLines(lineItems) : null,
|
|
412
348
|
children,
|
|
413
349
|
simulation && (status === "ready" || status === "confirming") ? /* @__PURE__ */ jsxs4("fieldset", { className: "join-pay-simulation", children: [
|
|
414
|
-
/* @__PURE__ */
|
|
350
|
+
/* @__PURE__ */ jsx4("legend", { children: "Payment details" }),
|
|
415
351
|
/* @__PURE__ */ jsxs4("label", { children: [
|
|
416
352
|
"Card number",
|
|
417
|
-
/* @__PURE__ */
|
|
353
|
+
/* @__PURE__ */ jsx4("input", { name: "simulationCardNumber", inputMode: "numeric", autoComplete: "off", defaultValue: "4242 4242 4242 4242" })
|
|
418
354
|
] }),
|
|
419
355
|
/* @__PURE__ */ jsxs4("label", { children: [
|
|
420
356
|
"Expiration",
|
|
421
|
-
/* @__PURE__ */
|
|
357
|
+
/* @__PURE__ */ jsx4("input", { name: "simulationCardExpiry", inputMode: "numeric", autoComplete: "off", defaultValue: "12 / 34" })
|
|
422
358
|
] }),
|
|
423
359
|
/* @__PURE__ */ jsxs4("label", { children: [
|
|
424
360
|
"Security code",
|
|
425
|
-
/* @__PURE__ */
|
|
361
|
+
/* @__PURE__ */ jsx4("input", { name: "simulationCardCvc", inputMode: "numeric", autoComplete: "off", defaultValue: "123" })
|
|
426
362
|
] }),
|
|
427
|
-
/* @__PURE__ */
|
|
363
|
+
/* @__PURE__ */ jsx4("p", { children: "This is a simulation. No card data is sent and no charge is created." })
|
|
428
364
|
] }) : null,
|
|
429
|
-
/* @__PURE__ */
|
|
430
|
-
status === "ready" || status === "confirming" ? /* @__PURE__ */
|
|
431
|
-
error ? /* @__PURE__ */
|
|
365
|
+
/* @__PURE__ */ jsx4("div", { ref: mountRef, hidden: status === "idle" || status === "loading" }),
|
|
366
|
+
status === "ready" || status === "confirming" ? /* @__PURE__ */ jsx4("button", { className: "submit-btn", disabled: status === "confirming", onClick: () => void pay(), children: status === "confirming" ? copy.processing : copy.payAndContinue }) : null,
|
|
367
|
+
error ? /* @__PURE__ */ jsx4("p", { className: "pay-error", children: error }) : null
|
|
432
368
|
] });
|
|
433
369
|
}
|
|
434
370
|
|
|
435
371
|
// src/ui/member-gifts.tsx
|
|
436
|
-
import { jsx as
|
|
437
|
-
function
|
|
438
|
-
const [data, setData] =
|
|
439
|
-
const [selected, setSelected] =
|
|
440
|
-
const [code, setCode] =
|
|
441
|
-
const [message, setMessage] =
|
|
372
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
|
|
373
|
+
function GiftPurchases(props) {
|
|
374
|
+
const [data, setData] = useState4(null);
|
|
375
|
+
const [selected, setSelected] = useState4(null);
|
|
376
|
+
const [code, setCode] = useState4("");
|
|
377
|
+
const [message, setMessage] = useState4("");
|
|
442
378
|
const purchaseId = useRef2(crypto.randomUUID());
|
|
443
379
|
const load = async () => setData(await props.api("/api/gifts"));
|
|
444
380
|
useEffect(() => {
|
|
@@ -454,17 +390,18 @@ function MemberGifts(props) {
|
|
|
454
390
|
}
|
|
455
391
|
};
|
|
456
392
|
if (!data) return null;
|
|
393
|
+
if (data.offers.length === 0 && data.claims.length === 0) return null;
|
|
457
394
|
const offer = data.offers.find((item) => item.id === selected);
|
|
458
395
|
return /* @__PURE__ */ jsxs5("section", { className: "member-gifts", children: [
|
|
459
|
-
/* @__PURE__ */ jsxs5("div", { className: "card", children: [
|
|
460
|
-
/* @__PURE__ */
|
|
461
|
-
/* @__PURE__ */
|
|
462
|
-
|
|
396
|
+
data.offers.length ? /* @__PURE__ */ jsxs5("div", { className: "card", children: [
|
|
397
|
+
/* @__PURE__ */ jsx5("div", { className: "card-label", children: props.copy.title }),
|
|
398
|
+
/* @__PURE__ */ jsx5("p", { children: props.copy.body }),
|
|
399
|
+
/* @__PURE__ */ jsx5(GiftOfferCards, { offers: data.offers, mode: "select", selectedOfferId: selected, onSelect: (id) => {
|
|
463
400
|
setSelected(id);
|
|
464
401
|
setCode("");
|
|
465
402
|
purchaseId.current = crypto.randomUUID();
|
|
466
|
-
} })
|
|
467
|
-
offer ? /* @__PURE__ */
|
|
403
|
+
} }),
|
|
404
|
+
offer ? /* @__PURE__ */ jsx5(
|
|
468
405
|
PaymentStep,
|
|
469
406
|
{
|
|
470
407
|
applicationId: purchaseId.current,
|
|
@@ -485,30 +422,27 @@ function MemberGifts(props) {
|
|
|
485
422
|
}
|
|
486
423
|
) : null,
|
|
487
424
|
code ? /* @__PURE__ */ jsxs5("div", { className: "gift-code-once", children: [
|
|
488
|
-
/* @__PURE__ */
|
|
489
|
-
/* @__PURE__ */
|
|
425
|
+
/* @__PURE__ */ jsx5("output", { children: code }),
|
|
426
|
+
/* @__PURE__ */ jsx5("p", { children: props.copy.saveCode })
|
|
490
427
|
] }) : null
|
|
491
|
-
] }),
|
|
428
|
+
] }) : null,
|
|
492
429
|
/* @__PURE__ */ jsxs5("div", { className: "card", children: [
|
|
493
|
-
/* @__PURE__ */
|
|
430
|
+
/* @__PURE__ */ jsx5("div", { className: "card-label", children: props.copy.purchases }),
|
|
494
431
|
data.claims.length ? data.claims.map((claim) => /* @__PURE__ */ jsxs5("div", { className: "member-row", children: [
|
|
495
|
-
/* @__PURE__ */
|
|
496
|
-
/* @__PURE__ */
|
|
497
|
-
claim.status === "pending" ? /* @__PURE__ */
|
|
498
|
-
] }, claim.id)) : /* @__PURE__ */
|
|
499
|
-
|
|
500
|
-
/* @__PURE__ */ jsxs5("div", { className: "card", children: [
|
|
501
|
-
/* @__PURE__ */ jsx6("div", { className: "card-label", children: props.copy.redeemTitle }),
|
|
502
|
-
/* @__PURE__ */ jsx6(GiftCodeRedeemer, { api: props.api, copy: props.copy, onRedeemed: load }),
|
|
503
|
-
message ? /* @__PURE__ */ jsx6("p", { role: "status", children: message }) : null
|
|
432
|
+
/* @__PURE__ */ jsx5("span", { children: claim.offerId }),
|
|
433
|
+
/* @__PURE__ */ jsx5("span", { children: props.copy[claim.status] }),
|
|
434
|
+
claim.status === "pending" ? /* @__PURE__ */ jsx5("button", { className: "btn secondary mini", onClick: () => void rotate(claim.id), children: props.copy.rotate }) : null
|
|
435
|
+
] }, claim.id)) : /* @__PURE__ */ jsx5("p", { children: props.copy.noPurchases }),
|
|
436
|
+
message ? /* @__PURE__ */ jsx5("p", { role: "status", children: message }) : null
|
|
504
437
|
] })
|
|
505
438
|
] });
|
|
506
439
|
}
|
|
440
|
+
var MemberGifts = GiftPurchases;
|
|
507
441
|
|
|
508
442
|
// src/ui/member-content.tsx
|
|
509
|
-
import { useEffect as useEffect2, useMemo as useMemo2, useState as
|
|
443
|
+
import { useEffect as useEffect2, useMemo as useMemo2, useState as useState5 } from "preact/hooks";
|
|
510
444
|
import { Markdown } from "@odla-ai/ui/components";
|
|
511
|
-
import { Fragment as Fragment2, jsx as
|
|
445
|
+
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
|
|
512
446
|
var pageLabel = (page) => `${page.title}${page.access === "locked" ? " \xB7 Locked" : ""}`;
|
|
513
447
|
function MemberContentArea(props) {
|
|
514
448
|
const {
|
|
@@ -516,12 +450,12 @@ function MemberContentArea(props) {
|
|
|
516
450
|
path = "/api/member-content",
|
|
517
451
|
upsellHref,
|
|
518
452
|
onUpsell,
|
|
519
|
-
loadingContent = /* @__PURE__ */
|
|
520
|
-
emptyContent = /* @__PURE__ */
|
|
453
|
+
loadingContent = /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: "Loading member pages\u2026" }),
|
|
454
|
+
emptyContent = /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: "No member pages have been published yet." })
|
|
521
455
|
} = props;
|
|
522
|
-
const [data, setData] =
|
|
523
|
-
const [error, setError] =
|
|
524
|
-
const [selectedId, setSelectedId] =
|
|
456
|
+
const [data, setData] = useState5(props.initialData ?? null);
|
|
457
|
+
const [error, setError] = useState5(null);
|
|
458
|
+
const [selectedId, setSelectedId] = useState5(
|
|
525
459
|
props.initialPageId ?? props.initialData?.pages[0]?.id ?? ""
|
|
526
460
|
);
|
|
527
461
|
useEffect2(() => {
|
|
@@ -550,14 +484,14 @@ function MemberContentArea(props) {
|
|
|
550
484
|
"Member pages could not be loaded: ",
|
|
551
485
|
error
|
|
552
486
|
] });
|
|
553
|
-
if (!data) return /* @__PURE__ */
|
|
554
|
-
if (data.pages.length === 0) return /* @__PURE__ */
|
|
487
|
+
if (!data) return /* @__PURE__ */ jsx6(Fragment2, { children: loadingContent });
|
|
488
|
+
if (data.pages.length === 0) return /* @__PURE__ */ jsx6(Fragment2, { children: emptyContent });
|
|
555
489
|
const selected = data.pages.find((page) => page.id === selectedId) ?? data.pages[0];
|
|
556
490
|
const href = selected.upsell && upsellHref ? upsellHref(selected.upsell.tierId, selected) : void 0;
|
|
557
491
|
return /* @__PURE__ */ jsxs6("div", { className: "chapter-member-content", "data-member-content": true, children: [
|
|
558
|
-
/* @__PURE__ */
|
|
559
|
-
/* @__PURE__ */
|
|
560
|
-
/* @__PURE__ */
|
|
492
|
+
/* @__PURE__ */ jsx6("nav", { className: "chapter-member-content-nav", "aria-label": "Member pages", children: sections.map(([section, pages]) => /* @__PURE__ */ jsxs6("section", { className: "chapter-member-content-section", children: [
|
|
493
|
+
/* @__PURE__ */ jsx6("h2", { children: section }),
|
|
494
|
+
/* @__PURE__ */ jsx6("ul", { children: pages.map((page) => /* @__PURE__ */ jsx6("li", { "data-parent-page": page.navigation.parentId ?? void 0, children: /* @__PURE__ */ jsx6(
|
|
561
495
|
"button",
|
|
562
496
|
{
|
|
563
497
|
type: "button",
|
|
@@ -574,16 +508,16 @@ function MemberContentArea(props) {
|
|
|
574
508
|
" \xB7 ",
|
|
575
509
|
selected.access
|
|
576
510
|
] }),
|
|
577
|
-
/* @__PURE__ */
|
|
578
|
-
selected.summary ? /* @__PURE__ */
|
|
511
|
+
/* @__PURE__ */ jsx6("h1", { children: selected.title }),
|
|
512
|
+
selected.summary ? /* @__PURE__ */ jsx6("p", { children: selected.summary }) : null
|
|
579
513
|
] }),
|
|
580
|
-
selected.access === "allowed" && selected.bodyMarkdown ? /* @__PURE__ */
|
|
581
|
-
selected.teaserMarkdown ? /* @__PURE__ */
|
|
514
|
+
selected.access === "allowed" && selected.bodyMarkdown ? /* @__PURE__ */ jsx6(Markdown, { source: selected.bodyMarkdown }) : /* @__PURE__ */ jsxs6("div", { className: "chapter-member-content-locked", children: [
|
|
515
|
+
selected.teaserMarkdown ? /* @__PURE__ */ jsx6(Markdown, { source: selected.teaserMarkdown }) : /* @__PURE__ */ jsx6("p", { children: "This page is not included in your current membership." }),
|
|
582
516
|
selected.upsell ? /* @__PURE__ */ jsxs6("aside", { className: "chapter-member-content-upsell", "aria-label": selected.upsell.label ?? "Membership option", children: [
|
|
583
|
-
/* @__PURE__ */
|
|
584
|
-
/* @__PURE__ */
|
|
585
|
-
selected.upsell.bodyMarkdown ? /* @__PURE__ */
|
|
586
|
-
href ? /* @__PURE__ */
|
|
517
|
+
/* @__PURE__ */ jsx6("h2", { children: selected.upsell.label ?? selected.upsell.tierName }),
|
|
518
|
+
/* @__PURE__ */ jsx6("p", { children: fmtMoney(selected.upsell.priceCents) }),
|
|
519
|
+
selected.upsell.bodyMarkdown ? /* @__PURE__ */ jsx6(Markdown, { source: selected.upsell.bodyMarkdown }) : null,
|
|
520
|
+
href ? /* @__PURE__ */ jsx6("a", { className: "btn primary", href, children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : onUpsell ? /* @__PURE__ */ jsx6("button", { className: "btn primary", type: "button", onClick: () => onUpsell(selected.upsell.tierId, selected), children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : null
|
|
587
521
|
] }) : null
|
|
588
522
|
] })
|
|
589
523
|
] })
|
|
@@ -591,12 +525,12 @@ function MemberContentArea(props) {
|
|
|
591
525
|
}
|
|
592
526
|
|
|
593
527
|
// src/ui/members.tsx
|
|
594
|
-
import { Fragment as Fragment3, jsx as
|
|
528
|
+
import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
|
|
595
529
|
function card(copy, kicker, body) {
|
|
596
530
|
return /* @__PURE__ */ jsxs7("div", { className: "card", children: [
|
|
597
|
-
/* @__PURE__ */
|
|
531
|
+
/* @__PURE__ */ jsx7("div", { className: "card-label", children: copy.provisional.cardLabel }),
|
|
598
532
|
/* @__PURE__ */ jsxs7("div", { className: "meeting-block", children: [
|
|
599
|
-
/* @__PURE__ */
|
|
533
|
+
/* @__PURE__ */ jsx7("div", { className: "meeting-kicker", children: kicker }),
|
|
600
534
|
body
|
|
601
535
|
] })
|
|
602
536
|
] });
|
|
@@ -608,8 +542,8 @@ function ProvisionalCard(props) {
|
|
|
608
542
|
copy,
|
|
609
543
|
copy.provisional.applicationNeeded,
|
|
610
544
|
/* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
611
|
-
/* @__PURE__ */
|
|
612
|
-
/* @__PURE__ */
|
|
545
|
+
/* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
|
|
546
|
+
/* @__PURE__ */ jsx7("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
|
|
613
547
|
] })
|
|
614
548
|
);
|
|
615
549
|
}
|
|
@@ -617,19 +551,19 @@ function ProvisionalCard(props) {
|
|
|
617
551
|
return card(
|
|
618
552
|
copy,
|
|
619
553
|
copy.provisional.refunded,
|
|
620
|
-
/* @__PURE__ */
|
|
554
|
+
/* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.refundedBody })
|
|
621
555
|
);
|
|
622
556
|
}
|
|
623
|
-
const membership = application.paid ? /* @__PURE__ */
|
|
557
|
+
const membership = application.paid ? /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: application.renewalAt ? formatChapterCopy(copy.provisional.renews, { date: fmtDate(application.renewalAt) }) : copy.provisional.active }) : null;
|
|
624
558
|
if (application.meetingAt) {
|
|
625
559
|
return card(
|
|
626
560
|
copy,
|
|
627
561
|
copy.provisional.introductionCall,
|
|
628
562
|
/* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
629
|
-
/* @__PURE__ */
|
|
630
|
-
/* @__PURE__ */
|
|
631
|
-
application.meetUrl ? /* @__PURE__ */
|
|
632
|
-
/* @__PURE__ */
|
|
563
|
+
/* @__PURE__ */ jsx7("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
|
|
564
|
+
/* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
|
|
565
|
+
application.meetUrl ? /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: /* @__PURE__ */ jsx7("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
|
|
566
|
+
/* @__PURE__ */ jsx7(
|
|
633
567
|
Rescheduler,
|
|
634
568
|
{
|
|
635
569
|
api,
|
|
@@ -647,8 +581,8 @@ function ProvisionalCard(props) {
|
|
|
647
581
|
copy,
|
|
648
582
|
copy.provisional.bookCall,
|
|
649
583
|
/* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
650
|
-
/* @__PURE__ */
|
|
651
|
-
/* @__PURE__ */
|
|
584
|
+
/* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
|
|
585
|
+
/* @__PURE__ */ jsx7(
|
|
652
586
|
Rescheduler,
|
|
653
587
|
{
|
|
654
588
|
api,
|
|
@@ -675,8 +609,8 @@ function MembersArea(props) {
|
|
|
675
609
|
renderProvisional
|
|
676
610
|
} = props;
|
|
677
611
|
const copy = props.copy ?? inheritedCopy.members;
|
|
678
|
-
const [me, setMe] =
|
|
679
|
-
const [error, setError] =
|
|
612
|
+
const [me, setMe] = useState6(null);
|
|
613
|
+
const [error, setError] = useState6(false);
|
|
680
614
|
const reload = async () => {
|
|
681
615
|
try {
|
|
682
616
|
setMe(await api("/api/me"));
|
|
@@ -687,22 +621,22 @@ function MembersArea(props) {
|
|
|
687
621
|
useEffect3(() => {
|
|
688
622
|
void reload();
|
|
689
623
|
}, []);
|
|
690
|
-
if (error) return /* @__PURE__ */
|
|
691
|
-
if (!me) return /* @__PURE__ */
|
|
624
|
+
if (error) return /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: copy.loadFailed });
|
|
625
|
+
if (!me) return /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: inheritedCopy.common.loading });
|
|
692
626
|
const role = me.role || "provisional";
|
|
693
627
|
return /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
694
628
|
/* @__PURE__ */ jsxs7("div", { className: "card", children: [
|
|
695
629
|
/* @__PURE__ */ jsxs7("div", { className: "member-row", children: [
|
|
696
|
-
/* @__PURE__ */
|
|
697
|
-
/* @__PURE__ */
|
|
630
|
+
/* @__PURE__ */ jsx7("span", { className: "member-email", children: me.email }),
|
|
631
|
+
/* @__PURE__ */ jsx7("span", { className: "role-badge " + role, children: role })
|
|
698
632
|
] }),
|
|
699
633
|
/* @__PURE__ */ jsxs7("div", { className: "account-actions", children: [
|
|
700
|
-
/* @__PURE__ */
|
|
701
|
-
role === "admin" ? /* @__PURE__ */
|
|
634
|
+
/* @__PURE__ */ jsx7("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
|
|
635
|
+
role === "admin" ? /* @__PURE__ */ jsx7("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
|
|
702
636
|
] })
|
|
703
637
|
] }),
|
|
704
638
|
role === "provisional" ? (() => {
|
|
705
|
-
const defaultContent = /* @__PURE__ */
|
|
639
|
+
const defaultContent = /* @__PURE__ */ jsx7(
|
|
706
640
|
ProvisionalCard,
|
|
707
641
|
{
|
|
708
642
|
api,
|
|
@@ -719,14 +653,14 @@ function MembersArea(props) {
|
|
|
719
653
|
reload,
|
|
720
654
|
defaultContent
|
|
721
655
|
}) ?? defaultContent;
|
|
722
|
-
})() : memberContent ?? (memberPages ? /* @__PURE__ */
|
|
656
|
+
})() : memberContent ?? (memberPages ? /* @__PURE__ */ jsx7(
|
|
723
657
|
MemberContentArea,
|
|
724
658
|
{
|
|
725
659
|
api,
|
|
726
660
|
...memberPages === true ? {} : memberPages
|
|
727
661
|
}
|
|
728
|
-
) : /* @__PURE__ */
|
|
729
|
-
/* @__PURE__ */
|
|
662
|
+
) : /* @__PURE__ */ jsx7("div", { className: "card", children: /* @__PURE__ */ jsx7("div", { className: "card-label", children: copy.full.welcome }) })),
|
|
663
|
+
/* @__PURE__ */ jsx7(GiftPurchases, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment })
|
|
730
664
|
] });
|
|
731
665
|
}
|
|
732
666
|
|
|
@@ -734,14 +668,14 @@ function MembersArea(props) {
|
|
|
734
668
|
import { useEffect as useEffect5, useRef as useRef3, useState as useState11 } from "preact/hooks";
|
|
735
669
|
|
|
736
670
|
// src/ui/join-booking.tsx
|
|
737
|
-
import { useEffect as useEffect4, useState as
|
|
738
|
-
import { jsx as
|
|
671
|
+
import { useEffect as useEffect4, useState as useState7 } from "preact/hooks";
|
|
672
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
|
|
739
673
|
function JoinBooking(props) {
|
|
740
674
|
const { applicationId, copy, onBooked, simulation } = props;
|
|
741
|
-
const [state, setState] =
|
|
742
|
-
const [msg, setMsg] =
|
|
743
|
-
const [busy, setBusy] =
|
|
744
|
-
const [selected, setSelected] =
|
|
675
|
+
const [state, setState] = useState7(null);
|
|
676
|
+
const [msg, setMsg] = useState7(null);
|
|
677
|
+
const [busy, setBusy] = useState7(false);
|
|
678
|
+
const [selected, setSelected] = useState7(null);
|
|
745
679
|
const load = async () => {
|
|
746
680
|
setMsg(null);
|
|
747
681
|
try {
|
|
@@ -798,9 +732,9 @@ function JoinBooking(props) {
|
|
|
798
732
|
setBusy(false);
|
|
799
733
|
}
|
|
800
734
|
};
|
|
801
|
-
if (!state) return /* @__PURE__ */
|
|
735
|
+
if (!state) return /* @__PURE__ */ jsx8("p", { className: "slots-status", children: msg ?? copy.loading });
|
|
802
736
|
return /* @__PURE__ */ jsxs8("div", { className: "join-book", children: [
|
|
803
|
-
/* @__PURE__ */
|
|
737
|
+
/* @__PURE__ */ jsx8(
|
|
804
738
|
SlotPicker,
|
|
805
739
|
{
|
|
806
740
|
slots: state.slots,
|
|
@@ -811,28 +745,28 @@ function JoinBooking(props) {
|
|
|
811
745
|
}
|
|
812
746
|
),
|
|
813
747
|
/* @__PURE__ */ jsxs8("div", { className: "slot-confirm", hidden: !selected, children: [
|
|
814
|
-
/* @__PURE__ */
|
|
815
|
-
msg ? /* @__PURE__ */
|
|
748
|
+
/* @__PURE__ */ jsx8("button", { className: "submit-btn", disabled: busy, onClick: () => void book(), children: busy ? copy.booking : copy.book }),
|
|
749
|
+
msg ? /* @__PURE__ */ jsx8("p", { className: "step2-note", children: msg }) : null
|
|
816
750
|
] })
|
|
817
751
|
] });
|
|
818
752
|
}
|
|
819
753
|
|
|
820
754
|
// src/ui/join-accepted.tsx
|
|
821
|
-
import { jsx as
|
|
755
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
|
|
822
756
|
function JoinAccepted(props) {
|
|
823
757
|
return /* @__PURE__ */ jsxs9("div", { className: "join-done card", children: [
|
|
824
|
-
/* @__PURE__ */
|
|
825
|
-
/* @__PURE__ */
|
|
826
|
-
/* @__PURE__ */
|
|
758
|
+
/* @__PURE__ */ jsx9("div", { className: "card-label", children: props.copy.accepted.label }),
|
|
759
|
+
/* @__PURE__ */ jsx9("p", { className: "meeting-note", children: props.copy.accepted.body }),
|
|
760
|
+
/* @__PURE__ */ jsx9("a", { className: "apply-link", href: props.membersHref, children: props.copy.done.memberArea })
|
|
827
761
|
] });
|
|
828
762
|
}
|
|
829
763
|
|
|
830
764
|
// src/ui/gift-claim-card.tsx
|
|
831
|
-
import { useState as
|
|
832
|
-
import { Fragment as Fragment4, jsx as
|
|
765
|
+
import { useState as useState8 } from "preact/hooks";
|
|
766
|
+
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
|
|
833
767
|
function GiftClaimCard(props) {
|
|
834
|
-
const [code, setCode] =
|
|
835
|
-
const [error, setError] =
|
|
768
|
+
const [code, setCode] = useState8(props.initialCode ?? "");
|
|
769
|
+
const [error, setError] = useState8(false);
|
|
836
770
|
const rotate = async () => {
|
|
837
771
|
if (!props.claimId) return;
|
|
838
772
|
setError(false);
|
|
@@ -846,20 +780,165 @@ function GiftClaimCard(props) {
|
|
|
846
780
|
else setError(true);
|
|
847
781
|
};
|
|
848
782
|
return /* @__PURE__ */ jsxs10("div", { className: "join-done card", children: [
|
|
849
|
-
/* @__PURE__ */
|
|
850
|
-
/* @__PURE__ */
|
|
783
|
+
/* @__PURE__ */ jsx10("div", { className: "card-label", children: props.copy.label }),
|
|
784
|
+
/* @__PURE__ */ jsx10("p", { className: "meeting-note", children: props.copy.body }),
|
|
851
785
|
code ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
852
|
-
/* @__PURE__ */
|
|
853
|
-
/* @__PURE__ */
|
|
786
|
+
/* @__PURE__ */ jsx10("output", { className: "gift-code", children: code }),
|
|
787
|
+
/* @__PURE__ */ jsx10("p", { children: props.copy.save })
|
|
854
788
|
] }) : null,
|
|
855
|
-
!code && props.claimId ? /* @__PURE__ */
|
|
856
|
-
error ? /* @__PURE__ */
|
|
789
|
+
!code && props.claimId ? /* @__PURE__ */ jsx10("button", { type: "button", className: "btn secondary", onClick: () => void rotate(), children: props.copy.rotate }) : null,
|
|
790
|
+
error ? /* @__PURE__ */ jsx10("p", { role: "alert", children: props.copy.rotateFailed }) : null
|
|
791
|
+
] });
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// src/ui/join-application-response.ts
|
|
795
|
+
function joinStateFromApplicationResponse(data, fallbackNeedsPayment, submittedGiftPurchase) {
|
|
796
|
+
if (!data.id) return null;
|
|
797
|
+
if (data.state === "accepted") return { step: "accepted", applicationId: data.id };
|
|
798
|
+
if (data.state === "paymentPending") return { step: "paymentPending", applicationId: data.id };
|
|
799
|
+
if (data.state === "booking") return { step: "booking", applicationId: data.id };
|
|
800
|
+
if (data.state === "payment") return {
|
|
801
|
+
step: "payment",
|
|
802
|
+
applicationId: data.id,
|
|
803
|
+
...data.giftPurchase || submittedGiftPurchase ? { giftPurchase: true } : {}
|
|
804
|
+
};
|
|
805
|
+
return fallbackNeedsPayment ? { step: "payment", applicationId: data.id, ...submittedGiftPurchase ? { giftPurchase: true } : {} } : { step: "booking", applicationId: data.id };
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// src/ui/gift-code-redeemer.tsx
|
|
809
|
+
import { InlineActionField } from "@odla-ai/ui/components";
|
|
810
|
+
import { useState as useState9 } from "preact/hooks";
|
|
811
|
+
import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
|
|
812
|
+
var GIFT_CODE_REDEEMER_CSS = `
|
|
813
|
+
.gift-code-redeemer{container-type:inline-size;display:grid;gap:var(--ui-space-1,.35rem);margin:0}
|
|
814
|
+
.gift-code-redeemer .inline-action-field-label{display:block;color:var(--ui-text-muted,#66777f);font-size:var(--ui-text-xs,.72rem);font-weight:var(--ui-weight-strong,700);letter-spacing:var(--ui-tracking-caps,.08em);text-transform:uppercase}
|
|
815
|
+
.gift-code-redeemer .inline-action-field-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--ui-space-2,.65rem);align-items:stretch}
|
|
816
|
+
.gift-code-redeemer .inline-action-field-input,.gift-code-redeemer .inline-action-field-action{min-height:var(--ui-inline-action-control-height,38px)}
|
|
817
|
+
.gift-code-redeemer .inline-action-field-input.code{font-family:var(--ui-font-mono,ui-monospace,monospace);font-variant-ligatures:none;letter-spacing:var(--ui-tracking-wide,.04em)}
|
|
818
|
+
.gift-code-redeemer .inline-action-field-input:focus-visible{outline:none;border-color:var(--ui-accent,#168c84);box-shadow:var(--ui-focus,0 0 0 3px rgb(22 140 132 / .18))}
|
|
819
|
+
.gift-code-redeemer .inline-action-field-action{white-space:nowrap}
|
|
820
|
+
.gift-code-redeemer .inline-action-field-status{display:block;min-block-size:1.4em;margin:0;color:var(--ui-text-muted,#66777f);font-size:var(--ui-text-sm,.8rem);line-height:1.4}
|
|
821
|
+
.gift-code-redeemer .inline-action-field-status.success{color:var(--ui-good,#1f7a52)}
|
|
822
|
+
.gift-code-redeemer .inline-action-field-status.error{color:var(--ui-danger,#b42318)}
|
|
823
|
+
@container (max-width:26rem){.gift-code-redeemer .inline-action-field-row{grid-template-columns:minmax(0,1fr)}.gift-code-redeemer .inline-action-field-action{width:100%}}
|
|
824
|
+
`;
|
|
825
|
+
function GiftCodeRedeemer({ api, applicationId, copy, id, onRedeemed }) {
|
|
826
|
+
const [code, setCode] = useState9("");
|
|
827
|
+
const [loading, setLoading] = useState9(false);
|
|
828
|
+
const [message, setMessage] = useState9("");
|
|
829
|
+
const [messageTone, setMessageTone] = useState9("neutral");
|
|
830
|
+
const normalizedCode = code.trim();
|
|
831
|
+
const redeem = async () => {
|
|
832
|
+
if (!normalizedCode || loading) return;
|
|
833
|
+
setLoading(true);
|
|
834
|
+
setMessage("");
|
|
835
|
+
setMessageTone("neutral");
|
|
836
|
+
try {
|
|
837
|
+
const result = await api("/api/gifts/redeem", {
|
|
838
|
+
method: "POST",
|
|
839
|
+
headers: { "content-type": "application/json" },
|
|
840
|
+
body: JSON.stringify({ code: normalizedCode, applicationId })
|
|
841
|
+
});
|
|
842
|
+
setCode("");
|
|
843
|
+
setMessage(copy.redeemed);
|
|
844
|
+
setMessageTone("success");
|
|
845
|
+
try {
|
|
846
|
+
await onRedeemed?.(result);
|
|
847
|
+
} catch {
|
|
848
|
+
}
|
|
849
|
+
} catch {
|
|
850
|
+
setMessage(copy.redeemFailed);
|
|
851
|
+
setMessageTone("error");
|
|
852
|
+
} finally {
|
|
853
|
+
setLoading(false);
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
return /* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
857
|
+
/* @__PURE__ */ jsx11("style", { children: GIFT_CODE_REDEEMER_CSS }),
|
|
858
|
+
/* @__PURE__ */ jsx11(
|
|
859
|
+
InlineActionField,
|
|
860
|
+
{
|
|
861
|
+
id,
|
|
862
|
+
className: "gift-code-redeemer",
|
|
863
|
+
label: copy.code,
|
|
864
|
+
value: code,
|
|
865
|
+
code: true,
|
|
866
|
+
actionLabel: copy.redeem,
|
|
867
|
+
loadingLabel: `${copy.redeem}\u2026`,
|
|
868
|
+
loading,
|
|
869
|
+
actionDisabled: !normalizedCode,
|
|
870
|
+
message,
|
|
871
|
+
messageTone,
|
|
872
|
+
inputProps: {
|
|
873
|
+
name: "giftCode",
|
|
874
|
+
maxLength: 64,
|
|
875
|
+
autoComplete: "one-time-code",
|
|
876
|
+
autoCapitalize: "none",
|
|
877
|
+
autocorrect: "off",
|
|
878
|
+
spellcheck: false
|
|
879
|
+
},
|
|
880
|
+
onValueChange: (value) => {
|
|
881
|
+
setCode(value);
|
|
882
|
+
if (message) {
|
|
883
|
+
setMessage("");
|
|
884
|
+
setMessageTone("neutral");
|
|
885
|
+
}
|
|
886
|
+
},
|
|
887
|
+
onAction: () => void redeem()
|
|
888
|
+
}
|
|
889
|
+
)
|
|
890
|
+
] });
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// src/ui/join-resume.ts
|
|
894
|
+
async function loadJoinResume(applicationId, fetcher = fetch) {
|
|
895
|
+
const res = await fetcher(`/api/join/resume?application=${encodeURIComponent(applicationId)}`);
|
|
896
|
+
const data = await res.json();
|
|
897
|
+
if (!res.ok) throw new Error(data.error ?? "The application could not be resumed.");
|
|
898
|
+
if (data.state === "done" && data.booked) return { step: "done", applicationId: data.applicationId, booked: data.booked };
|
|
899
|
+
if (data.state === "paymentPending") return { step: "paymentPending", applicationId: data.applicationId };
|
|
900
|
+
if (data.state === "booking") return { step: "booking", applicationId: data.applicationId };
|
|
901
|
+
if (data.state === "accepted") return { step: "accepted", applicationId: data.applicationId };
|
|
902
|
+
if (data.state === "gift") return { step: "gift", applicationId: data.applicationId, ...data.claimId ? { claimId: data.claimId } : {} };
|
|
903
|
+
return {
|
|
904
|
+
step: "payment",
|
|
905
|
+
applicationId: data.applicationId,
|
|
906
|
+
...data.giftPurchase ? { giftPurchase: true } : {}
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
// src/ui/join-gift-claim.tsx
|
|
911
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
|
|
912
|
+
function JoinGiftClaim(props) {
|
|
913
|
+
return /* @__PURE__ */ jsxs12("section", { className: "join-gift-claim card", children: [
|
|
914
|
+
/* @__PURE__ */ jsx12("div", { className: "card-label", children: props.copy.claimTitle }),
|
|
915
|
+
/* @__PURE__ */ jsx12("p", { children: props.copy.claimBody }),
|
|
916
|
+
/* @__PURE__ */ jsx12(
|
|
917
|
+
GiftCodeRedeemer,
|
|
918
|
+
{
|
|
919
|
+
api: props.api,
|
|
920
|
+
applicationId: props.applicationId,
|
|
921
|
+
copy: props.copy,
|
|
922
|
+
onRedeemed: async (result) => {
|
|
923
|
+
if (result.state === "booking" || result.state === "accepted") {
|
|
924
|
+
props.onState({ step: result.state, applicationId: result.applicationId });
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
try {
|
|
928
|
+
const resumed = props.loadResume ? await props.loadResume() : await loadJoinResume(result.applicationId);
|
|
929
|
+
if (resumed) props.onState(resumed);
|
|
930
|
+
} catch {
|
|
931
|
+
props.onError();
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
)
|
|
857
936
|
] });
|
|
858
937
|
}
|
|
859
938
|
|
|
860
939
|
// src/ui/join-tiers.tsx
|
|
861
940
|
import { useState as useState10 } from "preact/hooks";
|
|
862
|
-
import { jsx as
|
|
941
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
|
|
863
942
|
function useTierSelection(tiers, initialTierId) {
|
|
864
943
|
const [selectedTierId, setSelectedTierId] = useState10(() => {
|
|
865
944
|
const preset = tiers.find((tier) => tier.id === initialTierId);
|
|
@@ -876,10 +955,10 @@ function useTierSelection(tiers, initialTierId) {
|
|
|
876
955
|
};
|
|
877
956
|
}
|
|
878
957
|
function TierPlaceholder(context) {
|
|
879
|
-
return /* @__PURE__ */
|
|
880
|
-
/* @__PURE__ */
|
|
881
|
-
context.tiers.map((tier) => /* @__PURE__ */
|
|
882
|
-
/* @__PURE__ */
|
|
958
|
+
return /* @__PURE__ */ jsxs13("fieldset", { "data-chapter-placeholder": "tiers", children: [
|
|
959
|
+
/* @__PURE__ */ jsx13("legend", { children: "Membership (placeholder \u2014 pass renderTiers to style this)" }),
|
|
960
|
+
context.tiers.map((tier) => /* @__PURE__ */ jsxs13("label", { children: [
|
|
961
|
+
/* @__PURE__ */ jsx13(
|
|
883
962
|
"input",
|
|
884
963
|
{
|
|
885
964
|
type: "radio",
|
|
@@ -897,21 +976,8 @@ function tierNeedsPayment(selected, paymentsReady) {
|
|
|
897
976
|
return selected ? !selected.free && paymentsReady : paymentsReady;
|
|
898
977
|
}
|
|
899
978
|
|
|
900
|
-
// src/ui/join-resume.ts
|
|
901
|
-
async function loadJoinResume(applicationId, fetcher = fetch) {
|
|
902
|
-
const res = await fetcher(`/api/join/resume?application=${encodeURIComponent(applicationId)}`);
|
|
903
|
-
const data = await res.json();
|
|
904
|
-
if (!res.ok) throw new Error(data.error ?? "The application could not be resumed.");
|
|
905
|
-
if (data.state === "done" && data.booked) return { step: "done", applicationId: data.applicationId, booked: data.booked };
|
|
906
|
-
if (data.state === "paymentPending") return { step: "paymentPending", applicationId: data.applicationId };
|
|
907
|
-
if (data.state === "booking") return { step: "booking", applicationId: data.applicationId };
|
|
908
|
-
if (data.state === "accepted") return { step: "accepted", applicationId: data.applicationId };
|
|
909
|
-
if (data.state === "gift") return { step: "gift", applicationId: data.applicationId, ...data.claimId ? { claimId: data.claimId } : {} };
|
|
910
|
-
return { step: "payment", applicationId: data.applicationId };
|
|
911
|
-
}
|
|
912
|
-
|
|
913
979
|
// src/ui/join.tsx
|
|
914
|
-
import { Fragment as
|
|
980
|
+
import { Fragment as Fragment6, jsx as jsx14, jsxs as jsxs14 } from "preact/jsx-runtime";
|
|
915
981
|
function JoinIsland(props) {
|
|
916
982
|
const inheritedCopy = useChapterCopy();
|
|
917
983
|
const {
|
|
@@ -1004,22 +1070,11 @@ function JoinIsland(props) {
|
|
|
1004
1070
|
});
|
|
1005
1071
|
const data = await res.json();
|
|
1006
1072
|
if (!res.ok || !data.id) throw new Error(data.error ?? copy.form.submitFailed);
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
setState({ step: "paymentPending", applicationId: data.id });
|
|
1013
|
-
return;
|
|
1014
|
-
}
|
|
1015
|
-
if (data.state === "payment" || data.state === "booking") {
|
|
1016
|
-
setState({ step: data.state, applicationId: data.id });
|
|
1017
|
-
return;
|
|
1018
|
-
}
|
|
1019
|
-
setState({
|
|
1020
|
-
step: tierNeedsPayment(selectedTier, config.paymentsReady) ? "payment" : "booking",
|
|
1021
|
-
applicationId: data.id
|
|
1022
|
-
});
|
|
1073
|
+
setState(joinStateFromApplicationResponse(
|
|
1074
|
+
data,
|
|
1075
|
+
tierNeedsPayment(selectedTier, config.paymentsReady),
|
|
1076
|
+
Boolean(giftOfferId)
|
|
1077
|
+
));
|
|
1023
1078
|
} catch (err) {
|
|
1024
1079
|
setError(err instanceof Error ? err.message : copy.form.unexpectedFailure);
|
|
1025
1080
|
} finally {
|
|
@@ -1031,35 +1086,35 @@ function JoinIsland(props) {
|
|
|
1031
1086
|
..."applicationId" in state ? { applicationId: state.applicationId } : {}
|
|
1032
1087
|
});
|
|
1033
1088
|
if (state.step === "done") {
|
|
1034
|
-
const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */
|
|
1035
|
-
/* @__PURE__ */
|
|
1036
|
-
/* @__PURE__ */
|
|
1037
|
-
/* @__PURE__ */
|
|
1038
|
-
/* @__PURE__ */
|
|
1089
|
+
const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsxs14("div", { className: "join-done card", children: [
|
|
1090
|
+
/* @__PURE__ */ jsx14("div", { className: "card-label", children: copy.done.label }),
|
|
1091
|
+
/* @__PURE__ */ jsx14("p", { className: "meeting-date", children: fullLabel(state.booked.startAt, state.booked.timezone) }),
|
|
1092
|
+
/* @__PURE__ */ jsx14("p", { className: "meeting-note", children: copy.done.calendarInvite }),
|
|
1093
|
+
/* @__PURE__ */ jsx14("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
|
|
1039
1094
|
] });
|
|
1040
|
-
return /* @__PURE__ */
|
|
1095
|
+
return /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
1041
1096
|
header,
|
|
1042
1097
|
body
|
|
1043
1098
|
] });
|
|
1044
1099
|
}
|
|
1045
1100
|
if (state.step === "accepted") {
|
|
1046
|
-
const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */
|
|
1047
|
-
return /* @__PURE__ */
|
|
1101
|
+
const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsx14(JoinAccepted, { copy, membersHref });
|
|
1102
|
+
return /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
1048
1103
|
header,
|
|
1049
1104
|
body
|
|
1050
1105
|
] });
|
|
1051
1106
|
}
|
|
1052
1107
|
if (state.step === "gift") {
|
|
1053
|
-
const body = renderGift?.(state) ?? /* @__PURE__ */
|
|
1054
|
-
return /* @__PURE__ */
|
|
1108
|
+
const body = renderGift?.(state) ?? /* @__PURE__ */ jsx14(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
|
|
1109
|
+
return /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
1055
1110
|
header,
|
|
1056
1111
|
body
|
|
1057
1112
|
] });
|
|
1058
1113
|
}
|
|
1059
1114
|
if (state.step === "booking") {
|
|
1060
|
-
return /* @__PURE__ */
|
|
1115
|
+
return /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
1061
1116
|
header,
|
|
1062
|
-
/* @__PURE__ */
|
|
1117
|
+
/* @__PURE__ */ jsx14(
|
|
1063
1118
|
JoinBooking,
|
|
1064
1119
|
{
|
|
1065
1120
|
applicationId: state.applicationId,
|
|
@@ -1073,9 +1128,20 @@ function JoinIsland(props) {
|
|
|
1073
1128
|
] });
|
|
1074
1129
|
}
|
|
1075
1130
|
if (state.step === "payment") {
|
|
1076
|
-
return /* @__PURE__ */
|
|
1131
|
+
return /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
1077
1132
|
header,
|
|
1078
|
-
/* @__PURE__ */
|
|
1133
|
+
props.giftClaimApi && !state.giftPurchase ? /* @__PURE__ */ jsx14(
|
|
1134
|
+
JoinGiftClaim,
|
|
1135
|
+
{
|
|
1136
|
+
api: props.giftClaimApi,
|
|
1137
|
+
applicationId: state.applicationId,
|
|
1138
|
+
copy: copy.gift,
|
|
1139
|
+
loadResume: props.loadResume,
|
|
1140
|
+
onState: setState,
|
|
1141
|
+
onError: () => setError(copy.form.unexpectedFailure)
|
|
1142
|
+
}
|
|
1143
|
+
) : null,
|
|
1144
|
+
/* @__PURE__ */ jsx14(
|
|
1079
1145
|
PaymentStep,
|
|
1080
1146
|
{
|
|
1081
1147
|
applicationId: state.applicationId,
|
|
@@ -1103,25 +1169,25 @@ function JoinIsland(props) {
|
|
|
1103
1169
|
] });
|
|
1104
1170
|
}
|
|
1105
1171
|
if (state.step === "paymentPending") {
|
|
1106
|
-
return /* @__PURE__ */
|
|
1172
|
+
return /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
1107
1173
|
header,
|
|
1108
|
-
/* @__PURE__ */
|
|
1174
|
+
/* @__PURE__ */ jsx14("p", { className: "pay-status", role: "status", children: copy.payment.pending })
|
|
1109
1175
|
] });
|
|
1110
1176
|
}
|
|
1111
1177
|
const submitDisabled = submitting || props.submitDisabled === true;
|
|
1112
1178
|
const tierChooser = tiers.length > 1 ? props.renderTiers?.(tierSelection) ?? TierPlaceholder(tierSelection) : null;
|
|
1113
|
-
return /* @__PURE__ */
|
|
1179
|
+
return /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
1114
1180
|
header,
|
|
1115
|
-
/* @__PURE__ */
|
|
1116
|
-
(config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */
|
|
1117
|
-
/* @__PURE__ */
|
|
1118
|
-
/* @__PURE__ */
|
|
1119
|
-
/* @__PURE__ */
|
|
1181
|
+
/* @__PURE__ */ jsxs14("form", { className: "join-form", onSubmit: (e) => void submit(e), children: [
|
|
1182
|
+
(config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs14("fieldset", { children: [
|
|
1183
|
+
/* @__PURE__ */ jsx14("legend", { children: copy.gift.optionsLabel }),
|
|
1184
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: "btn secondary", "aria-pressed": !giftOfferId, onClick: () => setGiftOfferId(null), children: copy.gift.chooseSelf }),
|
|
1185
|
+
/* @__PURE__ */ jsx14(GiftOfferCards, { offers: config.giftOffers ?? [], mode: "select", selectedOfferId: giftOfferId, onSelect: setGiftOfferId })
|
|
1120
1186
|
] }) : null,
|
|
1121
1187
|
tierChooser,
|
|
1122
1188
|
children,
|
|
1123
|
-
error ? /* @__PURE__ */
|
|
1124
|
-
renderSubmit?.({ submitting, disabled: submitDisabled }) ?? /* @__PURE__ */
|
|
1189
|
+
error ? /* @__PURE__ */ jsx14("p", { className: "join-error", children: error }) : null,
|
|
1190
|
+
renderSubmit?.({ submitting, disabled: submitDisabled }) ?? /* @__PURE__ */ jsx14("button", { className: "submit-btn", type: "submit", disabled: submitDisabled, children: submitting ? copy.form.submitting : copy.form.submit })
|
|
1125
1191
|
] })
|
|
1126
1192
|
] });
|
|
1127
1193
|
}
|
|
@@ -1298,7 +1364,7 @@ function membershipPageDocument(input, options = {}) {
|
|
|
1298
1364
|
}
|
|
1299
1365
|
|
|
1300
1366
|
// src/ui/membership-cards.tsx
|
|
1301
|
-
import { jsx as
|
|
1367
|
+
import { jsx as jsx15, jsxs as jsxs15 } from "preact/jsx-runtime";
|
|
1302
1368
|
var MEMBERSHIP_CARD_TOKEN_DEFAULTS = Object.freeze({
|
|
1303
1369
|
"--ui-membership-grid-gap": "1.4rem",
|
|
1304
1370
|
"--ui-membership-card-padding": "2rem 1.7rem 1.8rem",
|
|
@@ -1367,67 +1433,67 @@ function membershipApplicationHref(applicationPath, tierId) {
|
|
|
1367
1433
|
}
|
|
1368
1434
|
function TierAction(props) {
|
|
1369
1435
|
if (props.mode === "select") {
|
|
1370
|
-
return /* @__PURE__ */
|
|
1436
|
+
return /* @__PURE__ */ jsxs15("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
|
|
1371
1437
|
props.label,
|
|
1372
|
-
/* @__PURE__ */
|
|
1438
|
+
/* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1373
1439
|
] });
|
|
1374
1440
|
}
|
|
1375
1441
|
if (props.mode === "preview") {
|
|
1376
|
-
return /* @__PURE__ */
|
|
1442
|
+
return /* @__PURE__ */ jsxs15("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
|
|
1377
1443
|
props.label,
|
|
1378
|
-
/* @__PURE__ */
|
|
1444
|
+
/* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1379
1445
|
] });
|
|
1380
1446
|
}
|
|
1381
|
-
return /* @__PURE__ */
|
|
1447
|
+
return /* @__PURE__ */ jsxs15("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
|
|
1382
1448
|
props.label,
|
|
1383
|
-
/* @__PURE__ */
|
|
1449
|
+
/* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1384
1450
|
] });
|
|
1385
1451
|
}
|
|
1386
1452
|
function TierCard(props) {
|
|
1387
1453
|
const { tier, presentation } = props;
|
|
1388
1454
|
const summary = presentation.summaryMarkdown ?? tier.blurb;
|
|
1389
1455
|
const action = presentation.ctaLabel ?? (tier.free ? "Join for free" : `Choose ${tier.name}`);
|
|
1390
|
-
return /* @__PURE__ */
|
|
1391
|
-
presentation.badge ? /* @__PURE__ */
|
|
1392
|
-
/* @__PURE__ */
|
|
1393
|
-
/* @__PURE__ */
|
|
1394
|
-
presentation.capacity ? /* @__PURE__ */
|
|
1395
|
-
/* @__PURE__ */
|
|
1396
|
-
/* @__PURE__ */
|
|
1456
|
+
return /* @__PURE__ */ jsxs15("article", { className: "chapter-membership-card", "data-tier-id": tier.id, "data-variant": presentation.variant ?? "standard", children: [
|
|
1457
|
+
presentation.badge ? /* @__PURE__ */ jsx15("div", { className: "chapter-membership-badge", children: presentation.badge }) : null,
|
|
1458
|
+
/* @__PURE__ */ jsx15("h3", { className: "chapter-membership-name", children: tier.name }),
|
|
1459
|
+
/* @__PURE__ */ jsxs15("div", { className: "chapter-membership-offer", "data-with-capacity": presentation.capacity ? "true" : void 0, children: [
|
|
1460
|
+
presentation.capacity ? /* @__PURE__ */ jsxs15("div", { className: "chapter-membership-capacity", "aria-label": `${presentation.capacity.total} ${presentation.capacity.label ?? "available"}`, children: [
|
|
1461
|
+
/* @__PURE__ */ jsx15("strong", { children: presentation.capacity.total.toLocaleString("en-US") }),
|
|
1462
|
+
/* @__PURE__ */ jsx15("small", { children: presentation.capacity.label ?? "available" })
|
|
1397
1463
|
] }) : null,
|
|
1398
|
-
/* @__PURE__ */
|
|
1399
|
-
presentation.priceEyebrow ? /* @__PURE__ */
|
|
1400
|
-
/* @__PURE__ */
|
|
1401
|
-
presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */
|
|
1402
|
-
/* @__PURE__ */
|
|
1403
|
-
!tier.free && presentation.billingLabel ? /* @__PURE__ */
|
|
1464
|
+
/* @__PURE__ */ jsxs15("div", { className: "chapter-membership-price-stack", children: [
|
|
1465
|
+
presentation.priceEyebrow ? /* @__PURE__ */ jsx15("p", { className: "chapter-membership-price-eyebrow", children: presentation.priceEyebrow }) : null,
|
|
1466
|
+
/* @__PURE__ */ jsxs15("div", { className: "chapter-membership-price-row", children: [
|
|
1467
|
+
presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */ jsx15("span", { className: "chapter-membership-compare", children: fmtMoney(presentation.compareAtPriceCents) }) : null,
|
|
1468
|
+
/* @__PURE__ */ jsx15("span", { className: "chapter-membership-price", children: tier.free ? "Free" : fmtMoney(tier.priceCents) }),
|
|
1469
|
+
!tier.free && presentation.billingLabel ? /* @__PURE__ */ jsx15("span", { className: "chapter-membership-billing", children: presentation.billingLabel }) : null
|
|
1404
1470
|
] })
|
|
1405
1471
|
] })
|
|
1406
1472
|
] }),
|
|
1407
|
-
presentation.priceNoteMarkdown ? /* @__PURE__ */
|
|
1408
|
-
summary ? /* @__PURE__ */
|
|
1409
|
-
presentation.benefits?.length ? /* @__PURE__ */
|
|
1410
|
-
/* @__PURE__ */
|
|
1411
|
-
/* @__PURE__ */
|
|
1473
|
+
presentation.priceNoteMarkdown ? /* @__PURE__ */ jsx15(Markdown2, { className: "chapter-membership-price-note", source: presentation.priceNoteMarkdown }) : null,
|
|
1474
|
+
summary ? /* @__PURE__ */ jsx15(Markdown2, { className: "chapter-membership-summary", source: summary }) : null,
|
|
1475
|
+
presentation.benefits?.length ? /* @__PURE__ */ jsx15("ul", { className: "chapter-membership-benefits", children: presentation.benefits.map((benefit, index) => /* @__PURE__ */ jsxs15("li", { children: [
|
|
1476
|
+
/* @__PURE__ */ jsx15("span", { className: "chapter-membership-check", "aria-hidden": "true", children: "\u2713" }),
|
|
1477
|
+
/* @__PURE__ */ jsx15(Markdown2, { className: "chapter-membership-benefit", source: benefit })
|
|
1412
1478
|
] }, `${tier.id}-benefit-${index}`)) }) : null,
|
|
1413
|
-
presentation.callout ? /* @__PURE__ */
|
|
1414
|
-
presentation.callout.label ? /* @__PURE__ */
|
|
1415
|
-
/* @__PURE__ */
|
|
1479
|
+
presentation.callout ? /* @__PURE__ */ jsxs15("aside", { className: "chapter-membership-callout", children: [
|
|
1480
|
+
presentation.callout.label ? /* @__PURE__ */ jsx15("p", { className: "chapter-membership-callout-label", children: presentation.callout.label }) : null,
|
|
1481
|
+
/* @__PURE__ */ jsx15(Markdown2, { source: presentation.callout.bodyMarkdown })
|
|
1416
1482
|
] }) : null,
|
|
1417
|
-
/* @__PURE__ */
|
|
1483
|
+
/* @__PURE__ */ jsx15(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
|
|
1418
1484
|
] });
|
|
1419
1485
|
}
|
|
1420
1486
|
function MembershipCards(props) {
|
|
1421
1487
|
const document2 = membershipPageDocument(props.document, { tiers: props.tiers });
|
|
1422
1488
|
const byId = new Map(props.tiers.map((tier) => [tier.id, tier]));
|
|
1423
1489
|
const mode = props.mode ?? "link";
|
|
1424
|
-
return /* @__PURE__ */
|
|
1425
|
-
/* @__PURE__ */
|
|
1426
|
-
/* @__PURE__ */
|
|
1490
|
+
return /* @__PURE__ */ jsxs15("section", { className: ["chapter-membership", props.className].filter(Boolean).join(" "), "data-chapter-membership": MEMBERSHIP_PAGE_RENDERER, "aria-label": props.ariaLabel ?? "Membership options", children: [
|
|
1491
|
+
/* @__PURE__ */ jsx15("style", { children: MEMBERSHIP_CARDS_CSS }),
|
|
1492
|
+
/* @__PURE__ */ jsx15("div", { className: "chapter-membership-grid", style: { "--chapter-membership-columns": String(Math.min(document2.tiers.length, 3)) }, children: document2.tiers.map((presentation) => {
|
|
1427
1493
|
const tier = byId.get(presentation.tierId);
|
|
1428
|
-
return /* @__PURE__ */
|
|
1494
|
+
return /* @__PURE__ */ jsx15(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
|
|
1429
1495
|
}) }),
|
|
1430
|
-
document2.footnoteMarkdown ? /* @__PURE__ */
|
|
1496
|
+
document2.footnoteMarkdown ? /* @__PURE__ */ jsx15(Markdown2, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
|
|
1431
1497
|
] });
|
|
1432
1498
|
}
|
|
1433
1499
|
|
|
@@ -1443,18 +1509,19 @@ export {
|
|
|
1443
1509
|
SlotPicker,
|
|
1444
1510
|
Rescheduler,
|
|
1445
1511
|
GiftOfferCards,
|
|
1446
|
-
GiftCodeRedeemer,
|
|
1447
1512
|
PaymentStep,
|
|
1513
|
+
GiftPurchases,
|
|
1448
1514
|
MemberGifts,
|
|
1449
1515
|
MemberContentArea,
|
|
1450
1516
|
MembersArea,
|
|
1517
|
+
GiftCodeRedeemer,
|
|
1518
|
+
loadJoinResume,
|
|
1451
1519
|
useTierSelection,
|
|
1452
1520
|
TierPlaceholder,
|
|
1453
1521
|
tierNeedsPayment,
|
|
1454
|
-
loadJoinResume,
|
|
1455
1522
|
JoinIsland,
|
|
1456
1523
|
MEMBERSHIP_CARD_TOKEN_DEFAULTS,
|
|
1457
1524
|
membershipApplicationHref,
|
|
1458
1525
|
MembershipCards
|
|
1459
1526
|
};
|
|
1460
|
-
//# sourceMappingURL=chunk-
|
|
1527
|
+
//# sourceMappingURL=chunk-S7CND3R5.js.map
|