@odla-ai/chapter 0.47.9 → 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.
@@ -110,7 +110,7 @@ function SlotPicker(props) {
110
110
  }
111
111
 
112
112
  // src/ui/members.tsx
113
- import { useEffect as useEffect3, useState as useState6 } from "preact/hooks";
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 useEffect2, useMemo as useMemo2, useState as useState5 } from "preact/hooks";
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 Fragment2, jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
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__ */ 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." })
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] = useState5(props.initialData ?? null);
457
- const [error, setError] = useState5(null);
458
- const [selectedId, setSelectedId] = useState5(
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
- useEffect2(() => {
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__ */ jsxs6("p", { className: "meeting-note", role: "alert", children: [
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__ */ jsx6(Fragment2, { children: loadingContent });
488
- if (data.pages.length === 0) return /* @__PURE__ */ jsx6(Fragment2, { children: emptyContent });
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__ */ jsxs6("div", { className: "chapter-member-content", "data-member-content": true, children: [
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(
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__ */ jsxs6("article", { className: "chapter-member-content-page", "data-access": selected.access, children: [
505
- /* @__PURE__ */ jsxs6("header", { children: [
506
- /* @__PURE__ */ jsxs6("div", { className: "card-label", children: [
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__ */ jsx6("h1", { children: selected.title }),
512
- selected.summary ? /* @__PURE__ */ jsx6("p", { children: selected.summary }) : null
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__ */ 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." }),
516
- selected.upsell ? /* @__PURE__ */ jsxs6("aside", { className: "chapter-member-content-upsell", "aria-label": selected.upsell.label ?? "Membership option", children: [
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
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 Fragment3, jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
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__ */ jsxs7("div", { className: "card", children: [
531
- /* @__PURE__ */ jsx7("div", { className: "card-label", children: copy.provisional.cardLabel }),
532
- /* @__PURE__ */ jsxs7("div", { className: "meeting-block", children: [
533
- /* @__PURE__ */ jsx7("div", { className: "meeting-kicker", children: kicker }),
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__ */ jsxs7(Fragment3, { children: [
545
- /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
546
- /* @__PURE__ */ jsx7("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
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__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.refundedBody })
658
+ /* @__PURE__ */ jsx8("div", { className: "meeting-note", children: copy.provisional.refundedBody })
555
659
  );
556
660
  }
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;
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__ */ jsxs7(Fragment3, { children: [
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(
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__ */ jsxs7(Fragment3, { children: [
584
- /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
585
- /* @__PURE__ */ jsx7(
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] = useState6(null);
613
- const [error, setError] = useState6(false);
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
- useEffect3(() => {
725
+ useEffect4(() => {
622
726
  void reload();
623
727
  }, []);
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 });
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__ */ jsxs7(Fragment3, { children: [
628
- /* @__PURE__ */ jsxs7("div", { className: "card", children: [
629
- /* @__PURE__ */ jsxs7("div", { className: "member-row", children: [
630
- /* @__PURE__ */ jsx7("span", { className: "member-email", children: me.email }),
631
- /* @__PURE__ */ jsx7("span", { className: "role-badge " + role, children: role })
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__ */ jsxs7("div", { className: "account-actions", children: [
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
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
- role === "provisional" ? (() => {
639
- const defaultContent = /* @__PURE__ */ jsx7(
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__ */ jsx7(
760
+ })() : memberContent ?? (memberPages ? /* @__PURE__ */ jsx8(
657
761
  MemberContentArea,
658
762
  {
659
763
  api,
660
764
  ...memberPages === true ? {} : memberPages
661
765
  }
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 })
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 useEffect5, useRef as useRef3, useState as useState11 } from "preact/hooks";
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 useEffect4, useState as useState7 } from "preact/hooks";
672
- import { jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
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] = useState7(null);
676
- const [msg, setMsg] = useState7(null);
677
- const [busy, setBusy] = useState7(false);
678
- const [selected, setSelected] = useState7(null);
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
- useEffect4(() => {
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__ */ jsx8("p", { className: "slots-status", children: msg ?? copy.loading });
736
- return /* @__PURE__ */ jsxs8("div", { className: "join-book", children: [
737
- /* @__PURE__ */ jsx8(
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__ */ jsxs8("div", { className: "slot-confirm", hidden: !selected, children: [
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
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 jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
958
+ import { jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
756
959
  function JoinAccepted(props) {
757
- return /* @__PURE__ */ jsxs9("div", { className: "join-done card", children: [
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 })
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 useState8 } from "preact/hooks";
766
- import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
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] = useState8(props.initialCode ?? "");
769
- const [error, setError] = useState8(false);
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__ */ jsxs10("div", { className: "join-done card", children: [
783
- /* @__PURE__ */ jsx10("div", { className: "card-label", children: props.copy.label }),
784
- /* @__PURE__ */ jsx10("p", { className: "meeting-note", children: props.copy.body }),
785
- code ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
786
- /* @__PURE__ */ jsx10("output", { className: "gift-code", children: code }),
787
- /* @__PURE__ */ jsx10("p", { children: props.copy.save })
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__ */ 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
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 useState9 } from "preact/hooks";
811
- import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
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] = useState9("");
827
- const [loading, setLoading] = useState9(false);
828
- const [message, setMessage] = useState9("");
829
- const [messageTone, setMessageTone] = useState9("neutral");
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__ */ jsxs11(Fragment5, { children: [
857
- /* @__PURE__ */ jsx11("style", { children: GIFT_CODE_REDEEMER_CSS }),
858
- /* @__PURE__ */ jsx11(
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 jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
1122
+ import { jsx as jsx14, jsxs as jsxs14 } from "preact/jsx-runtime";
912
1123
  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(
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 useState10 } from "preact/hooks";
941
- import { jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
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] = useState10(() => {
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__ */ 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(
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 Fragment6, jsx as jsx14, jsxs as jsxs14 } from "preact/jsx-runtime";
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] = useState11(props.initialState ?? { step: "form" });
998
- const [error, setError] = useState11(null);
999
- const [submitting, setSubmitting] = useState11(false);
1000
- const [giftOfferId, setGiftOfferId] = useState11(props.initialGiftOfferId ?? null);
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
- useEffect5(() => {
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
- useEffect5(() => {
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.id) throw new Error(data.error ?? copy.form.submitFailed);
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__ */ 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 })
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__ */ jsxs14(Fragment6, { children: [
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__ */ jsx14(JoinAccepted, { copy, membersHref });
1102
- return /* @__PURE__ */ jsxs14(Fragment6, { children: [
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__ */ jsx14(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
1109
- return /* @__PURE__ */ jsxs14(Fragment6, { children: [
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__ */ jsxs14(Fragment6, { children: [
1379
+ return /* @__PURE__ */ jsxs17(Fragment8, { children: [
1116
1380
  header,
1117
- /* @__PURE__ */ jsx14(
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
- return /* @__PURE__ */ jsxs14(Fragment6, { children: [
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__ */ jsx14(
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__ */ jsx14(
1145
- PaymentStep,
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
- return /* @__PURE__ */ jsxs14(Fragment6, { children: [
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__ */ jsx14("p", { className: "pay-status", role: "status", children: copy.payment.pending })
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__ */ jsxs14(Fragment6, { children: [
1472
+ return /* @__PURE__ */ jsxs17(Fragment8, { children: [
1180
1473
  header,
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 })
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__ */ 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 })
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 jsx15, jsxs as jsxs15 } from "preact/jsx-runtime";
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__ */ jsxs15("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
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__ */ jsx15("span", { "aria-hidden": "true", children: "\u2192" })
1731
+ /* @__PURE__ */ jsx18("span", { "aria-hidden": "true", children: "\u2192" })
1439
1732
  ] });
1440
1733
  }
1441
1734
  if (props.mode === "preview") {
1442
- return /* @__PURE__ */ jsxs15("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
1735
+ return /* @__PURE__ */ jsxs18("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
1443
1736
  props.label,
1444
- /* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: "\u2192" })
1737
+ /* @__PURE__ */ jsx18("span", { "aria-hidden": "true", children: "\u2192" })
1445
1738
  ] });
1446
1739
  }
1447
- return /* @__PURE__ */ jsxs15("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
1740
+ return /* @__PURE__ */ jsxs18("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
1448
1741
  props.label,
1449
- /* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: "\u2192" })
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__ */ 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" })
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__ */ 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
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__ */ 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 })
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__ */ 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 })
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__ */ jsx15(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
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__ */ 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) => {
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__ */ jsx15(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
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__ */ jsx15(Markdown2, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
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-VWDEHUNI.js.map
1820
+ //# sourceMappingURL=chunk-KZ2AXEZW.js.map