@odla-ai/chapter 0.36.0 → 0.38.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.
@@ -105,7 +105,7 @@ function SlotPicker(props) {
105
105
  }
106
106
 
107
107
  // src/ui/members.tsx
108
- import { useEffect as useEffect2, useState as useState5 } from "preact/hooks";
108
+ import { useEffect as useEffect3, useState as useState6 } from "preact/hooks";
109
109
 
110
110
  // src/ui/reschedule.tsx
111
111
  import { useState as useState2 } from "preact/hooks";
@@ -452,13 +452,98 @@ function MemberGifts(props) {
452
452
  ] });
453
453
  }
454
454
 
455
- // src/ui/members.tsx
455
+ // src/ui/member-content.tsx
456
+ import { useEffect as useEffect2, useMemo as useMemo2, useState as useState5 } from "preact/hooks";
457
+ import { Markdown } from "@odla-ai/ui/components";
456
458
  import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
459
+ var pageLabel = (page) => `${page.title}${page.access === "locked" ? " \xB7 Locked" : ""}`;
460
+ function MemberContentArea(props) {
461
+ const {
462
+ api,
463
+ path = "/api/member-content",
464
+ upsellHref,
465
+ onUpsell,
466
+ loadingContent = /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: "Loading member pages\u2026" }),
467
+ emptyContent = /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: "No member pages have been published yet." })
468
+ } = props;
469
+ const [data, setData] = useState5(props.initialData ?? null);
470
+ const [error, setError] = useState5(null);
471
+ const [selectedId, setSelectedId] = useState5(
472
+ props.initialPageId ?? props.initialData?.pages[0]?.id ?? ""
473
+ );
474
+ useEffect2(() => {
475
+ if (props.initialData) return;
476
+ let live = true;
477
+ setError(null);
478
+ void api(path).then((value) => {
479
+ if (!live) return;
480
+ setData(value);
481
+ setSelectedId((current) => value.pages.some((page) => page.id === current) ? current : value.pages[0]?.id ?? "");
482
+ }).catch((reason) => live && setError(reason instanceof Error ? reason.message : String(reason)));
483
+ return () => {
484
+ live = false;
485
+ };
486
+ }, [api, path, props.initialData]);
487
+ const sections = useMemo2(() => {
488
+ const result = /* @__PURE__ */ new Map();
489
+ for (const page of data?.pages ?? []) {
490
+ const list = result.get(page.navigation.section) ?? [];
491
+ list.push(page);
492
+ result.set(page.navigation.section, list);
493
+ }
494
+ return [...result.entries()];
495
+ }, [data]);
496
+ if (error) return /* @__PURE__ */ jsxs6("p", { className: "meeting-note", role: "alert", children: [
497
+ "Member pages could not be loaded: ",
498
+ error
499
+ ] });
500
+ if (!data) return /* @__PURE__ */ jsx6(Fragment2, { children: loadingContent });
501
+ if (data.pages.length === 0) return /* @__PURE__ */ jsx6(Fragment2, { children: emptyContent });
502
+ const selected = data.pages.find((page) => page.id === selectedId) ?? data.pages[0];
503
+ const href = selected.upsell && upsellHref ? upsellHref(selected.upsell.tierId, selected) : void 0;
504
+ return /* @__PURE__ */ jsxs6("div", { className: "chapter-member-content", "data-member-content": true, children: [
505
+ /* @__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: [
506
+ /* @__PURE__ */ jsx6("h2", { children: section }),
507
+ /* @__PURE__ */ jsx6("ul", { children: pages.map((page) => /* @__PURE__ */ jsx6("li", { "data-parent-page": page.navigation.parentId ?? void 0, children: /* @__PURE__ */ jsx6(
508
+ "button",
509
+ {
510
+ type: "button",
511
+ "aria-current": page.id === selected.id ? "page" : void 0,
512
+ onClick: () => setSelectedId(page.id),
513
+ children: pageLabel(page)
514
+ }
515
+ ) }, page.id)) })
516
+ ] }, section)) }),
517
+ /* @__PURE__ */ jsxs6("article", { className: "chapter-member-content-page", "data-access": selected.access, children: [
518
+ /* @__PURE__ */ jsxs6("header", { children: [
519
+ /* @__PURE__ */ jsxs6("div", { className: "card-label", children: [
520
+ selected.source.type === "parent" ? "Parent" : "Chapter",
521
+ " \xB7 ",
522
+ selected.access
523
+ ] }),
524
+ /* @__PURE__ */ jsx6("h1", { children: selected.title }),
525
+ selected.summary ? /* @__PURE__ */ jsx6("p", { children: selected.summary }) : null
526
+ ] }),
527
+ selected.access === "allowed" && selected.bodyMarkdown ? /* @__PURE__ */ jsx6(Markdown, { source: selected.bodyMarkdown }) : /* @__PURE__ */ jsxs6("div", { className: "chapter-member-content-locked", children: [
528
+ selected.teaserMarkdown ? /* @__PURE__ */ jsx6(Markdown, { source: selected.teaserMarkdown }) : /* @__PURE__ */ jsx6("p", { children: "This page is not included in your current membership." }),
529
+ selected.upsell ? /* @__PURE__ */ jsxs6("aside", { className: "chapter-member-content-upsell", "aria-label": selected.upsell.label ?? "Membership option", children: [
530
+ /* @__PURE__ */ jsx6("h2", { children: selected.upsell.label ?? selected.upsell.tierName }),
531
+ /* @__PURE__ */ jsx6("p", { children: fmtMoney(selected.upsell.priceCents) }),
532
+ selected.upsell.bodyMarkdown ? /* @__PURE__ */ jsx6(Markdown, { source: selected.upsell.bodyMarkdown }) : null,
533
+ 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
534
+ ] }) : null
535
+ ] })
536
+ ] })
537
+ ] });
538
+ }
539
+
540
+ // src/ui/members.tsx
541
+ import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
457
542
  function card(copy, kicker, body) {
458
- return /* @__PURE__ */ jsxs6("div", { className: "card", children: [
459
- /* @__PURE__ */ jsx6("div", { className: "card-label", children: copy.provisional.cardLabel }),
460
- /* @__PURE__ */ jsxs6("div", { className: "meeting-block", children: [
461
- /* @__PURE__ */ jsx6("div", { className: "meeting-kicker", children: kicker }),
543
+ return /* @__PURE__ */ jsxs7("div", { className: "card", children: [
544
+ /* @__PURE__ */ jsx7("div", { className: "card-label", children: copy.provisional.cardLabel }),
545
+ /* @__PURE__ */ jsxs7("div", { className: "meeting-block", children: [
546
+ /* @__PURE__ */ jsx7("div", { className: "meeting-kicker", children: kicker }),
462
547
  body
463
548
  ] })
464
549
  ] });
@@ -469,9 +554,9 @@ function ProvisionalCard(props) {
469
554
  return card(
470
555
  copy,
471
556
  copy.provisional.applicationNeeded,
472
- /* @__PURE__ */ jsxs6(Fragment2, { children: [
473
- /* @__PURE__ */ jsx6("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
474
- /* @__PURE__ */ jsx6("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
557
+ /* @__PURE__ */ jsxs7(Fragment3, { children: [
558
+ /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
559
+ /* @__PURE__ */ jsx7("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
475
560
  ] })
476
561
  );
477
562
  }
@@ -479,19 +564,19 @@ function ProvisionalCard(props) {
479
564
  return card(
480
565
  copy,
481
566
  copy.provisional.refunded,
482
- /* @__PURE__ */ jsx6("div", { className: "meeting-note", children: copy.provisional.refundedBody })
567
+ /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.refundedBody })
483
568
  );
484
569
  }
485
- const membership = application.paid ? /* @__PURE__ */ jsx6("div", { className: "meeting-note", children: application.renewalAt ? formatChapterCopy(copy.provisional.renews, { date: fmtDate(application.renewalAt) }) : copy.provisional.active }) : null;
570
+ 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;
486
571
  if (application.meetingAt) {
487
572
  return card(
488
573
  copy,
489
574
  copy.provisional.introductionCall,
490
- /* @__PURE__ */ jsxs6(Fragment2, { children: [
491
- /* @__PURE__ */ jsx6("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
492
- /* @__PURE__ */ jsx6("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
493
- application.meetUrl ? /* @__PURE__ */ jsx6("div", { className: "meeting-note", children: /* @__PURE__ */ jsx6("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
494
- /* @__PURE__ */ jsx6(
575
+ /* @__PURE__ */ jsxs7(Fragment3, { children: [
576
+ /* @__PURE__ */ jsx7("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
577
+ /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
578
+ application.meetUrl ? /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: /* @__PURE__ */ jsx7("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
579
+ /* @__PURE__ */ jsx7(
495
580
  Rescheduler,
496
581
  {
497
582
  api,
@@ -508,9 +593,9 @@ function ProvisionalCard(props) {
508
593
  return card(
509
594
  copy,
510
595
  copy.provisional.bookCall,
511
- /* @__PURE__ */ jsxs6(Fragment2, { children: [
512
- /* @__PURE__ */ jsx6("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
513
- /* @__PURE__ */ jsx6(
596
+ /* @__PURE__ */ jsxs7(Fragment3, { children: [
597
+ /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
598
+ /* @__PURE__ */ jsx7(
514
599
  Rescheduler,
515
600
  {
516
601
  api,
@@ -533,11 +618,12 @@ function MembersArea(props) {
533
618
  adminHref = "/admin/",
534
619
  applyHref = "/join.html",
535
620
  memberContent,
621
+ memberPages,
536
622
  renderProvisional
537
623
  } = props;
538
624
  const copy = props.copy ?? inheritedCopy.members;
539
- const [me, setMe] = useState5(null);
540
- const [error, setError] = useState5(false);
625
+ const [me, setMe] = useState6(null);
626
+ const [error, setError] = useState6(false);
541
627
  const reload = async () => {
542
628
  try {
543
629
  setMe(await api("/api/me"));
@@ -545,25 +631,25 @@ function MembersArea(props) {
545
631
  setError(true);
546
632
  }
547
633
  };
548
- useEffect2(() => {
634
+ useEffect3(() => {
549
635
  void reload();
550
636
  }, []);
551
- if (error) return /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: copy.loadFailed });
552
- if (!me) return /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: inheritedCopy.common.loading });
637
+ if (error) return /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: copy.loadFailed });
638
+ if (!me) return /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: inheritedCopy.common.loading });
553
639
  const role = me.role || "provisional";
554
- return /* @__PURE__ */ jsxs6(Fragment2, { children: [
555
- /* @__PURE__ */ jsxs6("div", { className: "card", children: [
556
- /* @__PURE__ */ jsxs6("div", { className: "member-row", children: [
557
- /* @__PURE__ */ jsx6("span", { className: "member-email", children: me.email }),
558
- /* @__PURE__ */ jsx6("span", { className: "role-badge " + role, children: role })
640
+ return /* @__PURE__ */ jsxs7(Fragment3, { children: [
641
+ /* @__PURE__ */ jsxs7("div", { className: "card", children: [
642
+ /* @__PURE__ */ jsxs7("div", { className: "member-row", children: [
643
+ /* @__PURE__ */ jsx7("span", { className: "member-email", children: me.email }),
644
+ /* @__PURE__ */ jsx7("span", { className: "role-badge " + role, children: role })
559
645
  ] }),
560
- /* @__PURE__ */ jsxs6("div", { className: "account-actions", children: [
561
- /* @__PURE__ */ jsx6("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
562
- role === "admin" ? /* @__PURE__ */ jsx6("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
646
+ /* @__PURE__ */ jsxs7("div", { className: "account-actions", children: [
647
+ /* @__PURE__ */ jsx7("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
648
+ role === "admin" ? /* @__PURE__ */ jsx7("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
563
649
  ] })
564
650
  ] }),
565
651
  role === "provisional" ? (() => {
566
- const defaultContent = /* @__PURE__ */ jsx6(
652
+ const defaultContent = /* @__PURE__ */ jsx7(
567
653
  ProvisionalCard,
568
654
  {
569
655
  api,
@@ -580,23 +666,29 @@ function MembersArea(props) {
580
666
  reload,
581
667
  defaultContent
582
668
  }) ?? defaultContent;
583
- })() : memberContent ?? /* @__PURE__ */ jsx6("div", { className: "card", children: /* @__PURE__ */ jsx6("div", { className: "card-label", children: copy.full.welcome }) }),
584
- /* @__PURE__ */ jsx6(MemberGifts, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment })
669
+ })() : memberContent ?? (memberPages ? /* @__PURE__ */ jsx7(
670
+ MemberContentArea,
671
+ {
672
+ api,
673
+ ...memberPages === true ? {} : memberPages
674
+ }
675
+ ) : /* @__PURE__ */ jsx7("div", { className: "card", children: /* @__PURE__ */ jsx7("div", { className: "card-label", children: copy.full.welcome }) })),
676
+ /* @__PURE__ */ jsx7(MemberGifts, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment })
585
677
  ] });
586
678
  }
587
679
 
588
680
  // src/ui/join.tsx
589
- import { useEffect as useEffect4, useRef as useRef3, useState as useState9 } from "preact/hooks";
681
+ import { useEffect as useEffect5, useRef as useRef3, useState as useState10 } from "preact/hooks";
590
682
 
591
683
  // src/ui/join-booking.tsx
592
- import { useEffect as useEffect3, useState as useState6 } from "preact/hooks";
593
- import { jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
684
+ import { useEffect as useEffect4, useState as useState7 } from "preact/hooks";
685
+ import { jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
594
686
  function JoinBooking(props) {
595
687
  const { applicationId, copy, onBooked, simulation } = props;
596
- const [state, setState] = useState6(null);
597
- const [msg, setMsg] = useState6(null);
598
- const [busy, setBusy] = useState6(false);
599
- const [selected, setSelected] = useState6(null);
688
+ const [state, setState] = useState7(null);
689
+ const [msg, setMsg] = useState7(null);
690
+ const [busy, setBusy] = useState7(false);
691
+ const [selected, setSelected] = useState7(null);
600
692
  const load = async () => {
601
693
  setMsg(null);
602
694
  try {
@@ -621,7 +713,7 @@ function JoinBooking(props) {
621
713
  setMsg(copy.loadFailed);
622
714
  }
623
715
  };
624
- useEffect3(() => {
716
+ useEffect4(() => {
625
717
  void load();
626
718
  }, [simulation]);
627
719
  const book = async () => {
@@ -653,9 +745,9 @@ function JoinBooking(props) {
653
745
  setBusy(false);
654
746
  }
655
747
  };
656
- if (!state) return /* @__PURE__ */ jsx7("p", { className: "slots-status", children: msg ?? copy.loading });
657
- return /* @__PURE__ */ jsxs7("div", { className: "join-book", children: [
658
- /* @__PURE__ */ jsx7(
748
+ if (!state) return /* @__PURE__ */ jsx8("p", { className: "slots-status", children: msg ?? copy.loading });
749
+ return /* @__PURE__ */ jsxs8("div", { className: "join-book", children: [
750
+ /* @__PURE__ */ jsx8(
659
751
  SlotPicker,
660
752
  {
661
753
  slots: state.slots,
@@ -665,29 +757,29 @@ function JoinBooking(props) {
665
757
  onDayChange: () => setSelected(null)
666
758
  }
667
759
  ),
668
- /* @__PURE__ */ jsxs7("div", { className: "slot-confirm", hidden: !selected, children: [
669
- /* @__PURE__ */ jsx7("button", { className: "submit-btn", disabled: busy, onClick: () => void book(), children: busy ? copy.booking : copy.book }),
670
- msg ? /* @__PURE__ */ jsx7("p", { className: "step2-note", children: msg }) : null
760
+ /* @__PURE__ */ jsxs8("div", { className: "slot-confirm", hidden: !selected, children: [
761
+ /* @__PURE__ */ jsx8("button", { className: "submit-btn", disabled: busy, onClick: () => void book(), children: busy ? copy.booking : copy.book }),
762
+ msg ? /* @__PURE__ */ jsx8("p", { className: "step2-note", children: msg }) : null
671
763
  ] })
672
764
  ] });
673
765
  }
674
766
 
675
767
  // src/ui/join-accepted.tsx
676
- import { jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
768
+ import { jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
677
769
  function JoinAccepted(props) {
678
- return /* @__PURE__ */ jsxs8("div", { className: "join-done card", children: [
679
- /* @__PURE__ */ jsx8("div", { className: "card-label", children: props.copy.accepted.label }),
680
- /* @__PURE__ */ jsx8("p", { className: "meeting-note", children: props.copy.accepted.body }),
681
- /* @__PURE__ */ jsx8("a", { className: "apply-link", href: props.membersHref, children: props.copy.done.memberArea })
770
+ return /* @__PURE__ */ jsxs9("div", { className: "join-done card", children: [
771
+ /* @__PURE__ */ jsx9("div", { className: "card-label", children: props.copy.accepted.label }),
772
+ /* @__PURE__ */ jsx9("p", { className: "meeting-note", children: props.copy.accepted.body }),
773
+ /* @__PURE__ */ jsx9("a", { className: "apply-link", href: props.membersHref, children: props.copy.done.memberArea })
682
774
  ] });
683
775
  }
684
776
 
685
777
  // src/ui/gift-claim-card.tsx
686
- import { useState as useState7 } from "preact/hooks";
687
- import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
778
+ import { useState as useState8 } from "preact/hooks";
779
+ import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
688
780
  function GiftClaimCard(props) {
689
- const [code, setCode] = useState7(props.initialCode ?? "");
690
- const [error, setError] = useState7(false);
781
+ const [code, setCode] = useState8(props.initialCode ?? "");
782
+ const [error, setError] = useState8(false);
691
783
  const rotate = async () => {
692
784
  if (!props.claimId) return;
693
785
  setError(false);
@@ -700,23 +792,23 @@ function GiftClaimCard(props) {
700
792
  if (response.ok && body.code) setCode(body.code);
701
793
  else setError(true);
702
794
  };
703
- return /* @__PURE__ */ jsxs9("div", { className: "join-done card", children: [
704
- /* @__PURE__ */ jsx9("div", { className: "card-label", children: props.copy.label }),
705
- /* @__PURE__ */ jsx9("p", { className: "meeting-note", children: props.copy.body }),
706
- code ? /* @__PURE__ */ jsxs9(Fragment3, { children: [
707
- /* @__PURE__ */ jsx9("output", { className: "gift-code", children: code }),
708
- /* @__PURE__ */ jsx9("p", { children: props.copy.save })
795
+ return /* @__PURE__ */ jsxs10("div", { className: "join-done card", children: [
796
+ /* @__PURE__ */ jsx10("div", { className: "card-label", children: props.copy.label }),
797
+ /* @__PURE__ */ jsx10("p", { className: "meeting-note", children: props.copy.body }),
798
+ code ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
799
+ /* @__PURE__ */ jsx10("output", { className: "gift-code", children: code }),
800
+ /* @__PURE__ */ jsx10("p", { children: props.copy.save })
709
801
  ] }) : null,
710
- !code && props.claimId ? /* @__PURE__ */ jsx9("button", { type: "button", className: "btn secondary", onClick: () => void rotate(), children: props.copy.rotate }) : null,
711
- error ? /* @__PURE__ */ jsx9("p", { role: "alert", children: props.copy.rotateFailed }) : null
802
+ !code && props.claimId ? /* @__PURE__ */ jsx10("button", { type: "button", className: "btn secondary", onClick: () => void rotate(), children: props.copy.rotate }) : null,
803
+ error ? /* @__PURE__ */ jsx10("p", { role: "alert", children: props.copy.rotateFailed }) : null
712
804
  ] });
713
805
  }
714
806
 
715
807
  // src/ui/join-tiers.tsx
716
- import { useState as useState8 } from "preact/hooks";
717
- import { jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
808
+ import { useState as useState9 } from "preact/hooks";
809
+ import { jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
718
810
  function useTierSelection(tiers, initialTierId) {
719
- const [selectedTierId, setSelectedTierId] = useState8(() => {
811
+ const [selectedTierId, setSelectedTierId] = useState9(() => {
720
812
  const preset = tiers.find((tier) => tier.id === initialTierId);
721
813
  if (preset) return preset.id;
722
814
  return tiers.length === 1 ? tiers[0].id : null;
@@ -731,10 +823,10 @@ function useTierSelection(tiers, initialTierId) {
731
823
  };
732
824
  }
733
825
  function TierPlaceholder(context) {
734
- return /* @__PURE__ */ jsxs10("fieldset", { "data-chapter-placeholder": "tiers", children: [
735
- /* @__PURE__ */ jsx10("legend", { children: "Membership (placeholder \u2014 pass renderTiers to style this)" }),
736
- context.tiers.map((tier) => /* @__PURE__ */ jsxs10("label", { children: [
737
- /* @__PURE__ */ jsx10(
826
+ return /* @__PURE__ */ jsxs11("fieldset", { "data-chapter-placeholder": "tiers", children: [
827
+ /* @__PURE__ */ jsx11("legend", { children: "Membership (placeholder \u2014 pass renderTiers to style this)" }),
828
+ context.tiers.map((tier) => /* @__PURE__ */ jsxs11("label", { children: [
829
+ /* @__PURE__ */ jsx11(
738
830
  "input",
739
831
  {
740
832
  type: "radio",
@@ -766,7 +858,7 @@ async function loadJoinResume(applicationId, fetcher = fetch) {
766
858
  }
767
859
 
768
860
  // src/ui/join.tsx
769
- import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
861
+ import { Fragment as Fragment5, jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
770
862
  function JoinIsland(props) {
771
863
  const inheritedCopy = useChapterCopy();
772
864
  const {
@@ -783,10 +875,10 @@ function JoinIsland(props) {
783
875
  const tiers = config.tiers ?? [];
784
876
  const tierSelection = useTierSelection(tiers, props.initialTierId);
785
877
  const { selectedTierId, selected: selectedTier } = tierSelection;
786
- const [state, setState] = useState9(props.initialState ?? { step: "form" });
787
- const [error, setError] = useState9(null);
788
- const [submitting, setSubmitting] = useState9(false);
789
- const [giftOfferId, setGiftOfferId] = useState9(props.initialGiftOfferId ?? null);
878
+ const [state, setState] = useState10(props.initialState ?? { step: "form" });
879
+ const [error, setError] = useState10(null);
880
+ const [submitting, setSubmitting] = useState10(false);
881
+ const [giftOfferId, setGiftOfferId] = useState10(props.initialGiftOfferId ?? null);
790
882
  const simulatedPayment = props.simulation ? props.simulation.payment ?? {
791
883
  lineItems: {
792
884
  standardCents: selectedTier?.priceCents ?? 0,
@@ -796,7 +888,7 @@ function JoinIsland(props) {
796
888
  } : void 0;
797
889
  const simulatedBooking = props.simulation ? props.simulation.booking ?? { slots: [], timezone: "UTC" } : void 0;
798
890
  const submissionId = useRef3(null);
799
- useEffect4(() => {
891
+ useEffect5(() => {
800
892
  if (props.simulation) return;
801
893
  const resolver = props.loadResume ?? (() => {
802
894
  if (typeof window === "undefined") return Promise.resolve(null);
@@ -813,7 +905,7 @@ function JoinIsland(props) {
813
905
  live = false;
814
906
  };
815
907
  }, [props.loadResume, props.simulation]);
816
- useEffect4(() => {
908
+ useEffect5(() => {
817
909
  if (state.step !== "paymentPending") return;
818
910
  let live = true;
819
911
  let timer;
@@ -886,35 +978,35 @@ function JoinIsland(props) {
886
978
  ..."applicationId" in state ? { applicationId: state.applicationId } : {}
887
979
  });
888
980
  if (state.step === "done") {
889
- const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsxs11("div", { className: "join-done card", children: [
890
- /* @__PURE__ */ jsx11("div", { className: "card-label", children: copy.done.label }),
891
- /* @__PURE__ */ jsx11("p", { className: "meeting-date", children: fullLabel(state.booked.startAt, state.booked.timezone) }),
892
- /* @__PURE__ */ jsx11("p", { className: "meeting-note", children: copy.done.calendarInvite }),
893
- /* @__PURE__ */ jsx11("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
981
+ const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsxs12("div", { className: "join-done card", children: [
982
+ /* @__PURE__ */ jsx12("div", { className: "card-label", children: copy.done.label }),
983
+ /* @__PURE__ */ jsx12("p", { className: "meeting-date", children: fullLabel(state.booked.startAt, state.booked.timezone) }),
984
+ /* @__PURE__ */ jsx12("p", { className: "meeting-note", children: copy.done.calendarInvite }),
985
+ /* @__PURE__ */ jsx12("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
894
986
  ] });
895
- return /* @__PURE__ */ jsxs11(Fragment4, { children: [
987
+ return /* @__PURE__ */ jsxs12(Fragment5, { children: [
896
988
  header,
897
989
  body
898
990
  ] });
899
991
  }
900
992
  if (state.step === "accepted") {
901
- const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsx11(JoinAccepted, { copy, membersHref });
902
- return /* @__PURE__ */ jsxs11(Fragment4, { children: [
993
+ const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsx12(JoinAccepted, { copy, membersHref });
994
+ return /* @__PURE__ */ jsxs12(Fragment5, { children: [
903
995
  header,
904
996
  body
905
997
  ] });
906
998
  }
907
999
  if (state.step === "gift") {
908
- const body = renderGift?.(state) ?? /* @__PURE__ */ jsx11(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
909
- return /* @__PURE__ */ jsxs11(Fragment4, { children: [
1000
+ const body = renderGift?.(state) ?? /* @__PURE__ */ jsx12(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
1001
+ return /* @__PURE__ */ jsxs12(Fragment5, { children: [
910
1002
  header,
911
1003
  body
912
1004
  ] });
913
1005
  }
914
1006
  if (state.step === "booking") {
915
- return /* @__PURE__ */ jsxs11(Fragment4, { children: [
1007
+ return /* @__PURE__ */ jsxs12(Fragment5, { children: [
916
1008
  header,
917
- /* @__PURE__ */ jsx11(
1009
+ /* @__PURE__ */ jsx12(
918
1010
  JoinBooking,
919
1011
  {
920
1012
  applicationId: state.applicationId,
@@ -928,9 +1020,9 @@ function JoinIsland(props) {
928
1020
  ] });
929
1021
  }
930
1022
  if (state.step === "payment") {
931
- return /* @__PURE__ */ jsxs11(Fragment4, { children: [
1023
+ return /* @__PURE__ */ jsxs12(Fragment5, { children: [
932
1024
  header,
933
- /* @__PURE__ */ jsx11(
1025
+ /* @__PURE__ */ jsx12(
934
1026
  PaymentStep,
935
1027
  {
936
1028
  applicationId: state.applicationId,
@@ -957,31 +1049,31 @@ function JoinIsland(props) {
957
1049
  ] });
958
1050
  }
959
1051
  if (state.step === "paymentPending") {
960
- return /* @__PURE__ */ jsxs11(Fragment4, { children: [
1052
+ return /* @__PURE__ */ jsxs12(Fragment5, { children: [
961
1053
  header,
962
- /* @__PURE__ */ jsx11("p", { className: "pay-status", role: "status", children: copy.payment.pending })
1054
+ /* @__PURE__ */ jsx12("p", { className: "pay-status", role: "status", children: copy.payment.pending })
963
1055
  ] });
964
1056
  }
965
1057
  const submitDisabled = submitting || props.submitDisabled === true;
966
1058
  const tierChooser = tiers.length > 1 ? props.renderTiers?.(tierSelection) ?? TierPlaceholder(tierSelection) : null;
967
- return /* @__PURE__ */ jsxs11(Fragment4, { children: [
1059
+ return /* @__PURE__ */ jsxs12(Fragment5, { children: [
968
1060
  header,
969
- /* @__PURE__ */ jsxs11("form", { className: "join-form", onSubmit: (e) => void submit(e), children: [
970
- (config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs11("fieldset", { children: [
971
- /* @__PURE__ */ jsx11("legend", { children: copy.gift.optionsLabel }),
972
- /* @__PURE__ */ jsx11("button", { type: "button", className: "btn secondary", "aria-pressed": !giftOfferId, onClick: () => setGiftOfferId(null), children: copy.gift.chooseSelf }),
973
- /* @__PURE__ */ jsx11(GiftOfferCards, { offers: config.giftOffers ?? [], mode: "select", selectedOfferId: giftOfferId, onSelect: setGiftOfferId })
1061
+ /* @__PURE__ */ jsxs12("form", { className: "join-form", onSubmit: (e) => void submit(e), children: [
1062
+ (config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs12("fieldset", { children: [
1063
+ /* @__PURE__ */ jsx12("legend", { children: copy.gift.optionsLabel }),
1064
+ /* @__PURE__ */ jsx12("button", { type: "button", className: "btn secondary", "aria-pressed": !giftOfferId, onClick: () => setGiftOfferId(null), children: copy.gift.chooseSelf }),
1065
+ /* @__PURE__ */ jsx12(GiftOfferCards, { offers: config.giftOffers ?? [], mode: "select", selectedOfferId: giftOfferId, onSelect: setGiftOfferId })
974
1066
  ] }) : null,
975
1067
  tierChooser,
976
1068
  children,
977
- error ? /* @__PURE__ */ jsx11("p", { className: "join-error", children: error }) : null,
978
- renderSubmit?.({ submitting, disabled: submitDisabled }) ?? /* @__PURE__ */ jsx11("button", { className: "submit-btn", type: "submit", disabled: submitDisabled, children: submitting ? copy.form.submitting : copy.form.submit })
1069
+ error ? /* @__PURE__ */ jsx12("p", { className: "join-error", children: error }) : null,
1070
+ renderSubmit?.({ submitting, disabled: submitDisabled }) ?? /* @__PURE__ */ jsx12("button", { className: "submit-btn", type: "submit", disabled: submitDisabled, children: submitting ? copy.form.submitting : copy.form.submit })
979
1071
  ] })
980
1072
  ] });
981
1073
  }
982
1074
 
983
1075
  // src/ui/membership-cards.tsx
984
- import { Markdown } from "@odla-ai/ui/components";
1076
+ import { Markdown as Markdown2 } from "@odla-ai/ui/components";
985
1077
 
986
1078
  // src/membership-page.ts
987
1079
  var MEMBERSHIP_PAGE_RENDERER = "membership-cards-v1";
@@ -1152,7 +1244,7 @@ function membershipPageDocument(input, options = {}) {
1152
1244
  }
1153
1245
 
1154
1246
  // src/ui/membership-cards.tsx
1155
- import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
1247
+ import { jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
1156
1248
  var MEMBERSHIP_CARD_TOKEN_DEFAULTS = Object.freeze({
1157
1249
  "--ui-membership-grid-gap": "1.4rem",
1158
1250
  "--ui-membership-card-padding": "2rem 1.7rem 1.8rem",
@@ -1221,67 +1313,67 @@ function membershipApplicationHref(applicationPath, tierId) {
1221
1313
  }
1222
1314
  function TierAction(props) {
1223
1315
  if (props.mode === "select") {
1224
- return /* @__PURE__ */ jsxs12("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
1316
+ return /* @__PURE__ */ jsxs13("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
1225
1317
  props.label,
1226
- /* @__PURE__ */ jsx12("span", { "aria-hidden": "true", children: "\u2192" })
1318
+ /* @__PURE__ */ jsx13("span", { "aria-hidden": "true", children: "\u2192" })
1227
1319
  ] });
1228
1320
  }
1229
1321
  if (props.mode === "preview") {
1230
- return /* @__PURE__ */ jsxs12("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
1322
+ return /* @__PURE__ */ jsxs13("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
1231
1323
  props.label,
1232
- /* @__PURE__ */ jsx12("span", { "aria-hidden": "true", children: "\u2192" })
1324
+ /* @__PURE__ */ jsx13("span", { "aria-hidden": "true", children: "\u2192" })
1233
1325
  ] });
1234
1326
  }
1235
- return /* @__PURE__ */ jsxs12("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
1327
+ return /* @__PURE__ */ jsxs13("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
1236
1328
  props.label,
1237
- /* @__PURE__ */ jsx12("span", { "aria-hidden": "true", children: "\u2192" })
1329
+ /* @__PURE__ */ jsx13("span", { "aria-hidden": "true", children: "\u2192" })
1238
1330
  ] });
1239
1331
  }
1240
1332
  function TierCard(props) {
1241
1333
  const { tier, presentation } = props;
1242
1334
  const summary = presentation.summaryMarkdown ?? tier.blurb;
1243
1335
  const action = presentation.ctaLabel ?? (tier.free ? "Join for free" : `Choose ${tier.name}`);
1244
- return /* @__PURE__ */ jsxs12("article", { className: "chapter-membership-card", "data-tier-id": tier.id, "data-variant": presentation.variant ?? "standard", children: [
1245
- presentation.badge ? /* @__PURE__ */ jsx12("div", { className: "chapter-membership-badge", children: presentation.badge }) : null,
1246
- /* @__PURE__ */ jsx12("h3", { className: "chapter-membership-name", children: tier.name }),
1247
- /* @__PURE__ */ jsxs12("div", { className: "chapter-membership-offer", "data-with-capacity": presentation.capacity ? "true" : void 0, children: [
1248
- presentation.capacity ? /* @__PURE__ */ jsxs12("div", { className: "chapter-membership-capacity", "aria-label": `${presentation.capacity.total} ${presentation.capacity.label ?? "available"}`, children: [
1249
- /* @__PURE__ */ jsx12("strong", { children: presentation.capacity.total.toLocaleString("en-US") }),
1250
- /* @__PURE__ */ jsx12("small", { children: presentation.capacity.label ?? "available" })
1336
+ return /* @__PURE__ */ jsxs13("article", { className: "chapter-membership-card", "data-tier-id": tier.id, "data-variant": presentation.variant ?? "standard", children: [
1337
+ presentation.badge ? /* @__PURE__ */ jsx13("div", { className: "chapter-membership-badge", children: presentation.badge }) : null,
1338
+ /* @__PURE__ */ jsx13("h3", { className: "chapter-membership-name", children: tier.name }),
1339
+ /* @__PURE__ */ jsxs13("div", { className: "chapter-membership-offer", "data-with-capacity": presentation.capacity ? "true" : void 0, children: [
1340
+ presentation.capacity ? /* @__PURE__ */ jsxs13("div", { className: "chapter-membership-capacity", "aria-label": `${presentation.capacity.total} ${presentation.capacity.label ?? "available"}`, children: [
1341
+ /* @__PURE__ */ jsx13("strong", { children: presentation.capacity.total.toLocaleString("en-US") }),
1342
+ /* @__PURE__ */ jsx13("small", { children: presentation.capacity.label ?? "available" })
1251
1343
  ] }) : null,
1252
- /* @__PURE__ */ jsxs12("div", { className: "chapter-membership-price-stack", children: [
1253
- presentation.priceEyebrow ? /* @__PURE__ */ jsx12("p", { className: "chapter-membership-price-eyebrow", children: presentation.priceEyebrow }) : null,
1254
- /* @__PURE__ */ jsxs12("div", { className: "chapter-membership-price-row", children: [
1255
- presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */ jsx12("span", { className: "chapter-membership-compare", children: fmtMoney(presentation.compareAtPriceCents) }) : null,
1256
- /* @__PURE__ */ jsx12("span", { className: "chapter-membership-price", children: tier.free ? "Free" : fmtMoney(tier.priceCents) }),
1257
- !tier.free && presentation.billingLabel ? /* @__PURE__ */ jsx12("span", { className: "chapter-membership-billing", children: presentation.billingLabel }) : null
1344
+ /* @__PURE__ */ jsxs13("div", { className: "chapter-membership-price-stack", children: [
1345
+ presentation.priceEyebrow ? /* @__PURE__ */ jsx13("p", { className: "chapter-membership-price-eyebrow", children: presentation.priceEyebrow }) : null,
1346
+ /* @__PURE__ */ jsxs13("div", { className: "chapter-membership-price-row", children: [
1347
+ presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */ jsx13("span", { className: "chapter-membership-compare", children: fmtMoney(presentation.compareAtPriceCents) }) : null,
1348
+ /* @__PURE__ */ jsx13("span", { className: "chapter-membership-price", children: tier.free ? "Free" : fmtMoney(tier.priceCents) }),
1349
+ !tier.free && presentation.billingLabel ? /* @__PURE__ */ jsx13("span", { className: "chapter-membership-billing", children: presentation.billingLabel }) : null
1258
1350
  ] })
1259
1351
  ] })
1260
1352
  ] }),
1261
- presentation.priceNoteMarkdown ? /* @__PURE__ */ jsx12(Markdown, { className: "chapter-membership-price-note", source: presentation.priceNoteMarkdown }) : null,
1262
- summary ? /* @__PURE__ */ jsx12(Markdown, { className: "chapter-membership-summary", source: summary }) : null,
1263
- presentation.benefits?.length ? /* @__PURE__ */ jsx12("ul", { className: "chapter-membership-benefits", children: presentation.benefits.map((benefit, index) => /* @__PURE__ */ jsxs12("li", { children: [
1264
- /* @__PURE__ */ jsx12("span", { className: "chapter-membership-check", "aria-hidden": "true", children: "\u2713" }),
1265
- /* @__PURE__ */ jsx12(Markdown, { className: "chapter-membership-benefit", source: benefit })
1353
+ presentation.priceNoteMarkdown ? /* @__PURE__ */ jsx13(Markdown2, { className: "chapter-membership-price-note", source: presentation.priceNoteMarkdown }) : null,
1354
+ summary ? /* @__PURE__ */ jsx13(Markdown2, { className: "chapter-membership-summary", source: summary }) : null,
1355
+ presentation.benefits?.length ? /* @__PURE__ */ jsx13("ul", { className: "chapter-membership-benefits", children: presentation.benefits.map((benefit, index) => /* @__PURE__ */ jsxs13("li", { children: [
1356
+ /* @__PURE__ */ jsx13("span", { className: "chapter-membership-check", "aria-hidden": "true", children: "\u2713" }),
1357
+ /* @__PURE__ */ jsx13(Markdown2, { className: "chapter-membership-benefit", source: benefit })
1266
1358
  ] }, `${tier.id}-benefit-${index}`)) }) : null,
1267
- presentation.callout ? /* @__PURE__ */ jsxs12("aside", { className: "chapter-membership-callout", children: [
1268
- presentation.callout.label ? /* @__PURE__ */ jsx12("p", { className: "chapter-membership-callout-label", children: presentation.callout.label }) : null,
1269
- /* @__PURE__ */ jsx12(Markdown, { source: presentation.callout.bodyMarkdown })
1359
+ presentation.callout ? /* @__PURE__ */ jsxs13("aside", { className: "chapter-membership-callout", children: [
1360
+ presentation.callout.label ? /* @__PURE__ */ jsx13("p", { className: "chapter-membership-callout-label", children: presentation.callout.label }) : null,
1361
+ /* @__PURE__ */ jsx13(Markdown2, { source: presentation.callout.bodyMarkdown })
1270
1362
  ] }) : null,
1271
- /* @__PURE__ */ jsx12(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
1363
+ /* @__PURE__ */ jsx13(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
1272
1364
  ] });
1273
1365
  }
1274
1366
  function MembershipCards(props) {
1275
1367
  const document2 = membershipPageDocument(props.document, { tiers: props.tiers });
1276
1368
  const byId = new Map(props.tiers.map((tier) => [tier.id, tier]));
1277
1369
  const mode = props.mode ?? "link";
1278
- return /* @__PURE__ */ jsxs12("section", { className: ["chapter-membership", props.className].filter(Boolean).join(" "), "data-chapter-membership": MEMBERSHIP_PAGE_RENDERER, "aria-label": props.ariaLabel ?? "Membership options", children: [
1279
- /* @__PURE__ */ jsx12("style", { children: MEMBERSHIP_CARDS_CSS }),
1280
- /* @__PURE__ */ jsx12("div", { className: "chapter-membership-grid", style: { "--chapter-membership-columns": String(Math.min(document2.tiers.length, 3)) }, children: document2.tiers.map((presentation) => {
1370
+ return /* @__PURE__ */ jsxs13("section", { className: ["chapter-membership", props.className].filter(Boolean).join(" "), "data-chapter-membership": MEMBERSHIP_PAGE_RENDERER, "aria-label": props.ariaLabel ?? "Membership options", children: [
1371
+ /* @__PURE__ */ jsx13("style", { children: MEMBERSHIP_CARDS_CSS }),
1372
+ /* @__PURE__ */ jsx13("div", { className: "chapter-membership-grid", style: { "--chapter-membership-columns": String(Math.min(document2.tiers.length, 3)) }, children: document2.tiers.map((presentation) => {
1281
1373
  const tier = byId.get(presentation.tierId);
1282
- return /* @__PURE__ */ jsx12(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
1374
+ return /* @__PURE__ */ jsx13(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
1283
1375
  }) }),
1284
- document2.footnoteMarkdown ? /* @__PURE__ */ jsx12(Markdown, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
1376
+ document2.footnoteMarkdown ? /* @__PURE__ */ jsx13(Markdown2, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
1285
1377
  ] });
1286
1378
  }
1287
1379
 
@@ -1299,6 +1391,7 @@ export {
1299
1391
  GiftOfferCards,
1300
1392
  PaymentStep,
1301
1393
  MemberGifts,
1394
+ MemberContentArea,
1302
1395
  MembersArea,
1303
1396
  useTierSelection,
1304
1397
  TierPlaceholder,
@@ -1309,4 +1402,4 @@ export {
1309
1402
  membershipApplicationHref,
1310
1403
  MembershipCards
1311
1404
  };
1312
- //# sourceMappingURL=chunk-I45VYBUV.js.map
1405
+ //# sourceMappingURL=chunk-BIYWPPH6.js.map