@odla-ai/chapter 0.47.10 → 0.48.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 +231 -19
- package/dist/{chunk-VWDEHUNI.js → chunk-KZ2AXEZW.js} +497 -204
- package/dist/chunk-KZ2AXEZW.js.map +1 -0
- package/dist/{chunk-7MEVZEL2.js → chunk-MQ4OPZCS.js} +969 -516
- package/dist/chunk-MQ4OPZCS.js.map +1 -0
- package/dist/{copy-context-Dorxp-WK.d.ts → copy-context-BveBZglM.d.ts} +18 -7
- package/dist/index.cjs +3789 -761
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +753 -70
- package/dist/index.d.ts +753 -70
- package/dist/index.js +3782 -754
- package/dist/index.js.map +1 -1
- package/dist/testing.cjs +144 -42
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +92 -2
- package/dist/testing.d.ts +92 -2
- package/dist/testing.js +144 -42
- package/dist/testing.js.map +1 -1
- package/dist/ui/admin/index.d.ts +75 -5
- package/dist/ui/admin/index.js +3 -1
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.js +4 -2
- package/dist/ui/member/index.d.ts +9 -2
- package/dist/ui/member/index.js +1 -1
- package/dist/worker/index.cjs +9695 -4707
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +509 -9
- package/dist/worker/index.d.ts +509 -9
- package/dist/worker/index.js +8377 -3390
- package/dist/worker/index.js.map +1 -1
- package/package.json +5 -5
- package/runbooks/adopt-existing.md +44 -8
- package/dist/chunk-7MEVZEL2.js.map +0 -1
- package/dist/chunk-VWDEHUNI.js.map +0 -1
|
@@ -110,7 +110,7 @@ function SlotPicker(props) {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
// src/ui/members.tsx
|
|
113
|
-
import { useEffect as
|
|
113
|
+
import { useEffect as useEffect4, useState as useState7 } from "preact/hooks";
|
|
114
114
|
|
|
115
115
|
// src/ui/reschedule.tsx
|
|
116
116
|
import { useState as useState2 } from "preact/hooks";
|
|
@@ -439,10 +439,114 @@ function GiftPurchases(props) {
|
|
|
439
439
|
}
|
|
440
440
|
var MemberGifts = GiftPurchases;
|
|
441
441
|
|
|
442
|
+
// src/ui/member-named-seat.tsx
|
|
443
|
+
import { useEffect as useEffect2, useState as useState5 } from "preact/hooks";
|
|
444
|
+
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
|
|
445
|
+
function NamedSeatPurchase({ api }) {
|
|
446
|
+
const [data, setData] = useState5(null), [error, setError] = useState5("");
|
|
447
|
+
const [name, setName] = useState5(""), [email, setEmail] = useState5(""), [reviewing, setReviewing] = useState5(false);
|
|
448
|
+
const [terms, setTerms] = useState5(false), [pending, setPending] = useState5(false);
|
|
449
|
+
const load = async () => {
|
|
450
|
+
try {
|
|
451
|
+
const value = await api("/api/named-seat");
|
|
452
|
+
setData(value);
|
|
453
|
+
setError("");
|
|
454
|
+
if (value.seat) {
|
|
455
|
+
setName(value.seat.recipientName);
|
|
456
|
+
setEmail(value.seat.recipientEmail);
|
|
457
|
+
}
|
|
458
|
+
} catch {
|
|
459
|
+
setError("The named-seat service is unavailable. Refresh to check your purchase before trying again.");
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
useEffect2(() => {
|
|
463
|
+
void load();
|
|
464
|
+
}, []);
|
|
465
|
+
const money = data ? new Intl.NumberFormat("en-US", { style: "currency", currency: data.currency }).format(data.amountCents / 100) : "";
|
|
466
|
+
return /* @__PURE__ */ jsxs6("section", { className: "card member-named-seat", "aria-label": "Named additional seat", children: [
|
|
467
|
+
/* @__PURE__ */ jsx6("h2", { children: "Named additional seat" }),
|
|
468
|
+
error ? /* @__PURE__ */ jsx6("p", { role: "alert", children: error }) : null,
|
|
469
|
+
data ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
470
|
+
data.seat ? /* @__PURE__ */ jsxs6("p", { children: [
|
|
471
|
+
data.seat.recipientName,
|
|
472
|
+
" \xB7 ",
|
|
473
|
+
data.seat.recipientEmail,
|
|
474
|
+
" \xB7 ",
|
|
475
|
+
data.seat.status.replaceAll("_", " ")
|
|
476
|
+
] }) : null,
|
|
477
|
+
data.eligible ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
478
|
+
/* @__PURE__ */ jsxs6("p", { children: [
|
|
479
|
+
money,
|
|
480
|
+
" paid in full now. This seat ",
|
|
481
|
+
data.autoRenew ? "renews with your primary membership" : "ends with your primary membership",
|
|
482
|
+
" on ",
|
|
483
|
+
new Date(data.termEndsAt).toLocaleDateString("en-US", { timeZone: "UTC" }),
|
|
484
|
+
".",
|
|
485
|
+
data.autoRenew ? ` Renewal then repeats every ${data.interval}; cancel renewal through your primary membership.` : " Your primary membership renewal is canceled; buying this seat does not turn it back on.",
|
|
486
|
+
" ",
|
|
487
|
+
"It belongs to one named person and cannot be reassigned."
|
|
488
|
+
] }),
|
|
489
|
+
/* @__PURE__ */ jsx6("p", { children: "The recipient must accept and complete their own application and any required interview. An unaccepted seat is fully refunded after 30 days." }),
|
|
490
|
+
!reviewing ? /* @__PURE__ */ jsxs6("form", { onSubmit: (event) => {
|
|
491
|
+
event.preventDefault();
|
|
492
|
+
setReviewing(true);
|
|
493
|
+
setTerms(false);
|
|
494
|
+
}, children: [
|
|
495
|
+
/* @__PURE__ */ jsxs6("label", { children: [
|
|
496
|
+
"Recipient name",
|
|
497
|
+
/* @__PURE__ */ jsx6("input", { required: true, maxLength: 160, value: name, disabled: Boolean(data.seat), onInput: (event) => setName(event.currentTarget.value) })
|
|
498
|
+
] }),
|
|
499
|
+
/* @__PURE__ */ jsxs6("label", { children: [
|
|
500
|
+
"Recipient email",
|
|
501
|
+
/* @__PURE__ */ jsx6("input", { required: true, type: "email", maxLength: 254, value: email, disabled: Boolean(data.seat), onInput: (event) => setEmail(event.currentTarget.value) })
|
|
502
|
+
] }),
|
|
503
|
+
/* @__PURE__ */ jsx6("button", { className: "btn primary", type: "submit", children: "Review named seat" })
|
|
504
|
+
] }) : /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
505
|
+
/* @__PURE__ */ jsxs6("p", { children: [
|
|
506
|
+
"For ",
|
|
507
|
+
name,
|
|
508
|
+
" \xB7 ",
|
|
509
|
+
email
|
|
510
|
+
] }),
|
|
511
|
+
/* @__PURE__ */ jsx6("button", { className: "btn secondary", type: "button", onClick: () => {
|
|
512
|
+
setReviewing(false);
|
|
513
|
+
setTerms(false);
|
|
514
|
+
void load();
|
|
515
|
+
}, children: "Back to recipient" }),
|
|
516
|
+
/* @__PURE__ */ jsxs6("label", { children: [
|
|
517
|
+
/* @__PURE__ */ jsx6("input", { type: "checkbox", checked: terms, onChange: (event) => setTerms(event.currentTarget.checked) }),
|
|
518
|
+
data.autoRenew ? "I agree to the full initial payment and automatic renewal with my membership; I can cancel renewal." : "I agree to the full initial payment and the displayed end date, with no automatic renewal while my membership renewal is canceled."
|
|
519
|
+
] }),
|
|
520
|
+
terms ? /* @__PURE__ */ jsx6(
|
|
521
|
+
PaymentStep,
|
|
522
|
+
{
|
|
523
|
+
applicationId: data.membershipId,
|
|
524
|
+
refundPolicyText: data.refundPolicyText,
|
|
525
|
+
merchantDisclosureText: data.merchantDisclosureText,
|
|
526
|
+
startCheckout: () => api("/api/named-seat/checkout", {
|
|
527
|
+
method: "POST",
|
|
528
|
+
headers: { "content-type": "application/json" },
|
|
529
|
+
body: JSON.stringify({ recipientName: name, recipientEmail: email, quoteDigest: data.digest, seatTermsAck: true, refundPolicyAck: true })
|
|
530
|
+
}),
|
|
531
|
+
onPaid: () => {
|
|
532
|
+
setPending(true);
|
|
533
|
+
setReviewing(false);
|
|
534
|
+
void load();
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
) : null
|
|
538
|
+
] })
|
|
539
|
+
] }) : !data.seat ? /* @__PURE__ */ jsx6("p", { children: "Additional seats are offered only during the first three months of a paid membership." }) : null,
|
|
540
|
+
pending ? /* @__PURE__ */ jsx6("p", { role: "status", children: "Payment confirmation is being reconciled. The recipient\u2019s access begins only after their own acceptance and approval." }) : null
|
|
541
|
+
] }) : !error ? /* @__PURE__ */ jsx6("p", { children: "Loading your seat terms\u2026" }) : null,
|
|
542
|
+
/* @__PURE__ */ jsx6("button", { className: "btn secondary", onClick: () => void load(), children: "Refresh seat status" })
|
|
543
|
+
] });
|
|
544
|
+
}
|
|
545
|
+
|
|
442
546
|
// src/ui/member-content.tsx
|
|
443
|
-
import { useEffect as
|
|
547
|
+
import { useEffect as useEffect3, useMemo as useMemo2, useState as useState6 } from "preact/hooks";
|
|
444
548
|
import { Markdown } from "@odla-ai/ui/components";
|
|
445
|
-
import { Fragment as
|
|
549
|
+
import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
|
|
446
550
|
var pageLabel = (page) => `${page.title}${page.access === "locked" ? " \xB7 Locked" : ""}`;
|
|
447
551
|
function MemberContentArea(props) {
|
|
448
552
|
const {
|
|
@@ -450,15 +554,15 @@ function MemberContentArea(props) {
|
|
|
450
554
|
path = "/api/member-content",
|
|
451
555
|
upsellHref,
|
|
452
556
|
onUpsell,
|
|
453
|
-
loadingContent = /* @__PURE__ */
|
|
454
|
-
emptyContent = /* @__PURE__ */
|
|
557
|
+
loadingContent = /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: "Loading member pages\u2026" }),
|
|
558
|
+
emptyContent = /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: "No member pages have been published yet." })
|
|
455
559
|
} = props;
|
|
456
|
-
const [data, setData] =
|
|
457
|
-
const [error, setError] =
|
|
458
|
-
const [selectedId, setSelectedId] =
|
|
560
|
+
const [data, setData] = useState6(props.initialData ?? null);
|
|
561
|
+
const [error, setError] = useState6(null);
|
|
562
|
+
const [selectedId, setSelectedId] = useState6(
|
|
459
563
|
props.initialPageId ?? props.initialData?.pages[0]?.id ?? ""
|
|
460
564
|
);
|
|
461
|
-
|
|
565
|
+
useEffect3(() => {
|
|
462
566
|
if (props.initialData) return;
|
|
463
567
|
let live = true;
|
|
464
568
|
setError(null);
|
|
@@ -480,18 +584,18 @@ function MemberContentArea(props) {
|
|
|
480
584
|
}
|
|
481
585
|
return [...result.entries()];
|
|
482
586
|
}, [data]);
|
|
483
|
-
if (error) return /* @__PURE__ */
|
|
587
|
+
if (error) return /* @__PURE__ */ jsxs7("p", { className: "meeting-note", role: "alert", children: [
|
|
484
588
|
"Member pages could not be loaded: ",
|
|
485
589
|
error
|
|
486
590
|
] });
|
|
487
|
-
if (!data) return /* @__PURE__ */
|
|
488
|
-
if (data.pages.length === 0) return /* @__PURE__ */
|
|
591
|
+
if (!data) return /* @__PURE__ */ jsx7(Fragment3, { children: loadingContent });
|
|
592
|
+
if (data.pages.length === 0) return /* @__PURE__ */ jsx7(Fragment3, { children: emptyContent });
|
|
489
593
|
const selected = data.pages.find((page) => page.id === selectedId) ?? data.pages[0];
|
|
490
594
|
const href = selected.upsell && upsellHref ? upsellHref(selected.upsell.tierId, selected) : void 0;
|
|
491
|
-
return /* @__PURE__ */
|
|
492
|
-
/* @__PURE__ */
|
|
493
|
-
/* @__PURE__ */
|
|
494
|
-
/* @__PURE__ */
|
|
595
|
+
return /* @__PURE__ */ jsxs7("div", { className: "chapter-member-content", "data-member-content": true, children: [
|
|
596
|
+
/* @__PURE__ */ jsx7("nav", { className: "chapter-member-content-nav", "aria-label": "Member pages", children: sections.map(([section, pages]) => /* @__PURE__ */ jsxs7("section", { className: "chapter-member-content-section", children: [
|
|
597
|
+
/* @__PURE__ */ jsx7("h2", { children: section }),
|
|
598
|
+
/* @__PURE__ */ jsx7("ul", { children: pages.map((page) => /* @__PURE__ */ jsx7("li", { "data-parent-page": page.navigation.parentId ?? void 0, children: /* @__PURE__ */ jsx7(
|
|
495
599
|
"button",
|
|
496
600
|
{
|
|
497
601
|
type: "button",
|
|
@@ -501,23 +605,23 @@ function MemberContentArea(props) {
|
|
|
501
605
|
}
|
|
502
606
|
) }, page.id)) })
|
|
503
607
|
] }, section)) }),
|
|
504
|
-
/* @__PURE__ */
|
|
505
|
-
/* @__PURE__ */
|
|
506
|
-
/* @__PURE__ */
|
|
608
|
+
/* @__PURE__ */ jsxs7("article", { className: "chapter-member-content-page", "data-access": selected.access, children: [
|
|
609
|
+
/* @__PURE__ */ jsxs7("header", { children: [
|
|
610
|
+
/* @__PURE__ */ jsxs7("div", { className: "card-label", children: [
|
|
507
611
|
selected.source.type === "parent" ? "Parent" : "Chapter",
|
|
508
612
|
" \xB7 ",
|
|
509
613
|
selected.access
|
|
510
614
|
] }),
|
|
511
|
-
/* @__PURE__ */
|
|
512
|
-
selected.summary ? /* @__PURE__ */
|
|
615
|
+
/* @__PURE__ */ jsx7("h1", { children: selected.title }),
|
|
616
|
+
selected.summary ? /* @__PURE__ */ jsx7("p", { children: selected.summary }) : null
|
|
513
617
|
] }),
|
|
514
|
-
selected.access === "allowed" && selected.bodyMarkdown ? /* @__PURE__ */
|
|
515
|
-
selected.teaserMarkdown ? /* @__PURE__ */
|
|
516
|
-
selected.upsell ? /* @__PURE__ */
|
|
517
|
-
/* @__PURE__ */
|
|
518
|
-
/* @__PURE__ */
|
|
519
|
-
selected.upsell.bodyMarkdown ? /* @__PURE__ */
|
|
520
|
-
href ? /* @__PURE__ */
|
|
618
|
+
selected.access === "allowed" && selected.bodyMarkdown ? /* @__PURE__ */ jsx7(Markdown, { source: selected.bodyMarkdown }) : /* @__PURE__ */ jsxs7("div", { className: "chapter-member-content-locked", children: [
|
|
619
|
+
selected.teaserMarkdown ? /* @__PURE__ */ jsx7(Markdown, { source: selected.teaserMarkdown }) : /* @__PURE__ */ jsx7("p", { children: "This page is not included in your current membership." }),
|
|
620
|
+
selected.upsell ? /* @__PURE__ */ jsxs7("aside", { className: "chapter-member-content-upsell", "aria-label": selected.upsell.label ?? "Membership option", children: [
|
|
621
|
+
/* @__PURE__ */ jsx7("h2", { children: selected.upsell.label ?? selected.upsell.tierName }),
|
|
622
|
+
/* @__PURE__ */ jsx7("p", { children: fmtMoney(selected.upsell.priceCents) }),
|
|
623
|
+
selected.upsell.bodyMarkdown ? /* @__PURE__ */ jsx7(Markdown, { source: selected.upsell.bodyMarkdown }) : null,
|
|
624
|
+
href ? /* @__PURE__ */ jsx7("a", { className: "btn primary", href, children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : onUpsell ? /* @__PURE__ */ jsx7("button", { className: "btn primary", type: "button", onClick: () => onUpsell(selected.upsell.tierId, selected), children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : null
|
|
521
625
|
] }) : null
|
|
522
626
|
] })
|
|
523
627
|
] })
|
|
@@ -525,12 +629,12 @@ function MemberContentArea(props) {
|
|
|
525
629
|
}
|
|
526
630
|
|
|
527
631
|
// src/ui/members.tsx
|
|
528
|
-
import { Fragment as
|
|
632
|
+
import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
|
|
529
633
|
function card(copy, kicker, body) {
|
|
530
|
-
return /* @__PURE__ */
|
|
531
|
-
/* @__PURE__ */
|
|
532
|
-
/* @__PURE__ */
|
|
533
|
-
/* @__PURE__ */
|
|
634
|
+
return /* @__PURE__ */ jsxs8("div", { className: "card", children: [
|
|
635
|
+
/* @__PURE__ */ jsx8("div", { className: "card-label", children: copy.provisional.cardLabel }),
|
|
636
|
+
/* @__PURE__ */ jsxs8("div", { className: "meeting-block", children: [
|
|
637
|
+
/* @__PURE__ */ jsx8("div", { className: "meeting-kicker", children: kicker }),
|
|
534
638
|
body
|
|
535
639
|
] })
|
|
536
640
|
] });
|
|
@@ -541,9 +645,9 @@ function ProvisionalCard(props) {
|
|
|
541
645
|
return card(
|
|
542
646
|
copy,
|
|
543
647
|
copy.provisional.applicationNeeded,
|
|
544
|
-
/* @__PURE__ */
|
|
545
|
-
/* @__PURE__ */
|
|
546
|
-
/* @__PURE__ */
|
|
648
|
+
/* @__PURE__ */ jsxs8(Fragment4, { children: [
|
|
649
|
+
/* @__PURE__ */ jsx8("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
|
|
650
|
+
/* @__PURE__ */ jsx8("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
|
|
547
651
|
] })
|
|
548
652
|
);
|
|
549
653
|
}
|
|
@@ -551,19 +655,19 @@ function ProvisionalCard(props) {
|
|
|
551
655
|
return card(
|
|
552
656
|
copy,
|
|
553
657
|
copy.provisional.refunded,
|
|
554
|
-
/* @__PURE__ */
|
|
658
|
+
/* @__PURE__ */ jsx8("div", { className: "meeting-note", children: copy.provisional.refundedBody })
|
|
555
659
|
);
|
|
556
660
|
}
|
|
557
|
-
const membership = application.paid ? /* @__PURE__ */
|
|
661
|
+
const membership = application.paid ? /* @__PURE__ */ jsx8("div", { className: "meeting-note", children: application.renewalAt ? formatChapterCopy(copy.provisional.renews, { date: fmtDate(application.renewalAt) }) : copy.provisional.active }) : null;
|
|
558
662
|
if (application.meetingAt) {
|
|
559
663
|
return card(
|
|
560
664
|
copy,
|
|
561
665
|
copy.provisional.introductionCall,
|
|
562
|
-
/* @__PURE__ */
|
|
563
|
-
/* @__PURE__ */
|
|
564
|
-
/* @__PURE__ */
|
|
565
|
-
application.meetUrl ? /* @__PURE__ */
|
|
566
|
-
/* @__PURE__ */
|
|
666
|
+
/* @__PURE__ */ jsxs8(Fragment4, { children: [
|
|
667
|
+
/* @__PURE__ */ jsx8("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
|
|
668
|
+
/* @__PURE__ */ jsx8("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
|
|
669
|
+
application.meetUrl ? /* @__PURE__ */ jsx8("div", { className: "meeting-note", children: /* @__PURE__ */ jsx8("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
|
|
670
|
+
/* @__PURE__ */ jsx8(
|
|
567
671
|
Rescheduler,
|
|
568
672
|
{
|
|
569
673
|
api,
|
|
@@ -580,9 +684,9 @@ function ProvisionalCard(props) {
|
|
|
580
684
|
return card(
|
|
581
685
|
copy,
|
|
582
686
|
copy.provisional.bookCall,
|
|
583
|
-
/* @__PURE__ */
|
|
584
|
-
/* @__PURE__ */
|
|
585
|
-
/* @__PURE__ */
|
|
687
|
+
/* @__PURE__ */ jsxs8(Fragment4, { children: [
|
|
688
|
+
/* @__PURE__ */ jsx8("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
|
|
689
|
+
/* @__PURE__ */ jsx8(
|
|
586
690
|
Rescheduler,
|
|
587
691
|
{
|
|
588
692
|
api,
|
|
@@ -609,8 +713,8 @@ function MembersArea(props) {
|
|
|
609
713
|
renderProvisional
|
|
610
714
|
} = props;
|
|
611
715
|
const copy = props.copy ?? inheritedCopy.members;
|
|
612
|
-
const [me, setMe] =
|
|
613
|
-
const [error, setError] =
|
|
716
|
+
const [me, setMe] = useState7(null);
|
|
717
|
+
const [error, setError] = useState7(false);
|
|
614
718
|
const reload = async () => {
|
|
615
719
|
try {
|
|
616
720
|
setMe(await api("/api/me"));
|
|
@@ -618,25 +722,25 @@ function MembersArea(props) {
|
|
|
618
722
|
setError(true);
|
|
619
723
|
}
|
|
620
724
|
};
|
|
621
|
-
|
|
725
|
+
useEffect4(() => {
|
|
622
726
|
void reload();
|
|
623
727
|
}, []);
|
|
624
|
-
if (error) return /* @__PURE__ */
|
|
625
|
-
if (!me) return /* @__PURE__ */
|
|
728
|
+
if (error) return /* @__PURE__ */ jsx8("p", { className: "meeting-note", children: copy.loadFailed });
|
|
729
|
+
if (!me) return /* @__PURE__ */ jsx8("p", { className: "meeting-note", children: inheritedCopy.common.loading });
|
|
626
730
|
const role = me.role || "provisional";
|
|
627
|
-
return /* @__PURE__ */
|
|
628
|
-
/* @__PURE__ */
|
|
629
|
-
/* @__PURE__ */
|
|
630
|
-
/* @__PURE__ */
|
|
631
|
-
/* @__PURE__ */
|
|
731
|
+
return /* @__PURE__ */ jsxs8(Fragment4, { children: [
|
|
732
|
+
/* @__PURE__ */ jsxs8("div", { className: "card", children: [
|
|
733
|
+
/* @__PURE__ */ jsxs8("div", { className: "member-row", children: [
|
|
734
|
+
/* @__PURE__ */ jsx8("span", { className: "member-email", children: me.email }),
|
|
735
|
+
/* @__PURE__ */ jsx8("span", { className: "role-badge " + role, children: role })
|
|
632
736
|
] }),
|
|
633
|
-
/* @__PURE__ */
|
|
634
|
-
/* @__PURE__ */
|
|
635
|
-
|
|
737
|
+
/* @__PURE__ */ jsxs8("div", { className: "account-actions", children: [
|
|
738
|
+
/* @__PURE__ */ jsx8("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
|
|
739
|
+
me.authorized || me.superAdmin ? /* @__PURE__ */ jsx8("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
|
|
636
740
|
] })
|
|
637
741
|
] }),
|
|
638
|
-
|
|
639
|
-
const defaultContent = /* @__PURE__ */
|
|
742
|
+
me.memberAccess !== true ? (() => {
|
|
743
|
+
const defaultContent = /* @__PURE__ */ jsx8(
|
|
640
744
|
ProvisionalCard,
|
|
641
745
|
{
|
|
642
746
|
api,
|
|
@@ -653,29 +757,128 @@ function MembersArea(props) {
|
|
|
653
757
|
reload,
|
|
654
758
|
defaultContent
|
|
655
759
|
}) ?? defaultContent;
|
|
656
|
-
})() : memberContent ?? (memberPages ? /* @__PURE__ */
|
|
760
|
+
})() : memberContent ?? (memberPages ? /* @__PURE__ */ jsx8(
|
|
657
761
|
MemberContentArea,
|
|
658
762
|
{
|
|
659
763
|
api,
|
|
660
764
|
...memberPages === true ? {} : memberPages
|
|
661
765
|
}
|
|
662
|
-
) : /* @__PURE__ */
|
|
663
|
-
/* @__PURE__ */
|
|
766
|
+
) : /* @__PURE__ */ jsx8("div", { className: "card", children: /* @__PURE__ */ jsx8("div", { className: "card-label", children: copy.full.welcome }) })),
|
|
767
|
+
/* @__PURE__ */ jsx8(GiftPurchases, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment }),
|
|
768
|
+
me.namedSeatsEnabled ? /* @__PURE__ */ jsx8(NamedSeatPurchase, { api }) : null
|
|
664
769
|
] });
|
|
665
770
|
}
|
|
666
771
|
|
|
667
772
|
// src/ui/join.tsx
|
|
668
|
-
import { useEffect as
|
|
773
|
+
import { useEffect as useEffect8, useRef as useRef3, useState as useState14 } from "preact/hooks";
|
|
774
|
+
|
|
775
|
+
// src/ui/membership-payment-step.tsx
|
|
776
|
+
import { useEffect as useEffect5, useState as useState8 } from "preact/hooks";
|
|
777
|
+
import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
|
|
778
|
+
function MembershipPaymentStep(props) {
|
|
779
|
+
const inherited = useChapterCopy();
|
|
780
|
+
const copy = props.copy ?? inherited.join.payment;
|
|
781
|
+
const [quote, setQuote] = useState8(null);
|
|
782
|
+
const [error, setError] = useState8(false);
|
|
783
|
+
const [revision, setRevision] = useState8(0);
|
|
784
|
+
useEffect5(() => {
|
|
785
|
+
let live = true;
|
|
786
|
+
setQuote(null);
|
|
787
|
+
setError(false);
|
|
788
|
+
void fetch(`/api/payments/quote?application=${encodeURIComponent(props.applicationId)}`, { method: "POST", cache: "no-store" }).then(async (response) => {
|
|
789
|
+
if (!response.ok) throw new Error("quote unavailable");
|
|
790
|
+
const value = await response.json();
|
|
791
|
+
if (value.applicationId !== props.applicationId || !/^[a-f0-9]{64}$/.test(value.digest) || !/^[a-z]{3}$/.test(value.currency) || !Number.isSafeInteger(value.lineItems?.dueTodayCents) || value.lineItems.dueTodayCents <= 0 || typeof value.refundPolicyText !== "string") throw new Error("invalid quote");
|
|
792
|
+
if (live) setQuote(value);
|
|
793
|
+
}).catch(() => {
|
|
794
|
+
if (live) setError(true);
|
|
795
|
+
});
|
|
796
|
+
return () => {
|
|
797
|
+
live = false;
|
|
798
|
+
};
|
|
799
|
+
}, [props.applicationId, revision]);
|
|
800
|
+
const refresh = () => {
|
|
801
|
+
setQuote(null);
|
|
802
|
+
setRevision((value) => value + 1);
|
|
803
|
+
};
|
|
804
|
+
if (!quote || quote.applicationId !== props.applicationId) return /* @__PURE__ */ jsxs9("div", { className: "join-pay", role: "status", children: [
|
|
805
|
+
props.merchantDisclosureText ? /* @__PURE__ */ jsx9("p", { className: "compliance-merchant", children: props.merchantDisclosureText }) : null,
|
|
806
|
+
/* @__PURE__ */ jsx9("p", { children: error ? copy.setupFailed : copy.preparing }),
|
|
807
|
+
error ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: refresh, children: "Reload payment terms" }) : null
|
|
808
|
+
] });
|
|
809
|
+
const startCheckout = async () => {
|
|
810
|
+
const response = await fetch("/api/payments/subscription", {
|
|
811
|
+
method: "POST",
|
|
812
|
+
headers: { "content-type": "application/json" },
|
|
813
|
+
body: JSON.stringify({ applicationId: props.applicationId, refundPolicyAck: true, quoteDigest: quote.digest })
|
|
814
|
+
});
|
|
815
|
+
if (!response.ok) {
|
|
816
|
+
if (response.status === 409) refresh();
|
|
817
|
+
throw new Error(copy.setupFailed);
|
|
818
|
+
}
|
|
819
|
+
return response.json();
|
|
820
|
+
};
|
|
821
|
+
const amount = (cents) => new Intl.NumberFormat("en-US", { style: "currency", currency: quote.currency }).format(cents / 100);
|
|
822
|
+
return /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
823
|
+
/* @__PURE__ */ jsxs9("section", { className: "payment-quote", "aria-label": "Membership price", children: [
|
|
824
|
+
/* @__PURE__ */ jsx9("h3", { children: quote.tierName }),
|
|
825
|
+
props.renderPriceLines ? props.renderPriceLines(quote.lineItems) : /* @__PURE__ */ jsxs9("dl", { children: [
|
|
826
|
+
/* @__PURE__ */ jsx9("dt", { children: "Membership price" }),
|
|
827
|
+
/* @__PURE__ */ jsxs9("dd", { children: [
|
|
828
|
+
amount(quote.lineItems.standardCents),
|
|
829
|
+
" per ",
|
|
830
|
+
quote.interval
|
|
831
|
+
] }),
|
|
832
|
+
quote.lineItems.discountCents > 0 ? /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
833
|
+
/* @__PURE__ */ jsx9("dt", { children: "Discount" }),
|
|
834
|
+
/* @__PURE__ */ jsx9("dd", { children: amount(quote.lineItems.discountCents) })
|
|
835
|
+
] }) : null,
|
|
836
|
+
/* @__PURE__ */ jsx9("dt", { children: "Due today" }),
|
|
837
|
+
/* @__PURE__ */ jsx9("dd", { children: amount(quote.lineItems.dueTodayCents) })
|
|
838
|
+
] }),
|
|
839
|
+
quote.commercial ? /* @__PURE__ */ jsxs9("div", { role: "note", "aria-label": "Renewal terms", children: [
|
|
840
|
+
quote.commercial.initialTermEndsAt !== void 0 ? /* @__PURE__ */ jsxs9("p", { children: [
|
|
841
|
+
"First renewal: ",
|
|
842
|
+
new Intl.DateTimeFormat("en-US", {
|
|
843
|
+
dateStyle: "long",
|
|
844
|
+
timeZone: "UTC"
|
|
845
|
+
}).format(quote.commercial.initialTermEndsAt),
|
|
846
|
+
"."
|
|
847
|
+
] }) : null,
|
|
848
|
+
/* @__PURE__ */ jsxs9("p", { children: [
|
|
849
|
+
"Renews automatically at ",
|
|
850
|
+
amount(quote.commercial.renewalCents),
|
|
851
|
+
" per ",
|
|
852
|
+
quote.interval,
|
|
853
|
+
" unless canceled before renewal."
|
|
854
|
+
] }),
|
|
855
|
+
quote.commercial.discountDuration === "first_term" ? /* @__PURE__ */ jsx9("p", { children: "The discount applies to your first paid term only." }) : null,
|
|
856
|
+
quote.commercial.discountDuration === "while_active" ? /* @__PURE__ */ jsx9("p", { children: "The discounted rate continues while this membership stays active." }) : null
|
|
857
|
+
] }) : null,
|
|
858
|
+
quote.trustCopy ? /* @__PURE__ */ jsx9("p", { className: "pay-trust", children: quote.trustCopy }) : null
|
|
859
|
+
] }),
|
|
860
|
+
/* @__PURE__ */ jsx9(
|
|
861
|
+
PaymentStep,
|
|
862
|
+
{
|
|
863
|
+
...props,
|
|
864
|
+
refundPolicyText: quote.refundPolicyText,
|
|
865
|
+
merchantDisclosureText: quote.merchantDisclosureText,
|
|
866
|
+
renderPriceLines: void 0,
|
|
867
|
+
startCheckout
|
|
868
|
+
}
|
|
869
|
+
)
|
|
870
|
+
] });
|
|
871
|
+
}
|
|
669
872
|
|
|
670
873
|
// src/ui/join-booking.tsx
|
|
671
|
-
import { useEffect as
|
|
672
|
-
import { jsx as
|
|
874
|
+
import { useEffect as useEffect6, useState as useState9 } from "preact/hooks";
|
|
875
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
|
|
673
876
|
function JoinBooking(props) {
|
|
674
877
|
const { applicationId, copy, onBooked, simulation } = props;
|
|
675
|
-
const [state, setState] =
|
|
676
|
-
const [msg, setMsg] =
|
|
677
|
-
const [busy, setBusy] =
|
|
678
|
-
const [selected, setSelected] =
|
|
878
|
+
const [state, setState] = useState9(null);
|
|
879
|
+
const [msg, setMsg] = useState9(null);
|
|
880
|
+
const [busy, setBusy] = useState9(false);
|
|
881
|
+
const [selected, setSelected] = useState9(null);
|
|
679
882
|
const load = async () => {
|
|
680
883
|
setMsg(null);
|
|
681
884
|
try {
|
|
@@ -700,7 +903,7 @@ function JoinBooking(props) {
|
|
|
700
903
|
setMsg(copy.loadFailed);
|
|
701
904
|
}
|
|
702
905
|
};
|
|
703
|
-
|
|
906
|
+
useEffect6(() => {
|
|
704
907
|
void load();
|
|
705
908
|
}, [simulation]);
|
|
706
909
|
const book = async () => {
|
|
@@ -732,9 +935,9 @@ function JoinBooking(props) {
|
|
|
732
935
|
setBusy(false);
|
|
733
936
|
}
|
|
734
937
|
};
|
|
735
|
-
if (!state) return /* @__PURE__ */
|
|
736
|
-
return /* @__PURE__ */
|
|
737
|
-
/* @__PURE__ */
|
|
938
|
+
if (!state) return /* @__PURE__ */ jsx10("p", { className: "slots-status", children: msg ?? copy.loading });
|
|
939
|
+
return /* @__PURE__ */ jsxs10("div", { className: "join-book", children: [
|
|
940
|
+
/* @__PURE__ */ jsx10(
|
|
738
941
|
SlotPicker,
|
|
739
942
|
{
|
|
740
943
|
slots: state.slots,
|
|
@@ -744,29 +947,29 @@ function JoinBooking(props) {
|
|
|
744
947
|
onDayChange: () => setSelected(null)
|
|
745
948
|
}
|
|
746
949
|
),
|
|
747
|
-
/* @__PURE__ */
|
|
748
|
-
/* @__PURE__ */
|
|
749
|
-
msg ? /* @__PURE__ */
|
|
950
|
+
/* @__PURE__ */ jsxs10("div", { className: "slot-confirm", hidden: !selected, children: [
|
|
951
|
+
/* @__PURE__ */ jsx10("button", { className: "submit-btn", disabled: busy, onClick: () => void book(), children: busy ? copy.booking : copy.book }),
|
|
952
|
+
msg ? /* @__PURE__ */ jsx10("p", { className: "step2-note", children: msg }) : null
|
|
750
953
|
] })
|
|
751
954
|
] });
|
|
752
955
|
}
|
|
753
956
|
|
|
754
957
|
// src/ui/join-accepted.tsx
|
|
755
|
-
import { jsx as
|
|
958
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
|
|
756
959
|
function JoinAccepted(props) {
|
|
757
|
-
return /* @__PURE__ */
|
|
758
|
-
/* @__PURE__ */
|
|
759
|
-
/* @__PURE__ */
|
|
760
|
-
/* @__PURE__ */
|
|
960
|
+
return /* @__PURE__ */ jsxs11("div", { className: "join-done card", children: [
|
|
961
|
+
/* @__PURE__ */ jsx11("div", { className: "card-label", children: props.copy.accepted.label }),
|
|
962
|
+
/* @__PURE__ */ jsx11("p", { className: "meeting-note", children: props.copy.accepted.body }),
|
|
963
|
+
/* @__PURE__ */ jsx11("a", { className: "apply-link", href: props.membersHref, children: props.copy.done.memberArea })
|
|
761
964
|
] });
|
|
762
965
|
}
|
|
763
966
|
|
|
764
967
|
// src/ui/gift-claim-card.tsx
|
|
765
|
-
import { useState as
|
|
766
|
-
import { Fragment as
|
|
968
|
+
import { useState as useState10 } from "preact/hooks";
|
|
969
|
+
import { Fragment as Fragment6, jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
|
|
767
970
|
function GiftClaimCard(props) {
|
|
768
|
-
const [code, setCode] =
|
|
769
|
-
const [error, setError] =
|
|
971
|
+
const [code, setCode] = useState10(props.initialCode ?? "");
|
|
972
|
+
const [error, setError] = useState10(false);
|
|
770
973
|
const rotate = async () => {
|
|
771
974
|
if (!props.claimId) return;
|
|
772
975
|
setError(false);
|
|
@@ -779,19 +982,24 @@ function GiftClaimCard(props) {
|
|
|
779
982
|
if (response.ok && body.code) setCode(body.code);
|
|
780
983
|
else setError(true);
|
|
781
984
|
};
|
|
782
|
-
return /* @__PURE__ */
|
|
783
|
-
/* @__PURE__ */
|
|
784
|
-
/* @__PURE__ */
|
|
785
|
-
code ? /* @__PURE__ */
|
|
786
|
-
/* @__PURE__ */
|
|
787
|
-
/* @__PURE__ */
|
|
985
|
+
return /* @__PURE__ */ jsxs12("div", { className: "join-done card", children: [
|
|
986
|
+
/* @__PURE__ */ jsx12("div", { className: "card-label", children: props.copy.label }),
|
|
987
|
+
/* @__PURE__ */ jsx12("p", { className: "meeting-note", children: props.copy.body }),
|
|
988
|
+
code ? /* @__PURE__ */ jsxs12(Fragment6, { children: [
|
|
989
|
+
/* @__PURE__ */ jsx12("output", { className: "gift-code", children: code }),
|
|
990
|
+
/* @__PURE__ */ jsx12("p", { children: props.copy.save })
|
|
788
991
|
] }) : null,
|
|
789
|
-
!code && props.claimId ? /* @__PURE__ */
|
|
790
|
-
error ? /* @__PURE__ */
|
|
992
|
+
!code && props.claimId ? /* @__PURE__ */ jsx12("button", { type: "button", className: "btn secondary", onClick: () => void rotate(), children: props.copy.rotate }) : null,
|
|
993
|
+
error ? /* @__PURE__ */ jsx12("p", { role: "alert", children: props.copy.rotateFailed }) : null
|
|
791
994
|
] });
|
|
792
995
|
}
|
|
793
996
|
|
|
794
997
|
// src/ui/join-application-response.ts
|
|
998
|
+
function applicationSubmitError(data, fallback) {
|
|
999
|
+
if (typeof data?.error === "string" && data.error.trim()) return data.error;
|
|
1000
|
+
if (data?.error && typeof data.error === "object" && typeof data.error.message === "string" && data.error.message.trim()) return data.error.message;
|
|
1001
|
+
return fallback;
|
|
1002
|
+
}
|
|
795
1003
|
function joinStateFromApplicationResponse(data, fallbackNeedsPayment, submittedGiftPurchase) {
|
|
796
1004
|
if (!data.id) return null;
|
|
797
1005
|
if (data.state === "accepted") return { step: "accepted", applicationId: data.id };
|
|
@@ -807,8 +1015,8 @@ function joinStateFromApplicationResponse(data, fallbackNeedsPayment, submittedG
|
|
|
807
1015
|
|
|
808
1016
|
// src/ui/gift-code-redeemer.tsx
|
|
809
1017
|
import { InlineActionField } from "@odla-ai/ui/components";
|
|
810
|
-
import { useState as
|
|
811
|
-
import { Fragment as
|
|
1018
|
+
import { useState as useState11 } from "preact/hooks";
|
|
1019
|
+
import { Fragment as Fragment7, jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
|
|
812
1020
|
var GIFT_CODE_REDEEMER_CSS = `
|
|
813
1021
|
.gift-code-redeemer{container-type:inline-size;display:grid;gap:var(--ui-space-1,.35rem);margin:0}
|
|
814
1022
|
.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}
|
|
@@ -823,10 +1031,10 @@ var GIFT_CODE_REDEEMER_CSS = `
|
|
|
823
1031
|
@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
1032
|
`;
|
|
825
1033
|
function GiftCodeRedeemer({ api, applicationId, copy, id, onRedeemed }) {
|
|
826
|
-
const [code, setCode] =
|
|
827
|
-
const [loading, setLoading] =
|
|
828
|
-
const [message, setMessage] =
|
|
829
|
-
const [messageTone, setMessageTone] =
|
|
1034
|
+
const [code, setCode] = useState11("");
|
|
1035
|
+
const [loading, setLoading] = useState11(false);
|
|
1036
|
+
const [message, setMessage] = useState11("");
|
|
1037
|
+
const [messageTone, setMessageTone] = useState11("neutral");
|
|
830
1038
|
const normalizedCode = code.trim();
|
|
831
1039
|
const redeem = async () => {
|
|
832
1040
|
if (!normalizedCode || loading) return;
|
|
@@ -853,9 +1061,9 @@ function GiftCodeRedeemer({ api, applicationId, copy, id, onRedeemed }) {
|
|
|
853
1061
|
setLoading(false);
|
|
854
1062
|
}
|
|
855
1063
|
};
|
|
856
|
-
return /* @__PURE__ */
|
|
857
|
-
/* @__PURE__ */
|
|
858
|
-
/* @__PURE__ */
|
|
1064
|
+
return /* @__PURE__ */ jsxs13(Fragment7, { children: [
|
|
1065
|
+
/* @__PURE__ */ jsx13("style", { children: GIFT_CODE_REDEEMER_CSS }),
|
|
1066
|
+
/* @__PURE__ */ jsx13(
|
|
859
1067
|
InlineActionField,
|
|
860
1068
|
{
|
|
861
1069
|
id,
|
|
@@ -894,12 +1102,15 @@ function GiftCodeRedeemer({ api, applicationId, copy, id, onRedeemed }) {
|
|
|
894
1102
|
async function loadJoinResume(applicationId, fetcher = fetch) {
|
|
895
1103
|
const res = await fetcher(`/api/join/resume?application=${encodeURIComponent(applicationId)}`);
|
|
896
1104
|
const data = await res.json();
|
|
1105
|
+
if (!data || data.applicationId !== applicationId) throw new Error("The application could not be resumed.");
|
|
1106
|
+
if (res.status === 409 && data.code === "application_closed") return { step: "closed", applicationId };
|
|
897
1107
|
if (!res.ok) throw new Error(data.error ?? "The application could not be resumed.");
|
|
898
1108
|
if (data.state === "done" && data.booked) return { step: "done", applicationId: data.applicationId, booked: data.booked };
|
|
899
1109
|
if (data.state === "paymentPending") return { step: "paymentPending", applicationId: data.applicationId };
|
|
900
1110
|
if (data.state === "booking") return { step: "booking", applicationId: data.applicationId };
|
|
901
1111
|
if (data.state === "accepted") return { step: "accepted", applicationId: data.applicationId };
|
|
902
1112
|
if (data.state === "gift") return { step: "gift", applicationId: data.applicationId, ...data.claimId ? { claimId: data.claimId } : {} };
|
|
1113
|
+
if (data.state !== "payment") throw new Error("The application continuation is not recognized.");
|
|
903
1114
|
return {
|
|
904
1115
|
step: "payment",
|
|
905
1116
|
applicationId: data.applicationId,
|
|
@@ -908,12 +1119,12 @@ async function loadJoinResume(applicationId, fetcher = fetch) {
|
|
|
908
1119
|
}
|
|
909
1120
|
|
|
910
1121
|
// src/ui/join-gift-claim.tsx
|
|
911
|
-
import { jsx as
|
|
1122
|
+
import { jsx as jsx14, jsxs as jsxs14 } from "preact/jsx-runtime";
|
|
912
1123
|
function JoinGiftClaim(props) {
|
|
913
|
-
return /* @__PURE__ */
|
|
914
|
-
/* @__PURE__ */
|
|
915
|
-
/* @__PURE__ */
|
|
916
|
-
/* @__PURE__ */
|
|
1124
|
+
return /* @__PURE__ */ jsxs14("section", { className: "join-gift-claim card", children: [
|
|
1125
|
+
/* @__PURE__ */ jsx14("div", { className: "card-label", children: props.copy.claimTitle }),
|
|
1126
|
+
/* @__PURE__ */ jsx14("p", { children: props.copy.claimBody }),
|
|
1127
|
+
/* @__PURE__ */ jsx14(
|
|
917
1128
|
GiftCodeRedeemer,
|
|
918
1129
|
{
|
|
919
1130
|
api: props.api,
|
|
@@ -936,11 +1147,48 @@ function JoinGiftClaim(props) {
|
|
|
936
1147
|
] });
|
|
937
1148
|
}
|
|
938
1149
|
|
|
1150
|
+
// src/ui/join-named-seat.tsx
|
|
1151
|
+
import { useState as useState12 } from "preact/hooks";
|
|
1152
|
+
import { jsx as jsx15, jsxs as jsxs15 } from "preact/jsx-runtime";
|
|
1153
|
+
function JoinNamedSeat(props) {
|
|
1154
|
+
const [seatId, setSeatId] = useState12(props.seatId ?? "");
|
|
1155
|
+
const [accepted, setAccepted] = useState12(false), [busy, setBusy] = useState12(false), [error, setError] = useState12("");
|
|
1156
|
+
return /* @__PURE__ */ jsxs15("section", { className: "join-named-seat card", children: [
|
|
1157
|
+
/* @__PURE__ */ jsx15("h2", { children: "Accept your named seat" }),
|
|
1158
|
+
/* @__PURE__ */ jsx15("p", { children: "Sign in with the email address on your invitation. Your membership is paid for; complete your own application and any required interview." }),
|
|
1159
|
+
/* @__PURE__ */ jsxs15("label", { children: [
|
|
1160
|
+
"Invitation reference",
|
|
1161
|
+
/* @__PURE__ */ jsx15("input", { value: seatId, disabled: busy, onInput: (event) => setSeatId(event.currentTarget.value) })
|
|
1162
|
+
] }),
|
|
1163
|
+
/* @__PURE__ */ jsxs15("label", { children: [
|
|
1164
|
+
/* @__PURE__ */ jsx15("input", { type: "checkbox", checked: accepted, disabled: busy, onChange: (event) => setAccepted(event.currentTarget.checked) }),
|
|
1165
|
+
"I accept this seat for myself. It cannot be reassigned and lasts only while the purchaser\u2019s membership and my seat are current."
|
|
1166
|
+
] }),
|
|
1167
|
+
error ? /* @__PURE__ */ jsx15("p", { role: "alert", children: error }) : null,
|
|
1168
|
+
/* @__PURE__ */ jsx15("button", { type: "button", className: "btn btn-primary", disabled: busy || !accepted || !seatId.trim(), onClick: async () => {
|
|
1169
|
+
setBusy(true);
|
|
1170
|
+
setError("");
|
|
1171
|
+
try {
|
|
1172
|
+
const result = await props.api("/api/named-seat/accept", {
|
|
1173
|
+
method: "POST",
|
|
1174
|
+
body: JSON.stringify({ applicationId: props.applicationId, seatId: seatId.trim(), acceptTerms: true })
|
|
1175
|
+
});
|
|
1176
|
+
if (!result.ok || result.applicationId !== props.applicationId || !["booking", "accepted", "paymentPending"].includes(result.state)) throw new Error("acceptance pending");
|
|
1177
|
+
props.onState({ step: result.state, applicationId: result.applicationId });
|
|
1178
|
+
} catch {
|
|
1179
|
+
setError("We could not confirm acceptance. Check that you are signed in with the invited email, then retry this invitation. Do not start another paid checkout.");
|
|
1180
|
+
} finally {
|
|
1181
|
+
setBusy(false);
|
|
1182
|
+
}
|
|
1183
|
+
}, children: busy ? "Confirming your seat\u2026" : "Accept seat \u2014 no payment" })
|
|
1184
|
+
] });
|
|
1185
|
+
}
|
|
1186
|
+
|
|
939
1187
|
// src/ui/join-tiers.tsx
|
|
940
|
-
import { useState as
|
|
941
|
-
import { jsx as
|
|
1188
|
+
import { useState as useState13 } from "preact/hooks";
|
|
1189
|
+
import { jsx as jsx16, jsxs as jsxs16 } from "preact/jsx-runtime";
|
|
942
1190
|
function useTierSelection(tiers, initialTierId) {
|
|
943
|
-
const [selectedTierId, setSelectedTierId] =
|
|
1191
|
+
const [selectedTierId, setSelectedTierId] = useState13(() => {
|
|
944
1192
|
const preset = tiers.find((tier) => tier.id === initialTierId);
|
|
945
1193
|
if (preset) return preset.id;
|
|
946
1194
|
return tiers.length === 1 ? tiers[0].id : null;
|
|
@@ -955,10 +1203,10 @@ function useTierSelection(tiers, initialTierId) {
|
|
|
955
1203
|
};
|
|
956
1204
|
}
|
|
957
1205
|
function TierPlaceholder(context) {
|
|
958
|
-
return /* @__PURE__ */
|
|
959
|
-
/* @__PURE__ */
|
|
960
|
-
context.tiers.map((tier) => /* @__PURE__ */
|
|
961
|
-
/* @__PURE__ */
|
|
1206
|
+
return /* @__PURE__ */ jsxs16("fieldset", { "data-chapter-placeholder": "tiers", children: [
|
|
1207
|
+
/* @__PURE__ */ jsx16("legend", { children: "Membership (placeholder \u2014 pass renderTiers to style this)" }),
|
|
1208
|
+
context.tiers.map((tier) => /* @__PURE__ */ jsxs16("label", { children: [
|
|
1209
|
+
/* @__PURE__ */ jsx16(
|
|
962
1210
|
"input",
|
|
963
1211
|
{
|
|
964
1212
|
type: "radio",
|
|
@@ -976,8 +1224,33 @@ function tierNeedsPayment(selected, paymentsReady) {
|
|
|
976
1224
|
return selected ? !selected.free && paymentsReady : paymentsReady;
|
|
977
1225
|
}
|
|
978
1226
|
|
|
1227
|
+
// src/ui/join-pending.ts
|
|
1228
|
+
import { useEffect as useEffect7 } from "preact/hooks";
|
|
1229
|
+
function useJoinPending(state, loadResume, setState) {
|
|
1230
|
+
useEffect7(() => {
|
|
1231
|
+
if (state.step !== "paymentPending") return;
|
|
1232
|
+
let live = true;
|
|
1233
|
+
let timer;
|
|
1234
|
+
const poll = async () => {
|
|
1235
|
+
try {
|
|
1236
|
+
const resumed = loadResume ? await loadResume() : await loadJoinResume(state.applicationId);
|
|
1237
|
+
if (!live || !resumed) return;
|
|
1238
|
+
setState(resumed);
|
|
1239
|
+
if (resumed.step === "paymentPending") timer = setTimeout(() => void poll(), 1500);
|
|
1240
|
+
} catch {
|
|
1241
|
+
if (live) timer = setTimeout(() => void poll(), 2500);
|
|
1242
|
+
}
|
|
1243
|
+
};
|
|
1244
|
+
timer = setTimeout(() => void poll(), 1e3);
|
|
1245
|
+
return () => {
|
|
1246
|
+
live = false;
|
|
1247
|
+
if (timer) clearTimeout(timer);
|
|
1248
|
+
};
|
|
1249
|
+
}, [state, loadResume]);
|
|
1250
|
+
}
|
|
1251
|
+
|
|
979
1252
|
// src/ui/join.tsx
|
|
980
|
-
import { Fragment as
|
|
1253
|
+
import { Fragment as Fragment8, jsx as jsx17, jsxs as jsxs17 } from "preact/jsx-runtime";
|
|
981
1254
|
function JoinIsland(props) {
|
|
982
1255
|
const inheritedCopy = useChapterCopy();
|
|
983
1256
|
const {
|
|
@@ -994,10 +1267,10 @@ function JoinIsland(props) {
|
|
|
994
1267
|
const tiers = config.tiers ?? [];
|
|
995
1268
|
const tierSelection = useTierSelection(tiers, props.initialTierId);
|
|
996
1269
|
const { selectedTierId, selected: selectedTier } = tierSelection;
|
|
997
|
-
const [state, setState] =
|
|
998
|
-
const [error, setError] =
|
|
999
|
-
const [submitting, setSubmitting] =
|
|
1000
|
-
const [giftOfferId, setGiftOfferId] =
|
|
1270
|
+
const [state, setState] = useState14(props.initialState ?? { step: "form" });
|
|
1271
|
+
const [error, setError] = useState14(null);
|
|
1272
|
+
const [submitting, setSubmitting] = useState14(false);
|
|
1273
|
+
const [giftOfferId, setGiftOfferId] = useState14(props.initialGiftOfferId ?? null);
|
|
1001
1274
|
const simulatedPayment = props.simulation ? props.simulation.payment ?? {
|
|
1002
1275
|
lineItems: {
|
|
1003
1276
|
standardCents: selectedTier?.priceCents ?? 0,
|
|
@@ -1007,7 +1280,7 @@ function JoinIsland(props) {
|
|
|
1007
1280
|
} : void 0;
|
|
1008
1281
|
const simulatedBooking = props.simulation ? props.simulation.booking ?? { slots: [], timezone: "UTC" } : void 0;
|
|
1009
1282
|
const submissionId = useRef3(null);
|
|
1010
|
-
|
|
1283
|
+
useEffect8(() => {
|
|
1011
1284
|
if (props.simulation) return;
|
|
1012
1285
|
const resolver = props.loadResume ?? (() => {
|
|
1013
1286
|
if (typeof window === "undefined") return Promise.resolve(null);
|
|
@@ -1024,26 +1297,7 @@ function JoinIsland(props) {
|
|
|
1024
1297
|
live = false;
|
|
1025
1298
|
};
|
|
1026
1299
|
}, [props.loadResume, props.simulation]);
|
|
1027
|
-
|
|
1028
|
-
if (state.step !== "paymentPending") return;
|
|
1029
|
-
let live = true;
|
|
1030
|
-
let timer;
|
|
1031
|
-
const poll = async () => {
|
|
1032
|
-
try {
|
|
1033
|
-
const resumed = props.loadResume ? await props.loadResume() : await loadJoinResume(state.applicationId);
|
|
1034
|
-
if (!live || !resumed) return;
|
|
1035
|
-
setState(resumed);
|
|
1036
|
-
if (resumed.step === "paymentPending") timer = setTimeout(() => void poll(), 1500);
|
|
1037
|
-
} catch {
|
|
1038
|
-
if (live) timer = setTimeout(() => void poll(), 2500);
|
|
1039
|
-
}
|
|
1040
|
-
};
|
|
1041
|
-
timer = setTimeout(() => void poll(), 1e3);
|
|
1042
|
-
return () => {
|
|
1043
|
-
live = false;
|
|
1044
|
-
if (timer) clearTimeout(timer);
|
|
1045
|
-
};
|
|
1046
|
-
}, [state, props.loadResume]);
|
|
1300
|
+
useJoinPending(state, props.loadResume, setState);
|
|
1047
1301
|
const submit = async (e) => {
|
|
1048
1302
|
e.preventDefault();
|
|
1049
1303
|
if (submitting || props.submitDisabled === true) return;
|
|
@@ -1069,7 +1323,7 @@ function JoinIsland(props) {
|
|
|
1069
1323
|
body: JSON.stringify(fields)
|
|
1070
1324
|
});
|
|
1071
1325
|
const data = await res.json();
|
|
1072
|
-
if (!res.ok || !data
|
|
1326
|
+
if (!res.ok || !data?.id) throw new Error(applicationSubmitError(data, copy.form.submitFailed));
|
|
1073
1327
|
setState(joinStateFromApplicationResponse(
|
|
1074
1328
|
data,
|
|
1075
1329
|
tierNeedsPayment(selectedTier, config.paymentsReady),
|
|
@@ -1085,36 +1339,46 @@ function JoinIsland(props) {
|
|
|
1085
1339
|
state,
|
|
1086
1340
|
..."applicationId" in state ? { applicationId: state.applicationId } : {}
|
|
1087
1341
|
});
|
|
1342
|
+
if (state.step === "closed") {
|
|
1343
|
+
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1344
|
+
header,
|
|
1345
|
+
/* @__PURE__ */ jsxs17("section", { className: "card", "aria-label": "Application closed", children: [
|
|
1346
|
+
/* @__PURE__ */ jsx17("h2", { children: "This application is closed" }),
|
|
1347
|
+
/* @__PURE__ */ jsx17("p", { children: "This link cannot resume payment or booking. Sign in to view your application status, or contact the chapter if you need help." }),
|
|
1348
|
+
/* @__PURE__ */ jsx17("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
|
|
1349
|
+
] })
|
|
1350
|
+
] });
|
|
1351
|
+
}
|
|
1088
1352
|
if (state.step === "done") {
|
|
1089
|
-
const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */
|
|
1090
|
-
/* @__PURE__ */
|
|
1091
|
-
/* @__PURE__ */
|
|
1092
|
-
/* @__PURE__ */
|
|
1093
|
-
/* @__PURE__ */
|
|
1353
|
+
const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsxs17("div", { className: "join-done card", children: [
|
|
1354
|
+
/* @__PURE__ */ jsx17("div", { className: "card-label", children: copy.done.label }),
|
|
1355
|
+
/* @__PURE__ */ jsx17("p", { className: "meeting-date", children: fullLabel(state.booked.startAt, state.booked.timezone) }),
|
|
1356
|
+
/* @__PURE__ */ jsx17("p", { className: "meeting-note", children: copy.done.calendarInvite }),
|
|
1357
|
+
/* @__PURE__ */ jsx17("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
|
|
1094
1358
|
] });
|
|
1095
|
-
return /* @__PURE__ */
|
|
1359
|
+
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1096
1360
|
header,
|
|
1097
1361
|
body
|
|
1098
1362
|
] });
|
|
1099
1363
|
}
|
|
1100
1364
|
if (state.step === "accepted") {
|
|
1101
|
-
const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */
|
|
1102
|
-
return /* @__PURE__ */
|
|
1365
|
+
const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsx17(JoinAccepted, { copy, membersHref });
|
|
1366
|
+
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1103
1367
|
header,
|
|
1104
1368
|
body
|
|
1105
1369
|
] });
|
|
1106
1370
|
}
|
|
1107
1371
|
if (state.step === "gift") {
|
|
1108
|
-
const body = renderGift?.(state) ?? /* @__PURE__ */
|
|
1109
|
-
return /* @__PURE__ */
|
|
1372
|
+
const body = renderGift?.(state) ?? /* @__PURE__ */ jsx17(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
|
|
1373
|
+
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1110
1374
|
header,
|
|
1111
1375
|
body
|
|
1112
1376
|
] });
|
|
1113
1377
|
}
|
|
1114
1378
|
if (state.step === "booking") {
|
|
1115
|
-
return /* @__PURE__ */
|
|
1379
|
+
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1116
1380
|
header,
|
|
1117
|
-
/* @__PURE__ */
|
|
1381
|
+
/* @__PURE__ */ jsx17(
|
|
1118
1382
|
JoinBooking,
|
|
1119
1383
|
{
|
|
1120
1384
|
applicationId: state.applicationId,
|
|
@@ -1128,9 +1392,24 @@ function JoinIsland(props) {
|
|
|
1128
1392
|
] });
|
|
1129
1393
|
}
|
|
1130
1394
|
if (state.step === "payment") {
|
|
1131
|
-
|
|
1395
|
+
if (props.namedSeatClaimApi && props.initialNamedSeatId && !props.simulation && !state.giftPurchase) {
|
|
1396
|
+
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1397
|
+
header,
|
|
1398
|
+
/* @__PURE__ */ jsx17(
|
|
1399
|
+
JoinNamedSeat,
|
|
1400
|
+
{
|
|
1401
|
+
api: props.namedSeatClaimApi,
|
|
1402
|
+
applicationId: state.applicationId,
|
|
1403
|
+
seatId: props.initialNamedSeatId,
|
|
1404
|
+
onState: setState
|
|
1405
|
+
}
|
|
1406
|
+
)
|
|
1407
|
+
] });
|
|
1408
|
+
}
|
|
1409
|
+
const Payment = state.giftPurchase || props.simulation ? PaymentStep : MembershipPaymentStep;
|
|
1410
|
+
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1132
1411
|
header,
|
|
1133
|
-
props.giftClaimApi && !state.giftPurchase ? /* @__PURE__ */
|
|
1412
|
+
props.giftClaimApi && !state.giftPurchase ? /* @__PURE__ */ jsx17(
|
|
1134
1413
|
JoinGiftClaim,
|
|
1135
1414
|
{
|
|
1136
1415
|
api: props.giftClaimApi,
|
|
@@ -1141,8 +1420,8 @@ function JoinIsland(props) {
|
|
|
1141
1420
|
onError: () => setError(copy.form.unexpectedFailure)
|
|
1142
1421
|
}
|
|
1143
1422
|
) : null,
|
|
1144
|
-
/* @__PURE__ */
|
|
1145
|
-
|
|
1423
|
+
/* @__PURE__ */ jsx17(
|
|
1424
|
+
Payment,
|
|
1146
1425
|
{
|
|
1147
1426
|
applicationId: state.applicationId,
|
|
1148
1427
|
refundPolicyText: config.refundPolicyText ?? "",
|
|
@@ -1169,25 +1448,39 @@ function JoinIsland(props) {
|
|
|
1169
1448
|
] });
|
|
1170
1449
|
}
|
|
1171
1450
|
if (state.step === "paymentPending") {
|
|
1172
|
-
|
|
1451
|
+
if (props.namedSeatClaimApi && props.initialNamedSeatId && !props.simulation) {
|
|
1452
|
+
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1453
|
+
header,
|
|
1454
|
+
/* @__PURE__ */ jsx17(
|
|
1455
|
+
JoinNamedSeat,
|
|
1456
|
+
{
|
|
1457
|
+
api: props.namedSeatClaimApi,
|
|
1458
|
+
applicationId: state.applicationId,
|
|
1459
|
+
seatId: props.initialNamedSeatId,
|
|
1460
|
+
onState: setState
|
|
1461
|
+
}
|
|
1462
|
+
)
|
|
1463
|
+
] });
|
|
1464
|
+
}
|
|
1465
|
+
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1173
1466
|
header,
|
|
1174
|
-
/* @__PURE__ */
|
|
1467
|
+
/* @__PURE__ */ jsx17("p", { className: "pay-status", role: "status", children: copy.payment.pending })
|
|
1175
1468
|
] });
|
|
1176
1469
|
}
|
|
1177
1470
|
const submitDisabled = submitting || props.submitDisabled === true;
|
|
1178
1471
|
const tierChooser = tiers.length > 1 ? props.renderTiers?.(tierSelection) ?? TierPlaceholder(tierSelection) : null;
|
|
1179
|
-
return /* @__PURE__ */
|
|
1472
|
+
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1180
1473
|
header,
|
|
1181
|
-
/* @__PURE__ */
|
|
1182
|
-
(config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */
|
|
1183
|
-
/* @__PURE__ */
|
|
1184
|
-
/* @__PURE__ */
|
|
1185
|
-
/* @__PURE__ */
|
|
1474
|
+
/* @__PURE__ */ jsxs17("form", { className: "join-form", onSubmit: (e) => void submit(e), children: [
|
|
1475
|
+
(config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs17("fieldset", { children: [
|
|
1476
|
+
/* @__PURE__ */ jsx17("legend", { children: copy.gift.optionsLabel }),
|
|
1477
|
+
/* @__PURE__ */ jsx17("button", { type: "button", className: "btn secondary", "aria-pressed": !giftOfferId, onClick: () => setGiftOfferId(null), children: copy.gift.chooseSelf }),
|
|
1478
|
+
/* @__PURE__ */ jsx17(GiftOfferCards, { offers: config.giftOffers ?? [], mode: "select", selectedOfferId: giftOfferId, onSelect: setGiftOfferId })
|
|
1186
1479
|
] }) : null,
|
|
1187
1480
|
tierChooser,
|
|
1188
1481
|
children,
|
|
1189
|
-
error ? /* @__PURE__ */
|
|
1190
|
-
renderSubmit?.({ submitting, disabled: submitDisabled }) ?? /* @__PURE__ */
|
|
1482
|
+
error ? /* @__PURE__ */ jsx17("p", { className: "join-error", children: error }) : null,
|
|
1483
|
+
renderSubmit?.({ submitting, disabled: submitDisabled }) ?? /* @__PURE__ */ jsx17("button", { className: "submit-btn", type: "submit", disabled: submitDisabled, children: submitting ? copy.form.submitting : copy.form.submit })
|
|
1191
1484
|
] })
|
|
1192
1485
|
] });
|
|
1193
1486
|
}
|
|
@@ -1364,7 +1657,7 @@ function membershipPageDocument(input, options = {}) {
|
|
|
1364
1657
|
}
|
|
1365
1658
|
|
|
1366
1659
|
// src/ui/membership-cards.tsx
|
|
1367
|
-
import { jsx as
|
|
1660
|
+
import { jsx as jsx18, jsxs as jsxs18 } from "preact/jsx-runtime";
|
|
1368
1661
|
var MEMBERSHIP_CARD_TOKEN_DEFAULTS = Object.freeze({
|
|
1369
1662
|
"--ui-membership-grid-gap": "1.4rem",
|
|
1370
1663
|
"--ui-membership-card-padding": "2rem 1.7rem 1.8rem",
|
|
@@ -1433,67 +1726,67 @@ function membershipApplicationHref(applicationPath, tierId) {
|
|
|
1433
1726
|
}
|
|
1434
1727
|
function TierAction(props) {
|
|
1435
1728
|
if (props.mode === "select") {
|
|
1436
|
-
return /* @__PURE__ */
|
|
1729
|
+
return /* @__PURE__ */ jsxs18("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
|
|
1437
1730
|
props.label,
|
|
1438
|
-
/* @__PURE__ */
|
|
1731
|
+
/* @__PURE__ */ jsx18("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1439
1732
|
] });
|
|
1440
1733
|
}
|
|
1441
1734
|
if (props.mode === "preview") {
|
|
1442
|
-
return /* @__PURE__ */
|
|
1735
|
+
return /* @__PURE__ */ jsxs18("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
|
|
1443
1736
|
props.label,
|
|
1444
|
-
/* @__PURE__ */
|
|
1737
|
+
/* @__PURE__ */ jsx18("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1445
1738
|
] });
|
|
1446
1739
|
}
|
|
1447
|
-
return /* @__PURE__ */
|
|
1740
|
+
return /* @__PURE__ */ jsxs18("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
|
|
1448
1741
|
props.label,
|
|
1449
|
-
/* @__PURE__ */
|
|
1742
|
+
/* @__PURE__ */ jsx18("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1450
1743
|
] });
|
|
1451
1744
|
}
|
|
1452
1745
|
function TierCard(props) {
|
|
1453
1746
|
const { tier, presentation } = props;
|
|
1454
1747
|
const summary = presentation.summaryMarkdown ?? tier.blurb;
|
|
1455
1748
|
const action = presentation.ctaLabel ?? (tier.free ? "Join for free" : `Choose ${tier.name}`);
|
|
1456
|
-
return /* @__PURE__ */
|
|
1457
|
-
presentation.badge ? /* @__PURE__ */
|
|
1458
|
-
/* @__PURE__ */
|
|
1459
|
-
/* @__PURE__ */
|
|
1460
|
-
presentation.capacity ? /* @__PURE__ */
|
|
1461
|
-
/* @__PURE__ */
|
|
1462
|
-
/* @__PURE__ */
|
|
1749
|
+
return /* @__PURE__ */ jsxs18("article", { className: "chapter-membership-card", "data-tier-id": tier.id, "data-variant": presentation.variant ?? "standard", children: [
|
|
1750
|
+
presentation.badge ? /* @__PURE__ */ jsx18("div", { className: "chapter-membership-badge", children: presentation.badge }) : null,
|
|
1751
|
+
/* @__PURE__ */ jsx18("h3", { className: "chapter-membership-name", children: tier.name }),
|
|
1752
|
+
/* @__PURE__ */ jsxs18("div", { className: "chapter-membership-offer", "data-with-capacity": presentation.capacity ? "true" : void 0, children: [
|
|
1753
|
+
presentation.capacity ? /* @__PURE__ */ jsxs18("div", { className: "chapter-membership-capacity", "aria-label": `${presentation.capacity.total} ${presentation.capacity.label ?? "available"}`, children: [
|
|
1754
|
+
/* @__PURE__ */ jsx18("strong", { children: presentation.capacity.total.toLocaleString("en-US") }),
|
|
1755
|
+
/* @__PURE__ */ jsx18("small", { children: presentation.capacity.label ?? "available" })
|
|
1463
1756
|
] }) : null,
|
|
1464
|
-
/* @__PURE__ */
|
|
1465
|
-
presentation.priceEyebrow ? /* @__PURE__ */
|
|
1466
|
-
/* @__PURE__ */
|
|
1467
|
-
presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */
|
|
1468
|
-
/* @__PURE__ */
|
|
1469
|
-
!tier.free && presentation.billingLabel ? /* @__PURE__ */
|
|
1757
|
+
/* @__PURE__ */ jsxs18("div", { className: "chapter-membership-price-stack", children: [
|
|
1758
|
+
presentation.priceEyebrow ? /* @__PURE__ */ jsx18("p", { className: "chapter-membership-price-eyebrow", children: presentation.priceEyebrow }) : null,
|
|
1759
|
+
/* @__PURE__ */ jsxs18("div", { className: "chapter-membership-price-row", children: [
|
|
1760
|
+
presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */ jsx18("span", { className: "chapter-membership-compare", children: fmtMoney(presentation.compareAtPriceCents) }) : null,
|
|
1761
|
+
/* @__PURE__ */ jsx18("span", { className: "chapter-membership-price", children: tier.free ? "Free" : fmtMoney(tier.priceCents) }),
|
|
1762
|
+
!tier.free && presentation.billingLabel ? /* @__PURE__ */ jsx18("span", { className: "chapter-membership-billing", children: presentation.billingLabel }) : null
|
|
1470
1763
|
] })
|
|
1471
1764
|
] })
|
|
1472
1765
|
] }),
|
|
1473
|
-
presentation.priceNoteMarkdown ? /* @__PURE__ */
|
|
1474
|
-
summary ? /* @__PURE__ */
|
|
1475
|
-
presentation.benefits?.length ? /* @__PURE__ */
|
|
1476
|
-
/* @__PURE__ */
|
|
1477
|
-
/* @__PURE__ */
|
|
1766
|
+
presentation.priceNoteMarkdown ? /* @__PURE__ */ jsx18(Markdown2, { className: "chapter-membership-price-note", source: presentation.priceNoteMarkdown }) : null,
|
|
1767
|
+
summary ? /* @__PURE__ */ jsx18(Markdown2, { className: "chapter-membership-summary", source: summary }) : null,
|
|
1768
|
+
presentation.benefits?.length ? /* @__PURE__ */ jsx18("ul", { className: "chapter-membership-benefits", children: presentation.benefits.map((benefit, index) => /* @__PURE__ */ jsxs18("li", { children: [
|
|
1769
|
+
/* @__PURE__ */ jsx18("span", { className: "chapter-membership-check", "aria-hidden": "true", children: "\u2713" }),
|
|
1770
|
+
/* @__PURE__ */ jsx18(Markdown2, { className: "chapter-membership-benefit", source: benefit })
|
|
1478
1771
|
] }, `${tier.id}-benefit-${index}`)) }) : null,
|
|
1479
|
-
presentation.callout ? /* @__PURE__ */
|
|
1480
|
-
presentation.callout.label ? /* @__PURE__ */
|
|
1481
|
-
/* @__PURE__ */
|
|
1772
|
+
presentation.callout ? /* @__PURE__ */ jsxs18("aside", { className: "chapter-membership-callout", children: [
|
|
1773
|
+
presentation.callout.label ? /* @__PURE__ */ jsx18("p", { className: "chapter-membership-callout-label", children: presentation.callout.label }) : null,
|
|
1774
|
+
/* @__PURE__ */ jsx18(Markdown2, { source: presentation.callout.bodyMarkdown })
|
|
1482
1775
|
] }) : null,
|
|
1483
|
-
/* @__PURE__ */
|
|
1776
|
+
/* @__PURE__ */ jsx18(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
|
|
1484
1777
|
] });
|
|
1485
1778
|
}
|
|
1486
1779
|
function MembershipCards(props) {
|
|
1487
1780
|
const document2 = membershipPageDocument(props.document, { tiers: props.tiers });
|
|
1488
1781
|
const byId = new Map(props.tiers.map((tier) => [tier.id, tier]));
|
|
1489
1782
|
const mode = props.mode ?? "link";
|
|
1490
|
-
return /* @__PURE__ */
|
|
1491
|
-
/* @__PURE__ */
|
|
1492
|
-
/* @__PURE__ */
|
|
1783
|
+
return /* @__PURE__ */ jsxs18("section", { className: ["chapter-membership", props.className].filter(Boolean).join(" "), "data-chapter-membership": MEMBERSHIP_PAGE_RENDERER, "aria-label": props.ariaLabel ?? "Membership options", children: [
|
|
1784
|
+
/* @__PURE__ */ jsx18("style", { children: MEMBERSHIP_CARDS_CSS }),
|
|
1785
|
+
/* @__PURE__ */ jsx18("div", { className: "chapter-membership-grid", style: { "--chapter-membership-columns": String(Math.min(document2.tiers.length, 3)) }, children: document2.tiers.map((presentation) => {
|
|
1493
1786
|
const tier = byId.get(presentation.tierId);
|
|
1494
|
-
return /* @__PURE__ */
|
|
1787
|
+
return /* @__PURE__ */ jsx18(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
|
|
1495
1788
|
}) }),
|
|
1496
|
-
document2.footnoteMarkdown ? /* @__PURE__ */
|
|
1789
|
+
document2.footnoteMarkdown ? /* @__PURE__ */ jsx18(Markdown2, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
|
|
1497
1790
|
] });
|
|
1498
1791
|
}
|
|
1499
1792
|
|
|
@@ -1524,4 +1817,4 @@ export {
|
|
|
1524
1817
|
membershipApplicationHref,
|
|
1525
1818
|
MembershipCards
|
|
1526
1819
|
};
|
|
1527
|
-
//# sourceMappingURL=chunk-
|
|
1820
|
+
//# sourceMappingURL=chunk-KZ2AXEZW.js.map
|