@odla-ai/chapter 0.48.3 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-KZ2AXEZW.js → chunk-KHDO2QFA.js} +749 -543
- package/dist/chunk-KHDO2QFA.js.map +1 -0
- package/dist/{chunk-MQ4OPZCS.js → chunk-KXIGZWG5.js} +720 -615
- package/dist/chunk-KXIGZWG5.js.map +1 -0
- package/dist/{chunk-4HS2JPE2.js → chunk-N2JIKINY.js} +17 -1
- package/dist/chunk-N2JIKINY.js.map +1 -0
- package/dist/{copy-context-CMupQL9h.d.ts → copy-context-By4Nq7yB.d.ts} +6 -1
- package/dist/index.cjs +488 -118
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -3
- package/dist/index.d.ts +50 -3
- package/dist/index.js +484 -114
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +14 -3
- package/dist/ui/admin/index.js +6 -2
- package/dist/ui/index.d.ts +3 -3
- package/dist/ui/index.js +11 -3
- package/dist/ui/member/index.d.ts +36 -4
- package/dist/ui/member/index.js +6 -2
- package/dist/worker/index.cjs +7109 -6318
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +24 -1
- package/dist/worker/index.d.ts +24 -1
- package/dist/worker/index.js +7239 -6448
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-4HS2JPE2.js.map +0 -1
- package/dist/chunk-KZ2AXEZW.js.map +0 -1
- package/dist/chunk-MQ4OPZCS.js.map +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
+
DEFAULT_JOIN_COPY,
|
|
2
3
|
formatChapterCopy,
|
|
3
4
|
useChapterCopy
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-N2JIKINY.js";
|
|
5
6
|
import {
|
|
6
7
|
collectFormFields
|
|
7
8
|
} from "./chunk-IVXVECKR.js";
|
|
@@ -109,113 +110,15 @@ function SlotPicker(props) {
|
|
|
109
110
|
] });
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
// src/ui/
|
|
113
|
-
import { useEffect as
|
|
113
|
+
// src/ui/member-restart.tsx
|
|
114
|
+
import { useEffect as useEffect2, useState as useState4 } from "preact/hooks";
|
|
114
115
|
|
|
115
|
-
// src/ui/
|
|
116
|
-
import { useState as
|
|
117
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
118
|
-
function Rescheduler(props) {
|
|
119
|
-
const inheritedCopy = useChapterCopy();
|
|
120
|
-
const copy = props.copy ?? inheritedCopy.members.reschedule;
|
|
121
|
-
const { api, applicationId, timezone, onRescheduled, label = copy.changeTime } = props;
|
|
122
|
-
const [open, setOpen] = useState2(false);
|
|
123
|
-
const [slots, setSlots] = useState2(null);
|
|
124
|
-
const [tz, setTz] = useState2(timezone);
|
|
125
|
-
const [busy, setBusy] = useState2(false);
|
|
126
|
-
const [msg, setMsg] = useState2(null);
|
|
127
|
-
const start = async () => {
|
|
128
|
-
setOpen(true);
|
|
129
|
-
setSlots(null);
|
|
130
|
-
setMsg(null);
|
|
131
|
-
try {
|
|
132
|
-
const r = await api("/api/schedule/slots");
|
|
133
|
-
if (r.schedulingReady === false) {
|
|
134
|
-
setSlots([]);
|
|
135
|
-
setMsg(copy.unavailable);
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
setSlots(r.slots ?? []);
|
|
139
|
-
if (r.timezone) setTz(r.timezone);
|
|
140
|
-
} catch {
|
|
141
|
-
setSlots([]);
|
|
142
|
-
setMsg(copy.loadFailed);
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
const pick = async (slot) => {
|
|
146
|
-
setBusy(true);
|
|
147
|
-
setMsg(null);
|
|
148
|
-
try {
|
|
149
|
-
await api("/api/schedule/book", { method: "POST", body: JSON.stringify({ applicationId, startAt: slot.startAt }) });
|
|
150
|
-
setOpen(false);
|
|
151
|
-
await onRescheduled();
|
|
152
|
-
} catch (e) {
|
|
153
|
-
setMsg(e instanceof Error ? e.message : copy.slotGone);
|
|
154
|
-
} finally {
|
|
155
|
-
setBusy(false);
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
if (!open) {
|
|
159
|
-
return /* @__PURE__ */ jsx2("p", { className: "meeting-note", children: /* @__PURE__ */ jsx2(
|
|
160
|
-
"a",
|
|
161
|
-
{
|
|
162
|
-
href: "#",
|
|
163
|
-
onClick: (e) => {
|
|
164
|
-
e.preventDefault();
|
|
165
|
-
void start();
|
|
166
|
-
},
|
|
167
|
-
children: label
|
|
168
|
-
}
|
|
169
|
-
) });
|
|
170
|
-
}
|
|
171
|
-
return /* @__PURE__ */ jsxs2("div", { className: "msched", children: [
|
|
172
|
-
slots === null ? /* @__PURE__ */ jsx2("p", { className: "meeting-note", children: copy.loading }) : slots.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "meeting-note", children: msg ?? copy.noTimes }) : /* @__PURE__ */ jsx2(
|
|
173
|
-
SlotPicker,
|
|
174
|
-
{
|
|
175
|
-
slots,
|
|
176
|
-
timezone: tz,
|
|
177
|
-
classes: { days: "msched-days", day: "msched-day", times: "msched-times", time: "msched-time" },
|
|
178
|
-
onPick: (s) => void pick(s)
|
|
179
|
-
}
|
|
180
|
-
),
|
|
181
|
-
busy ? /* @__PURE__ */ jsx2("p", { className: "meeting-note", children: copy.rescheduling }) : null,
|
|
182
|
-
msg && slots && slots.length > 0 ? /* @__PURE__ */ jsx2("p", { className: "meeting-note error", children: msg }) : null,
|
|
183
|
-
/* @__PURE__ */ jsx2("p", { className: "meeting-note", children: /* @__PURE__ */ jsx2(
|
|
184
|
-
"a",
|
|
185
|
-
{
|
|
186
|
-
href: "#",
|
|
187
|
-
onClick: (e) => {
|
|
188
|
-
e.preventDefault();
|
|
189
|
-
setOpen(false);
|
|
190
|
-
},
|
|
191
|
-
children: copy.keepTime
|
|
192
|
-
}
|
|
193
|
-
) })
|
|
194
|
-
] });
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// src/ui/member-gifts.tsx
|
|
198
|
-
import { useEffect, useRef as useRef2, useState as useState4 } from "preact/hooks";
|
|
199
|
-
|
|
200
|
-
// src/ui/gift-offer-cards.tsx
|
|
201
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
202
|
-
var price = (cents, currency) => currency === "usd" ? fmtMoney(cents) : new Intl.NumberFormat(void 0, { style: "currency", currency: currency.toUpperCase() }).format(cents / 100);
|
|
203
|
-
function GiftOfferCards(props) {
|
|
204
|
-
const mode = props.mode ?? "preview";
|
|
205
|
-
return /* @__PURE__ */ jsx3("section", { className: "chapter-gift-offers", "aria-label": props.ariaLabel ?? "Gift options", children: props.offers.map((offer) => /* @__PURE__ */ jsxs3("article", { className: "card chapter-gift-offer", "data-offer-id": offer.id, children: [
|
|
206
|
-
/* @__PURE__ */ jsx3("div", { className: "card-label", children: offer.title }),
|
|
207
|
-
/* @__PURE__ */ jsx3("p", { children: offer.description }),
|
|
208
|
-
/* @__PURE__ */ jsxs3("p", { className: "meeting-date", children: [
|
|
209
|
-
price(offer.priceCents, offer.currency),
|
|
210
|
-
offer.billingMode === "subscription" ? " recurring" : ""
|
|
211
|
-
] }),
|
|
212
|
-
mode === "select" ? /* @__PURE__ */ jsx3("button", { type: "button", className: "btn secondary", "aria-pressed": props.selectedOfferId === offer.id, onClick: () => props.onSelect?.(offer.id), children: offer.ctaLabel }) : /* @__PURE__ */ jsx3("span", { className: "btn secondary", "aria-disabled": "true", children: offer.ctaLabel })
|
|
213
|
-
] }, offer.id)) });
|
|
214
|
-
}
|
|
116
|
+
// src/ui/membership-payment-step.tsx
|
|
117
|
+
import { useEffect, useState as useState3 } from "preact/hooks";
|
|
215
118
|
|
|
216
119
|
// src/ui/payment-step.tsx
|
|
217
|
-
import { useRef, useState as
|
|
218
|
-
import { jsx as
|
|
120
|
+
import { useRef, useState as useState2 } from "preact/hooks";
|
|
121
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
219
122
|
var loader = null;
|
|
220
123
|
function loadStripe() {
|
|
221
124
|
const existing = globalThis.Stripe;
|
|
@@ -249,9 +152,9 @@ function PaymentStep(props) {
|
|
|
249
152
|
simulation
|
|
250
153
|
} = props;
|
|
251
154
|
const copy = props.copy ?? inheritedCopy.join.payment;
|
|
252
|
-
const [status, setStatus] =
|
|
253
|
-
const [error, setError] =
|
|
254
|
-
const [lineItems, setLineItems] =
|
|
155
|
+
const [status, setStatus] = useState2("idle");
|
|
156
|
+
const [error, setError] = useState2(null);
|
|
157
|
+
const [lineItems, setLineItems] = useState2(null);
|
|
255
158
|
const mountRef = useRef(null);
|
|
256
159
|
const stripeRef = useRef(null);
|
|
257
160
|
const elementsRef = useRef(null);
|
|
@@ -325,12 +228,12 @@ function PaymentStep(props) {
|
|
|
325
228
|
setStatus("ready");
|
|
326
229
|
}
|
|
327
230
|
};
|
|
328
|
-
return /* @__PURE__ */
|
|
329
|
-
/* @__PURE__ */
|
|
330
|
-
merchantDisclosureText ? /* @__PURE__ */
|
|
331
|
-
/* @__PURE__ */
|
|
332
|
-
/* @__PURE__ */
|
|
333
|
-
/* @__PURE__ */
|
|
231
|
+
return /* @__PURE__ */ jsxs2("div", { className: "join-pay", children: [
|
|
232
|
+
/* @__PURE__ */ jsxs2("div", { className: "compliance-box", children: [
|
|
233
|
+
merchantDisclosureText ? /* @__PURE__ */ jsx2("p", { className: "compliance-merchant", children: merchantDisclosureText }) : null,
|
|
234
|
+
/* @__PURE__ */ jsx2("p", { className: "compliance-policy", children: refundPolicyText }),
|
|
235
|
+
/* @__PURE__ */ jsxs2("label", { className: "compliance-check", children: [
|
|
236
|
+
/* @__PURE__ */ jsx2(
|
|
334
237
|
"input",
|
|
335
238
|
{
|
|
336
239
|
type: "checkbox",
|
|
@@ -340,44 +243,352 @@ function PaymentStep(props) {
|
|
|
340
243
|
}
|
|
341
244
|
}
|
|
342
245
|
),
|
|
343
|
-
copy.consent ? /* @__PURE__ */
|
|
246
|
+
copy.consent ? /* @__PURE__ */ jsx2("span", { children: copy.consent }) : null
|
|
344
247
|
] })
|
|
345
248
|
] }),
|
|
346
|
-
status === "loading" ? /* @__PURE__ */
|
|
249
|
+
status === "loading" ? /* @__PURE__ */ jsx2("p", { className: "pay-status", children: copy.preparing }) : null,
|
|
347
250
|
lineItems && renderPriceLines ? renderPriceLines(lineItems) : null,
|
|
348
251
|
children,
|
|
349
|
-
simulation && (status === "ready" || status === "confirming") ? /* @__PURE__ */
|
|
350
|
-
/* @__PURE__ */
|
|
351
|
-
/* @__PURE__ */
|
|
252
|
+
simulation && (status === "ready" || status === "confirming") ? /* @__PURE__ */ jsxs2("fieldset", { className: "join-pay-simulation", children: [
|
|
253
|
+
/* @__PURE__ */ jsx2("legend", { children: "Payment details" }),
|
|
254
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
352
255
|
"Card number",
|
|
353
|
-
/* @__PURE__ */
|
|
256
|
+
/* @__PURE__ */ jsx2("input", { name: "simulationCardNumber", inputMode: "numeric", autoComplete: "off", defaultValue: "4242 4242 4242 4242" })
|
|
354
257
|
] }),
|
|
355
|
-
/* @__PURE__ */
|
|
258
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
356
259
|
"Expiration",
|
|
357
|
-
/* @__PURE__ */
|
|
260
|
+
/* @__PURE__ */ jsx2("input", { name: "simulationCardExpiry", inputMode: "numeric", autoComplete: "off", defaultValue: "12 / 34" })
|
|
358
261
|
] }),
|
|
359
|
-
/* @__PURE__ */
|
|
262
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
360
263
|
"Security code",
|
|
361
|
-
/* @__PURE__ */
|
|
264
|
+
/* @__PURE__ */ jsx2("input", { name: "simulationCardCvc", inputMode: "numeric", autoComplete: "off", defaultValue: "123" })
|
|
362
265
|
] }),
|
|
363
|
-
/* @__PURE__ */
|
|
266
|
+
/* @__PURE__ */ jsx2("p", { children: "This is a simulation. No card data is sent and no charge is created." })
|
|
364
267
|
] }) : null,
|
|
365
|
-
/* @__PURE__ */
|
|
366
|
-
status === "ready" || status === "confirming" ? /* @__PURE__ */
|
|
367
|
-
error ? /* @__PURE__ */
|
|
268
|
+
/* @__PURE__ */ jsx2("div", { ref: mountRef, hidden: status === "idle" || status === "loading" }),
|
|
269
|
+
status === "ready" || status === "confirming" ? /* @__PURE__ */ jsx2("button", { className: "submit-btn", disabled: status === "confirming", onClick: () => void pay(), children: status === "confirming" ? copy.processing : copy.payAndContinue }) : null,
|
|
270
|
+
error ? /* @__PURE__ */ jsx2("p", { className: "pay-error", children: error }) : null
|
|
368
271
|
] });
|
|
369
272
|
}
|
|
370
273
|
|
|
371
|
-
// src/ui/
|
|
274
|
+
// src/ui/membership-payment-step.tsx
|
|
275
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
276
|
+
function MembershipPaymentStep(props) {
|
|
277
|
+
const inherited = useChapterCopy();
|
|
278
|
+
const copy = props.copy ?? inherited.join.payment;
|
|
279
|
+
const [quote, setQuote] = useState3(null);
|
|
280
|
+
const [error, setError] = useState3(false);
|
|
281
|
+
const [revision, setRevision] = useState3(0);
|
|
282
|
+
useEffect(() => {
|
|
283
|
+
let live = true;
|
|
284
|
+
setQuote(null);
|
|
285
|
+
setError(false);
|
|
286
|
+
void fetch(`/api/payments/quote?application=${encodeURIComponent(props.applicationId)}`, { method: "POST", cache: "no-store" }).then(async (response) => {
|
|
287
|
+
if (!response.ok) throw new Error("quote unavailable");
|
|
288
|
+
const value = await response.json();
|
|
289
|
+
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");
|
|
290
|
+
if (live) setQuote(value);
|
|
291
|
+
}).catch(() => {
|
|
292
|
+
if (live) setError(true);
|
|
293
|
+
});
|
|
294
|
+
return () => {
|
|
295
|
+
live = false;
|
|
296
|
+
};
|
|
297
|
+
}, [props.applicationId, revision]);
|
|
298
|
+
const refresh = () => {
|
|
299
|
+
setQuote(null);
|
|
300
|
+
setRevision((value) => value + 1);
|
|
301
|
+
};
|
|
302
|
+
if (!quote || quote.applicationId !== props.applicationId) return /* @__PURE__ */ jsxs3("div", { className: "join-pay", role: "status", children: [
|
|
303
|
+
props.merchantDisclosureText ? /* @__PURE__ */ jsx3("p", { className: "compliance-merchant", children: props.merchantDisclosureText }) : null,
|
|
304
|
+
/* @__PURE__ */ jsx3("p", { children: error ? copy.setupFailed : copy.preparing }),
|
|
305
|
+
error ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: refresh, children: "Reload payment terms" }) : null
|
|
306
|
+
] });
|
|
307
|
+
const startCheckout = async () => {
|
|
308
|
+
const response = await fetch("/api/payments/subscription", {
|
|
309
|
+
method: "POST",
|
|
310
|
+
headers: { "content-type": "application/json" },
|
|
311
|
+
body: JSON.stringify({ applicationId: props.applicationId, refundPolicyAck: true, quoteDigest: quote.digest })
|
|
312
|
+
});
|
|
313
|
+
if (!response.ok) {
|
|
314
|
+
if (response.status === 409) refresh();
|
|
315
|
+
throw new Error(copy.setupFailed);
|
|
316
|
+
}
|
|
317
|
+
return response.json();
|
|
318
|
+
};
|
|
319
|
+
const amount = (cents) => new Intl.NumberFormat("en-US", { style: "currency", currency: quote.currency }).format(cents / 100);
|
|
320
|
+
return /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
321
|
+
/* @__PURE__ */ jsxs3("section", { className: "payment-quote", "aria-label": "Membership price", children: [
|
|
322
|
+
/* @__PURE__ */ jsx3("h3", { children: quote.tierName }),
|
|
323
|
+
props.renderPriceLines ? props.renderPriceLines(quote.lineItems) : /* @__PURE__ */ jsxs3("dl", { children: [
|
|
324
|
+
/* @__PURE__ */ jsx3("dt", { children: "Membership price" }),
|
|
325
|
+
/* @__PURE__ */ jsxs3("dd", { children: [
|
|
326
|
+
amount(quote.lineItems.standardCents),
|
|
327
|
+
" per ",
|
|
328
|
+
quote.interval
|
|
329
|
+
] }),
|
|
330
|
+
quote.lineItems.discountCents > 0 ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
331
|
+
/* @__PURE__ */ jsx3("dt", { children: "Discount" }),
|
|
332
|
+
/* @__PURE__ */ jsx3("dd", { children: amount(quote.lineItems.discountCents) })
|
|
333
|
+
] }) : null,
|
|
334
|
+
/* @__PURE__ */ jsx3("dt", { children: "Due today" }),
|
|
335
|
+
/* @__PURE__ */ jsx3("dd", { children: amount(quote.lineItems.dueTodayCents) })
|
|
336
|
+
] }),
|
|
337
|
+
quote.commercial ? /* @__PURE__ */ jsxs3("div", { role: "note", "aria-label": "Renewal terms", children: [
|
|
338
|
+
quote.commercial.initialTermEndsAt !== void 0 ? /* @__PURE__ */ jsxs3("p", { children: [
|
|
339
|
+
"First renewal: ",
|
|
340
|
+
new Intl.DateTimeFormat("en-US", {
|
|
341
|
+
dateStyle: "long",
|
|
342
|
+
timeZone: "UTC"
|
|
343
|
+
}).format(quote.commercial.initialTermEndsAt),
|
|
344
|
+
"."
|
|
345
|
+
] }) : null,
|
|
346
|
+
/* @__PURE__ */ jsxs3("p", { children: [
|
|
347
|
+
"Renews automatically at ",
|
|
348
|
+
amount(quote.commercial.renewalCents),
|
|
349
|
+
" per ",
|
|
350
|
+
quote.interval,
|
|
351
|
+
" unless canceled before renewal."
|
|
352
|
+
] }),
|
|
353
|
+
quote.commercial.discountDuration === "first_term" ? /* @__PURE__ */ jsx3("p", { children: "The discount applies to your first paid term only." }) : null,
|
|
354
|
+
quote.commercial.discountDuration === "while_active" ? /* @__PURE__ */ jsx3("p", { children: "The discounted rate continues while this membership stays active." }) : null
|
|
355
|
+
] }) : null,
|
|
356
|
+
quote.trustCopy ? /* @__PURE__ */ jsx3("p", { className: "pay-trust", children: quote.trustCopy }) : null
|
|
357
|
+
] }),
|
|
358
|
+
/* @__PURE__ */ jsx3(
|
|
359
|
+
PaymentStep,
|
|
360
|
+
{
|
|
361
|
+
...props,
|
|
362
|
+
refundPolicyText: quote.refundPolicyText,
|
|
363
|
+
merchantDisclosureText: quote.merchantDisclosureText,
|
|
364
|
+
renderPriceLines: void 0,
|
|
365
|
+
startCheckout
|
|
366
|
+
}
|
|
367
|
+
)
|
|
368
|
+
] });
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// src/ui/journey-frame.tsx
|
|
372
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
|
|
373
|
+
var styles = `
|
|
374
|
+
.chapter-journey{color:var(--ui-text,#202827);font-family:var(--ui-font-sans,inherit);line-height:1.65;max-width:46rem;margin-inline:auto;min-width:0}
|
|
375
|
+
.chapter-journey *{box-sizing:border-box}
|
|
376
|
+
.chapter-journey :where(h2,h3,p){margin:0 0 1rem}
|
|
377
|
+
.chapter-journey :where(h2,h3){font-family:var(--ui-font-display,inherit);line-height:1.2;letter-spacing:-.025em;text-transform:none}
|
|
378
|
+
.chapter-journey h2{font-size:clamp(1.6rem,3vw,2.15rem)}
|
|
379
|
+
.chapter-journey h3{font-size:1.3rem}
|
|
380
|
+
.chapter-journey :where(.card,.join-form,.payment-quote,.join-book){padding:clamp(1.25rem,4vw,2.4rem);border:1px solid var(--ui-border,#dfe3df);border-radius:var(--ui-radius-lg,16px);background:var(--ui-surface,#fff);margin-block:1.2rem}
|
|
381
|
+
.chapter-journey :where(.card-label,.journey-eyebrow){font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ui-text-muted,#536360);margin-bottom:.7rem;font-weight:600}
|
|
382
|
+
.chapter-journey :where(form,.journey-fields){display:grid;gap:1.25rem}
|
|
383
|
+
.chapter-journey :where(label){display:block;font-size:.95rem;font-weight:500;letter-spacing:normal;text-transform:none;line-height:1.55}
|
|
384
|
+
.chapter-journey :where(input:not([type=checkbox]):not([type=radio]),select,textarea){display:block;width:100%;margin-top:.45rem;padding:.8rem 1rem;border:1px solid var(--ui-border-strong,#aeb9b5);border-radius:8px;background:var(--ui-bg,#fff);color:inherit;font:inherit;min-height:48px}
|
|
385
|
+
.chapter-journey :where(input,textarea,button,a,select):focus-visible{outline:3px solid var(--ui-accent,#3d6a60);outline-offset:3px}
|
|
386
|
+
.chapter-journey :where(input[type=checkbox],input[type=radio]){width:1.15rem;height:1.15rem;margin:.2rem 0 0;flex:none;accent-color:var(--ui-accent,#285c50)}
|
|
387
|
+
.chapter-journey :where(.journey-consent,.compliance-check,.check){display:flex;align-items:flex-start;gap:.8rem;text-align:left;letter-spacing:normal;text-transform:none;font-size:.95rem;font-weight:400}
|
|
388
|
+
.chapter-journey :where(button,.submit-btn,.apply-link){display:inline-flex;align-items:center;justify-content:center;min-height:46px;padding:.75rem 1.2rem;border:1px solid transparent;border-radius:8px;font:inherit;font-size:.95rem;font-weight:600;letter-spacing:normal;line-height:1.35;text-decoration:none;text-transform:none;cursor:pointer;background:var(--ui-accent,#285c50);color:var(--ui-on-accent,#fff)}
|
|
389
|
+
.chapter-journey :where(button.secondary,.journey-secondary){background:transparent;color:var(--ui-text,#202827);border-color:var(--ui-border,#dfe3df)}
|
|
390
|
+
.chapter-journey :is(.slot-time,.slot-day){background:var(--ui-surface,#fff);color:var(--ui-text,#202827);border-color:var(--ui-border,#dfe3df)}
|
|
391
|
+
.chapter-journey :is(.slot-time,.slot-day):hover{background:var(--ui-surface-2,#f3f5f2);color:var(--ui-text,#202827);border-color:var(--ui-accent,#285c50)}
|
|
392
|
+
.chapter-journey :is(.slot-time,.slot-day)[aria-pressed=true]{background:var(--ui-accent,#285c50);color:var(--ui-on-accent,#fff)}
|
|
393
|
+
.chapter-journey button:disabled{opacity:.55;cursor:default}
|
|
394
|
+
.chapter-journey :where(.compliance-box,.journey-note){padding:1.2rem;background:var(--ui-surface-2,#f3f5f2);border-radius:10px;margin-block:1.2rem}
|
|
395
|
+
.chapter-journey :where(.compliance-box p:last-child,.journey-note p:last-child,.card p:last-child){margin-bottom:0}
|
|
396
|
+
.chapter-journey .journey-invitation{padding:1.1rem 1.3rem;border-left:3px solid var(--ui-accent,#285c50);background:var(--ui-surface-2,#f3f5f2);border-radius:0 10px 10px 0;margin-block:1rem}
|
|
397
|
+
.chapter-journey .journey-invitation p{margin:0}
|
|
398
|
+
.chapter-journey :where(.journey-error,.join-error,.pay-error,[role=alert]){padding:.9rem 1rem;border:1px solid var(--ui-danger,#9c3636);border-radius:8px;color:var(--ui-danger,#9c3636);font-size:.95rem}
|
|
399
|
+
.chapter-journey :where(.payment-quote dl,.journey-summary){display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.65rem 1rem;margin:1.3rem 0;padding:1rem 0;border-block:1px solid var(--ui-border,#dfe3df)}
|
|
400
|
+
.chapter-journey :where(dd){margin:0;text-align:right;font-variant-numeric:tabular-nums}
|
|
401
|
+
.chapter-journey :where(.pay-status,.meeting-note,.slots-status){color:var(--ui-text-muted,#536360)}
|
|
402
|
+
.chapter-journey .journey-actions{display:flex;gap:.75rem;flex-wrap:wrap;margin-top:1.25rem}
|
|
403
|
+
.chapter-journey fieldset{min-width:0;border:0;padding:0;margin:0}
|
|
404
|
+
@media(max-width:520px){.chapter-journey .journey-actions>*{width:100%}.chapter-journey .journey-summary{grid-template-columns:1fr}.chapter-journey .journey-summary dd{text-align:left}.chapter-journey :where(.card,.join-form,.payment-quote,.join-book){padding:1.25rem}}
|
|
405
|
+
`;
|
|
406
|
+
function JourneyFrame({ children }) {
|
|
407
|
+
return /* @__PURE__ */ jsxs4("div", { className: "chapter-journey", children: [
|
|
408
|
+
/* @__PURE__ */ jsx4("style", { children: styles }),
|
|
409
|
+
children
|
|
410
|
+
] });
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// src/ui/member-restart.tsx
|
|
372
414
|
import { jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
|
|
415
|
+
function MemberRestart(props) {
|
|
416
|
+
const [id, setId] = useState4(props.applicationId);
|
|
417
|
+
const [busy, setBusy] = useState4(false);
|
|
418
|
+
const [error, setError] = useState4("");
|
|
419
|
+
const [paid, setPaid] = useState4(false);
|
|
420
|
+
const [checking, setChecking] = useState4(false);
|
|
421
|
+
const [revision, setRevision] = useState4(0);
|
|
422
|
+
useEffect2(() => {
|
|
423
|
+
if (!paid) return;
|
|
424
|
+
let live = true, timer, attempt = 0;
|
|
425
|
+
setChecking(true);
|
|
426
|
+
const check = async () => {
|
|
427
|
+
try {
|
|
428
|
+
const me = await props.api("/api/me");
|
|
429
|
+
if (!live) return;
|
|
430
|
+
if (me.memberAccess === true) {
|
|
431
|
+
await props.onComplete();
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
} catch {
|
|
435
|
+
}
|
|
436
|
+
if (!live) return;
|
|
437
|
+
if (++attempt < 12) timer = setTimeout(() => void check(), 2500);
|
|
438
|
+
else setChecking(false);
|
|
439
|
+
};
|
|
440
|
+
void check();
|
|
441
|
+
return () => {
|
|
442
|
+
live = false;
|
|
443
|
+
clearTimeout(timer);
|
|
444
|
+
};
|
|
445
|
+
}, [paid, revision]);
|
|
446
|
+
const start = async () => {
|
|
447
|
+
setBusy(true);
|
|
448
|
+
setError("");
|
|
449
|
+
try {
|
|
450
|
+
const result = await props.api("/api/membership/restart", { method: "POST" });
|
|
451
|
+
if (!result.applicationId) throw new Error("We could not prepare your subscription. Please retry.");
|
|
452
|
+
setId(result.applicationId);
|
|
453
|
+
} catch (cause) {
|
|
454
|
+
setError(cause instanceof Error ? cause.message.slice(0, 300) : "We could not prepare your subscription. Please retry.");
|
|
455
|
+
} finally {
|
|
456
|
+
setBusy(false);
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
return /* @__PURE__ */ jsx5(JourneyFrame, { children: /* @__PURE__ */ jsxs5("section", { className: "card", "aria-label": "Restart membership", children: [
|
|
460
|
+
/* @__PURE__ */ jsx5("p", { className: "card-label", children: "Welcome back" }),
|
|
461
|
+
/* @__PURE__ */ jsx5("h2", { children: "Restart your membership" }),
|
|
462
|
+
/* @__PURE__ */ jsx5("p", { children: "Your account is ready, and your previous approval still counts. No new application or interview is needed." }),
|
|
463
|
+
/* @__PURE__ */ jsxs5("dl", { className: "journey-summary", children: [
|
|
464
|
+
/* @__PURE__ */ jsx5("dt", { children: "Name" }),
|
|
465
|
+
/* @__PURE__ */ jsx5("dd", { children: [props.application.firstName, props.application.lastName].filter(Boolean).join(" ") }),
|
|
466
|
+
/* @__PURE__ */ jsx5("dt", { children: "Email" }),
|
|
467
|
+
/* @__PURE__ */ jsx5("dd", { children: props.application.email })
|
|
468
|
+
] }),
|
|
469
|
+
paid ? /* @__PURE__ */ jsxs5("div", { role: "status", children: [
|
|
470
|
+
/* @__PURE__ */ jsx5("h3", { children: "Confirming your membership" }),
|
|
471
|
+
/* @__PURE__ */ jsx5("p", { children: "We\u2019re waiting for payment confirmation. Your membership will open here as soon as it arrives." }),
|
|
472
|
+
!checking ? /* @__PURE__ */ jsx5("button", { type: "button", onClick: () => setRevision((value) => value + 1), children: "Check membership" }) : null
|
|
473
|
+
] }) : id ? /* @__PURE__ */ jsx5(MembershipPaymentStep, { applicationId: id, refundPolicyText: "", onPaid: () => setPaid(true) }) : /* @__PURE__ */ jsx5("button", { type: "button", disabled: busy, onClick: () => void start(), children: busy ? "Preparing your membership\u2026" : "Review membership and payment" }),
|
|
474
|
+
error ? /* @__PURE__ */ jsx5("p", { role: "alert", children: error }) : null
|
|
475
|
+
] }) });
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// src/ui/members.tsx
|
|
479
|
+
import { useEffect as useEffect6, useState as useState9 } from "preact/hooks";
|
|
480
|
+
|
|
481
|
+
// src/ui/reschedule.tsx
|
|
482
|
+
import { useState as useState5 } from "preact/hooks";
|
|
483
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
|
|
484
|
+
function Rescheduler(props) {
|
|
485
|
+
const inheritedCopy = useChapterCopy();
|
|
486
|
+
const copy = props.copy ?? inheritedCopy.members.reschedule;
|
|
487
|
+
const { api, applicationId, timezone, onRescheduled, label = copy.changeTime } = props;
|
|
488
|
+
const [open, setOpen] = useState5(false);
|
|
489
|
+
const [slots, setSlots] = useState5(null);
|
|
490
|
+
const [tz, setTz] = useState5(timezone);
|
|
491
|
+
const [busy, setBusy] = useState5(false);
|
|
492
|
+
const [msg, setMsg] = useState5(null);
|
|
493
|
+
const start = async () => {
|
|
494
|
+
setOpen(true);
|
|
495
|
+
setSlots(null);
|
|
496
|
+
setMsg(null);
|
|
497
|
+
try {
|
|
498
|
+
const r = await api("/api/schedule/slots");
|
|
499
|
+
if (r.schedulingReady === false) {
|
|
500
|
+
setSlots([]);
|
|
501
|
+
setMsg(copy.unavailable);
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
setSlots(r.slots ?? []);
|
|
505
|
+
if (r.timezone) setTz(r.timezone);
|
|
506
|
+
} catch {
|
|
507
|
+
setSlots([]);
|
|
508
|
+
setMsg(copy.loadFailed);
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
const pick = async (slot) => {
|
|
512
|
+
setBusy(true);
|
|
513
|
+
setMsg(null);
|
|
514
|
+
try {
|
|
515
|
+
await api("/api/schedule/book", { method: "POST", body: JSON.stringify({ applicationId, startAt: slot.startAt }) });
|
|
516
|
+
setOpen(false);
|
|
517
|
+
await onRescheduled();
|
|
518
|
+
} catch (e) {
|
|
519
|
+
setMsg(e instanceof Error ? e.message : copy.slotGone);
|
|
520
|
+
} finally {
|
|
521
|
+
setBusy(false);
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
if (!open) {
|
|
525
|
+
return /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: /* @__PURE__ */ jsx6(
|
|
526
|
+
"a",
|
|
527
|
+
{
|
|
528
|
+
href: "#",
|
|
529
|
+
onClick: (e) => {
|
|
530
|
+
e.preventDefault();
|
|
531
|
+
void start();
|
|
532
|
+
},
|
|
533
|
+
children: label
|
|
534
|
+
}
|
|
535
|
+
) });
|
|
536
|
+
}
|
|
537
|
+
return /* @__PURE__ */ jsxs6("div", { className: "msched", children: [
|
|
538
|
+
slots === null ? /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: copy.loading }) : slots.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: msg ?? copy.noTimes }) : /* @__PURE__ */ jsx6(
|
|
539
|
+
SlotPicker,
|
|
540
|
+
{
|
|
541
|
+
slots,
|
|
542
|
+
timezone: tz,
|
|
543
|
+
classes: { days: "msched-days", day: "msched-day", times: "msched-times", time: "msched-time" },
|
|
544
|
+
onPick: (s) => void pick(s)
|
|
545
|
+
}
|
|
546
|
+
),
|
|
547
|
+
busy ? /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: copy.rescheduling }) : null,
|
|
548
|
+
msg && slots && slots.length > 0 ? /* @__PURE__ */ jsx6("p", { className: "meeting-note error", children: msg }) : null,
|
|
549
|
+
/* @__PURE__ */ jsx6("p", { className: "meeting-note", children: /* @__PURE__ */ jsx6(
|
|
550
|
+
"a",
|
|
551
|
+
{
|
|
552
|
+
href: "#",
|
|
553
|
+
onClick: (e) => {
|
|
554
|
+
e.preventDefault();
|
|
555
|
+
setOpen(false);
|
|
556
|
+
},
|
|
557
|
+
children: copy.keepTime
|
|
558
|
+
}
|
|
559
|
+
) })
|
|
560
|
+
] });
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// src/ui/member-gifts.tsx
|
|
564
|
+
import { useEffect as useEffect3, useRef as useRef2, useState as useState6 } from "preact/hooks";
|
|
565
|
+
|
|
566
|
+
// src/ui/gift-offer-cards.tsx
|
|
567
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
|
|
568
|
+
var price = (cents, currency) => currency === "usd" ? fmtMoney(cents) : new Intl.NumberFormat(void 0, { style: "currency", currency: currency.toUpperCase() }).format(cents / 100);
|
|
569
|
+
function GiftOfferCards(props) {
|
|
570
|
+
const mode = props.mode ?? "preview";
|
|
571
|
+
return /* @__PURE__ */ jsx7("section", { className: "chapter-gift-offers", "aria-label": props.ariaLabel ?? "Gift options", children: props.offers.map((offer) => /* @__PURE__ */ jsxs7("article", { className: "card chapter-gift-offer", "data-offer-id": offer.id, children: [
|
|
572
|
+
/* @__PURE__ */ jsx7("div", { className: "card-label", children: offer.title }),
|
|
573
|
+
/* @__PURE__ */ jsx7("p", { children: offer.description }),
|
|
574
|
+
/* @__PURE__ */ jsxs7("p", { className: "meeting-date", children: [
|
|
575
|
+
price(offer.priceCents, offer.currency),
|
|
576
|
+
offer.billingMode === "subscription" ? " recurring" : ""
|
|
577
|
+
] }),
|
|
578
|
+
mode === "select" ? /* @__PURE__ */ jsx7("button", { type: "button", className: "btn secondary", "aria-pressed": props.selectedOfferId === offer.id, onClick: () => props.onSelect?.(offer.id), children: offer.ctaLabel }) : /* @__PURE__ */ jsx7("span", { className: "btn secondary", "aria-disabled": "true", children: offer.ctaLabel })
|
|
579
|
+
] }, offer.id)) });
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// src/ui/member-gifts.tsx
|
|
583
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
|
|
373
584
|
function GiftPurchases(props) {
|
|
374
|
-
const [data, setData] =
|
|
375
|
-
const [selected, setSelected] =
|
|
376
|
-
const [code, setCode] =
|
|
377
|
-
const [message, setMessage] =
|
|
585
|
+
const [data, setData] = useState6(null);
|
|
586
|
+
const [selected, setSelected] = useState6(null);
|
|
587
|
+
const [code, setCode] = useState6("");
|
|
588
|
+
const [message, setMessage] = useState6("");
|
|
378
589
|
const purchaseId = useRef2(crypto.randomUUID());
|
|
379
590
|
const load = async () => setData(await props.api("/api/gifts"));
|
|
380
|
-
|
|
591
|
+
useEffect3(() => {
|
|
381
592
|
void load().catch(() => setData({ offers: [], claims: [] }));
|
|
382
593
|
}, []);
|
|
383
594
|
const rotate = async (claimId) => {
|
|
@@ -392,16 +603,16 @@ function GiftPurchases(props) {
|
|
|
392
603
|
if (!data) return null;
|
|
393
604
|
if (data.offers.length === 0 && data.claims.length === 0) return null;
|
|
394
605
|
const offer = data.offers.find((item) => item.id === selected);
|
|
395
|
-
return /* @__PURE__ */
|
|
396
|
-
data.offers.length ? /* @__PURE__ */
|
|
397
|
-
/* @__PURE__ */
|
|
398
|
-
/* @__PURE__ */
|
|
399
|
-
/* @__PURE__ */
|
|
606
|
+
return /* @__PURE__ */ jsxs8("section", { className: "member-gifts", children: [
|
|
607
|
+
data.offers.length ? /* @__PURE__ */ jsxs8("div", { className: "card", children: [
|
|
608
|
+
/* @__PURE__ */ jsx8("div", { className: "card-label", children: props.copy.title }),
|
|
609
|
+
/* @__PURE__ */ jsx8("p", { children: props.copy.body }),
|
|
610
|
+
/* @__PURE__ */ jsx8(GiftOfferCards, { offers: data.offers, mode: "select", selectedOfferId: selected, onSelect: (id) => {
|
|
400
611
|
setSelected(id);
|
|
401
612
|
setCode("");
|
|
402
613
|
purchaseId.current = crypto.randomUUID();
|
|
403
614
|
} }),
|
|
404
|
-
offer ? /* @__PURE__ */
|
|
615
|
+
offer ? /* @__PURE__ */ jsx8(
|
|
405
616
|
PaymentStep,
|
|
406
617
|
{
|
|
407
618
|
applicationId: purchaseId.current,
|
|
@@ -421,31 +632,31 @@ function GiftPurchases(props) {
|
|
|
421
632
|
}
|
|
422
633
|
}
|
|
423
634
|
) : null,
|
|
424
|
-
code ? /* @__PURE__ */
|
|
425
|
-
/* @__PURE__ */
|
|
426
|
-
/* @__PURE__ */
|
|
635
|
+
code ? /* @__PURE__ */ jsxs8("div", { className: "gift-code-once", children: [
|
|
636
|
+
/* @__PURE__ */ jsx8("output", { children: code }),
|
|
637
|
+
/* @__PURE__ */ jsx8("p", { children: props.copy.saveCode })
|
|
427
638
|
] }) : null
|
|
428
639
|
] }) : null,
|
|
429
|
-
/* @__PURE__ */
|
|
430
|
-
/* @__PURE__ */
|
|
431
|
-
data.claims.length ? data.claims.map((claim) => /* @__PURE__ */
|
|
432
|
-
/* @__PURE__ */
|
|
433
|
-
/* @__PURE__ */
|
|
434
|
-
claim.status === "pending" ? /* @__PURE__ */
|
|
435
|
-
] }, claim.id)) : /* @__PURE__ */
|
|
436
|
-
message ? /* @__PURE__ */
|
|
640
|
+
/* @__PURE__ */ jsxs8("div", { className: "card", children: [
|
|
641
|
+
/* @__PURE__ */ jsx8("div", { className: "card-label", children: props.copy.purchases }),
|
|
642
|
+
data.claims.length ? data.claims.map((claim) => /* @__PURE__ */ jsxs8("div", { className: "member-row", children: [
|
|
643
|
+
/* @__PURE__ */ jsx8("span", { children: claim.offerId }),
|
|
644
|
+
/* @__PURE__ */ jsx8("span", { children: props.copy[claim.status] }),
|
|
645
|
+
claim.status === "pending" ? /* @__PURE__ */ jsx8("button", { className: "btn secondary mini", onClick: () => void rotate(claim.id), children: props.copy.rotate }) : null
|
|
646
|
+
] }, claim.id)) : /* @__PURE__ */ jsx8("p", { children: props.copy.noPurchases }),
|
|
647
|
+
message ? /* @__PURE__ */ jsx8("p", { role: "status", children: message }) : null
|
|
437
648
|
] })
|
|
438
649
|
] });
|
|
439
650
|
}
|
|
440
651
|
var MemberGifts = GiftPurchases;
|
|
441
652
|
|
|
442
653
|
// src/ui/member-named-seat.tsx
|
|
443
|
-
import { useEffect as
|
|
444
|
-
import { Fragment as
|
|
654
|
+
import { useEffect as useEffect4, useState as useState7 } from "preact/hooks";
|
|
655
|
+
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
|
|
445
656
|
function NamedSeatPurchase({ api }) {
|
|
446
|
-
const [data, setData] =
|
|
447
|
-
const [name, setName] =
|
|
448
|
-
const [terms, setTerms] =
|
|
657
|
+
const [data, setData] = useState7(null), [error, setError] = useState7("");
|
|
658
|
+
const [name, setName] = useState7(""), [email, setEmail] = useState7(""), [reviewing, setReviewing] = useState7(false);
|
|
659
|
+
const [terms, setTerms] = useState7(false), [pending, setPending] = useState7(false);
|
|
449
660
|
const load = async () => {
|
|
450
661
|
try {
|
|
451
662
|
const value = await api("/api/named-seat");
|
|
@@ -459,23 +670,23 @@ function NamedSeatPurchase({ api }) {
|
|
|
459
670
|
setError("The named-seat service is unavailable. Refresh to check your purchase before trying again.");
|
|
460
671
|
}
|
|
461
672
|
};
|
|
462
|
-
|
|
673
|
+
useEffect4(() => {
|
|
463
674
|
void load();
|
|
464
675
|
}, []);
|
|
465
676
|
const money = data ? new Intl.NumberFormat("en-US", { style: "currency", currency: data.currency }).format(data.amountCents / 100) : "";
|
|
466
|
-
return /* @__PURE__ */
|
|
467
|
-
/* @__PURE__ */
|
|
468
|
-
error ? /* @__PURE__ */
|
|
469
|
-
data ? /* @__PURE__ */
|
|
470
|
-
data.seat ? /* @__PURE__ */
|
|
677
|
+
return /* @__PURE__ */ jsx9(JourneyFrame, { children: /* @__PURE__ */ jsxs9("section", { className: "card member-named-seat", "aria-label": "Named additional seat", children: [
|
|
678
|
+
/* @__PURE__ */ jsx9("h2", { children: "Named additional seat" }),
|
|
679
|
+
error ? /* @__PURE__ */ jsx9("p", { role: "alert", children: error }) : null,
|
|
680
|
+
data ? /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
681
|
+
data.seat ? /* @__PURE__ */ jsxs9("p", { children: [
|
|
471
682
|
data.seat.recipientName,
|
|
472
683
|
" \xB7 ",
|
|
473
684
|
data.seat.recipientEmail,
|
|
474
685
|
" \xB7 ",
|
|
475
686
|
data.seat.status.replaceAll("_", " ")
|
|
476
687
|
] }) : null,
|
|
477
|
-
data.eligible ? /* @__PURE__ */
|
|
478
|
-
/* @__PURE__ */
|
|
688
|
+
data.eligible ? /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
689
|
+
/* @__PURE__ */ jsxs9("p", { children: [
|
|
479
690
|
money,
|
|
480
691
|
" paid in full now. This seat ",
|
|
481
692
|
data.autoRenew ? "renews with your primary membership" : "ends with your primary membership",
|
|
@@ -486,38 +697,38 @@ function NamedSeatPurchase({ api }) {
|
|
|
486
697
|
" ",
|
|
487
698
|
"It belongs to one named person and cannot be reassigned."
|
|
488
699
|
] }),
|
|
489
|
-
/* @__PURE__ */
|
|
490
|
-
!reviewing ? /* @__PURE__ */
|
|
700
|
+
/* @__PURE__ */ jsx9("p", { children: "The recipient must accept and complete their own application and any required interview. An unaccepted seat is fully refunded after 30 days." }),
|
|
701
|
+
!reviewing ? /* @__PURE__ */ jsxs9("form", { onSubmit: (event) => {
|
|
491
702
|
event.preventDefault();
|
|
492
703
|
setReviewing(true);
|
|
493
704
|
setTerms(false);
|
|
494
705
|
}, children: [
|
|
495
|
-
/* @__PURE__ */
|
|
706
|
+
/* @__PURE__ */ jsxs9("label", { children: [
|
|
496
707
|
"Recipient name",
|
|
497
|
-
/* @__PURE__ */
|
|
708
|
+
/* @__PURE__ */ jsx9("input", { required: true, maxLength: 160, value: name, disabled: Boolean(data.seat), onInput: (event) => setName(event.currentTarget.value) })
|
|
498
709
|
] }),
|
|
499
|
-
/* @__PURE__ */
|
|
710
|
+
/* @__PURE__ */ jsxs9("label", { children: [
|
|
500
711
|
"Recipient email",
|
|
501
|
-
/* @__PURE__ */
|
|
712
|
+
/* @__PURE__ */ jsx9("input", { required: true, type: "email", maxLength: 254, value: email, disabled: Boolean(data.seat), onInput: (event) => setEmail(event.currentTarget.value) })
|
|
502
713
|
] }),
|
|
503
|
-
/* @__PURE__ */
|
|
504
|
-
] }) : /* @__PURE__ */
|
|
505
|
-
/* @__PURE__ */
|
|
714
|
+
/* @__PURE__ */ jsx9("button", { className: "btn primary", type: "submit", children: "Review named seat" })
|
|
715
|
+
] }) : /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
716
|
+
/* @__PURE__ */ jsxs9("p", { children: [
|
|
506
717
|
"For ",
|
|
507
718
|
name,
|
|
508
719
|
" \xB7 ",
|
|
509
720
|
email
|
|
510
721
|
] }),
|
|
511
|
-
/* @__PURE__ */
|
|
722
|
+
/* @__PURE__ */ jsx9("button", { className: "btn secondary", type: "button", onClick: () => {
|
|
512
723
|
setReviewing(false);
|
|
513
724
|
setTerms(false);
|
|
514
725
|
void load();
|
|
515
726
|
}, children: "Back to recipient" }),
|
|
516
|
-
/* @__PURE__ */
|
|
517
|
-
/* @__PURE__ */
|
|
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."
|
|
727
|
+
/* @__PURE__ */ jsxs9("label", { className: "journey-consent", children: [
|
|
728
|
+
/* @__PURE__ */ jsx9("input", { type: "checkbox", checked: terms, onChange: (event) => setTerms(event.currentTarget.checked) }),
|
|
729
|
+
/* @__PURE__ */ jsx9("span", { children: 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
730
|
] }),
|
|
520
|
-
terms ? /* @__PURE__ */
|
|
731
|
+
terms ? /* @__PURE__ */ jsx9(
|
|
521
732
|
PaymentStep,
|
|
522
733
|
{
|
|
523
734
|
applicationId: data.membershipId,
|
|
@@ -536,17 +747,17 @@ function NamedSeatPurchase({ api }) {
|
|
|
536
747
|
}
|
|
537
748
|
) : null
|
|
538
749
|
] })
|
|
539
|
-
] }) : !data.seat ? /* @__PURE__ */
|
|
540
|
-
pending ? /* @__PURE__ */
|
|
541
|
-
] }) : !error ? /* @__PURE__ */
|
|
542
|
-
/* @__PURE__ */
|
|
543
|
-
] });
|
|
750
|
+
] }) : !data.seat ? /* @__PURE__ */ jsx9("p", { children: "Additional seats are offered only during the first three months of a paid membership." }) : null,
|
|
751
|
+
pending ? /* @__PURE__ */ jsx9("p", { role: "status", children: "Payment confirmation is being reconciled. The recipient\u2019s access begins only after their own acceptance and approval." }) : null
|
|
752
|
+
] }) : !error ? /* @__PURE__ */ jsx9("p", { children: "Loading your seat terms\u2026" }) : null,
|
|
753
|
+
/* @__PURE__ */ jsx9("button", { className: "btn secondary", onClick: () => void load(), children: "Refresh seat status" })
|
|
754
|
+
] }) });
|
|
544
755
|
}
|
|
545
756
|
|
|
546
757
|
// src/ui/member-content.tsx
|
|
547
|
-
import { useEffect as
|
|
758
|
+
import { useEffect as useEffect5, useMemo as useMemo2, useState as useState8 } from "preact/hooks";
|
|
548
759
|
import { Markdown } from "@odla-ai/ui/components";
|
|
549
|
-
import { Fragment as
|
|
760
|
+
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
|
|
550
761
|
var pageLabel = (page) => `${page.title}${page.access === "locked" ? " \xB7 Locked" : ""}`;
|
|
551
762
|
function MemberContentArea(props) {
|
|
552
763
|
const {
|
|
@@ -554,15 +765,15 @@ function MemberContentArea(props) {
|
|
|
554
765
|
path = "/api/member-content",
|
|
555
766
|
upsellHref,
|
|
556
767
|
onUpsell,
|
|
557
|
-
loadingContent = /* @__PURE__ */
|
|
558
|
-
emptyContent = /* @__PURE__ */
|
|
768
|
+
loadingContent = /* @__PURE__ */ jsx10("p", { className: "meeting-note", children: "Loading member pages\u2026" }),
|
|
769
|
+
emptyContent = /* @__PURE__ */ jsx10("p", { className: "meeting-note", children: "No member pages have been published yet." })
|
|
559
770
|
} = props;
|
|
560
|
-
const [data, setData] =
|
|
561
|
-
const [error, setError] =
|
|
562
|
-
const [selectedId, setSelectedId] =
|
|
771
|
+
const [data, setData] = useState8(props.initialData ?? null);
|
|
772
|
+
const [error, setError] = useState8(null);
|
|
773
|
+
const [selectedId, setSelectedId] = useState8(
|
|
563
774
|
props.initialPageId ?? props.initialData?.pages[0]?.id ?? ""
|
|
564
775
|
);
|
|
565
|
-
|
|
776
|
+
useEffect5(() => {
|
|
566
777
|
if (props.initialData) return;
|
|
567
778
|
let live = true;
|
|
568
779
|
setError(null);
|
|
@@ -584,18 +795,18 @@ function MemberContentArea(props) {
|
|
|
584
795
|
}
|
|
585
796
|
return [...result.entries()];
|
|
586
797
|
}, [data]);
|
|
587
|
-
if (error) return /* @__PURE__ */
|
|
798
|
+
if (error) return /* @__PURE__ */ jsxs10("p", { className: "meeting-note", role: "alert", children: [
|
|
588
799
|
"Member pages could not be loaded: ",
|
|
589
800
|
error
|
|
590
801
|
] });
|
|
591
|
-
if (!data) return /* @__PURE__ */
|
|
592
|
-
if (data.pages.length === 0) return /* @__PURE__ */
|
|
802
|
+
if (!data) return /* @__PURE__ */ jsx10(Fragment4, { children: loadingContent });
|
|
803
|
+
if (data.pages.length === 0) return /* @__PURE__ */ jsx10(Fragment4, { children: emptyContent });
|
|
593
804
|
const selected = data.pages.find((page) => page.id === selectedId) ?? data.pages[0];
|
|
594
805
|
const href = selected.upsell && upsellHref ? upsellHref(selected.upsell.tierId, selected) : void 0;
|
|
595
|
-
return /* @__PURE__ */
|
|
596
|
-
/* @__PURE__ */
|
|
597
|
-
/* @__PURE__ */
|
|
598
|
-
/* @__PURE__ */
|
|
806
|
+
return /* @__PURE__ */ jsxs10("div", { className: "chapter-member-content", "data-member-content": true, children: [
|
|
807
|
+
/* @__PURE__ */ jsx10("nav", { className: "chapter-member-content-nav", "aria-label": "Member pages", children: sections.map(([section, pages]) => /* @__PURE__ */ jsxs10("section", { className: "chapter-member-content-section", children: [
|
|
808
|
+
/* @__PURE__ */ jsx10("h2", { children: section }),
|
|
809
|
+
/* @__PURE__ */ jsx10("ul", { children: pages.map((page) => /* @__PURE__ */ jsx10("li", { "data-parent-page": page.navigation.parentId ?? void 0, children: /* @__PURE__ */ jsx10(
|
|
599
810
|
"button",
|
|
600
811
|
{
|
|
601
812
|
type: "button",
|
|
@@ -605,23 +816,23 @@ function MemberContentArea(props) {
|
|
|
605
816
|
}
|
|
606
817
|
) }, page.id)) })
|
|
607
818
|
] }, section)) }),
|
|
608
|
-
/* @__PURE__ */
|
|
609
|
-
/* @__PURE__ */
|
|
610
|
-
/* @__PURE__ */
|
|
819
|
+
/* @__PURE__ */ jsxs10("article", { className: "chapter-member-content-page", "data-access": selected.access, children: [
|
|
820
|
+
/* @__PURE__ */ jsxs10("header", { children: [
|
|
821
|
+
/* @__PURE__ */ jsxs10("div", { className: "card-label", children: [
|
|
611
822
|
selected.source.type === "parent" ? "Parent" : "Chapter",
|
|
612
823
|
" \xB7 ",
|
|
613
824
|
selected.access
|
|
614
825
|
] }),
|
|
615
|
-
/* @__PURE__ */
|
|
616
|
-
selected.summary ? /* @__PURE__ */
|
|
826
|
+
/* @__PURE__ */ jsx10("h1", { children: selected.title }),
|
|
827
|
+
selected.summary ? /* @__PURE__ */ jsx10("p", { children: selected.summary }) : null
|
|
617
828
|
] }),
|
|
618
|
-
selected.access === "allowed" && selected.bodyMarkdown ? /* @__PURE__ */
|
|
619
|
-
selected.teaserMarkdown ? /* @__PURE__ */
|
|
620
|
-
selected.upsell ? /* @__PURE__ */
|
|
621
|
-
/* @__PURE__ */
|
|
622
|
-
/* @__PURE__ */
|
|
623
|
-
selected.upsell.bodyMarkdown ? /* @__PURE__ */
|
|
624
|
-
href ? /* @__PURE__ */
|
|
829
|
+
selected.access === "allowed" && selected.bodyMarkdown ? /* @__PURE__ */ jsx10(Markdown, { source: selected.bodyMarkdown }) : /* @__PURE__ */ jsxs10("div", { className: "chapter-member-content-locked", children: [
|
|
830
|
+
selected.teaserMarkdown ? /* @__PURE__ */ jsx10(Markdown, { source: selected.teaserMarkdown }) : /* @__PURE__ */ jsx10("p", { children: "This page is not included in your current membership." }),
|
|
831
|
+
selected.upsell ? /* @__PURE__ */ jsxs10("aside", { className: "chapter-member-content-upsell", "aria-label": selected.upsell.label ?? "Membership option", children: [
|
|
832
|
+
/* @__PURE__ */ jsx10("h2", { children: selected.upsell.label ?? selected.upsell.tierName }),
|
|
833
|
+
/* @__PURE__ */ jsx10("p", { children: fmtMoney(selected.upsell.priceCents) }),
|
|
834
|
+
selected.upsell.bodyMarkdown ? /* @__PURE__ */ jsx10(Markdown, { source: selected.upsell.bodyMarkdown }) : null,
|
|
835
|
+
href ? /* @__PURE__ */ jsx10("a", { className: "btn primary", href, children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : onUpsell ? /* @__PURE__ */ jsx10("button", { className: "btn primary", type: "button", onClick: () => onUpsell(selected.upsell.tierId, selected), children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : null
|
|
625
836
|
] }) : null
|
|
626
837
|
] })
|
|
627
838
|
] })
|
|
@@ -629,12 +840,12 @@ function MemberContentArea(props) {
|
|
|
629
840
|
}
|
|
630
841
|
|
|
631
842
|
// src/ui/members.tsx
|
|
632
|
-
import { Fragment as
|
|
843
|
+
import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
|
|
633
844
|
function card(copy, kicker, body) {
|
|
634
|
-
return /* @__PURE__ */
|
|
635
|
-
/* @__PURE__ */
|
|
636
|
-
/* @__PURE__ */
|
|
637
|
-
/* @__PURE__ */
|
|
845
|
+
return /* @__PURE__ */ jsxs11("div", { className: "card", children: [
|
|
846
|
+
/* @__PURE__ */ jsx11("div", { className: "card-label", children: copy.provisional.cardLabel }),
|
|
847
|
+
/* @__PURE__ */ jsxs11("div", { className: "meeting-block", children: [
|
|
848
|
+
/* @__PURE__ */ jsx11("div", { className: "meeting-kicker", children: kicker }),
|
|
638
849
|
body
|
|
639
850
|
] })
|
|
640
851
|
] });
|
|
@@ -645,9 +856,9 @@ function ProvisionalCard(props) {
|
|
|
645
856
|
return card(
|
|
646
857
|
copy,
|
|
647
858
|
copy.provisional.applicationNeeded,
|
|
648
|
-
/* @__PURE__ */
|
|
649
|
-
/* @__PURE__ */
|
|
650
|
-
/* @__PURE__ */
|
|
859
|
+
/* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
860
|
+
/* @__PURE__ */ jsx11("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
|
|
861
|
+
/* @__PURE__ */ jsx11("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
|
|
651
862
|
] })
|
|
652
863
|
);
|
|
653
864
|
}
|
|
@@ -655,19 +866,19 @@ function ProvisionalCard(props) {
|
|
|
655
866
|
return card(
|
|
656
867
|
copy,
|
|
657
868
|
copy.provisional.refunded,
|
|
658
|
-
/* @__PURE__ */
|
|
869
|
+
/* @__PURE__ */ jsx11("div", { className: "meeting-note", children: copy.provisional.refundedBody })
|
|
659
870
|
);
|
|
660
871
|
}
|
|
661
|
-
const membership = application.paid ? /* @__PURE__ */
|
|
872
|
+
const membership = application.paid ? /* @__PURE__ */ jsx11("div", { className: "meeting-note", children: application.renewalAt ? formatChapterCopy(copy.provisional.renews, { date: fmtDate(application.renewalAt) }) : copy.provisional.active }) : null;
|
|
662
873
|
if (application.meetingAt) {
|
|
663
874
|
return card(
|
|
664
875
|
copy,
|
|
665
876
|
copy.provisional.introductionCall,
|
|
666
|
-
/* @__PURE__ */
|
|
667
|
-
/* @__PURE__ */
|
|
668
|
-
/* @__PURE__ */
|
|
669
|
-
application.meetUrl ? /* @__PURE__ */
|
|
670
|
-
/* @__PURE__ */
|
|
877
|
+
/* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
878
|
+
/* @__PURE__ */ jsx11("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
|
|
879
|
+
/* @__PURE__ */ jsx11("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
|
|
880
|
+
application.meetUrl ? /* @__PURE__ */ jsx11("div", { className: "meeting-note", children: /* @__PURE__ */ jsx11("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
|
|
881
|
+
/* @__PURE__ */ jsx11(
|
|
671
882
|
Rescheduler,
|
|
672
883
|
{
|
|
673
884
|
api,
|
|
@@ -684,9 +895,9 @@ function ProvisionalCard(props) {
|
|
|
684
895
|
return card(
|
|
685
896
|
copy,
|
|
686
897
|
copy.provisional.bookCall,
|
|
687
|
-
/* @__PURE__ */
|
|
688
|
-
/* @__PURE__ */
|
|
689
|
-
/* @__PURE__ */
|
|
898
|
+
/* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
899
|
+
/* @__PURE__ */ jsx11("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
|
|
900
|
+
/* @__PURE__ */ jsx11(
|
|
690
901
|
Rescheduler,
|
|
691
902
|
{
|
|
692
903
|
api,
|
|
@@ -713,8 +924,8 @@ function MembersArea(props) {
|
|
|
713
924
|
renderProvisional
|
|
714
925
|
} = props;
|
|
715
926
|
const copy = props.copy ?? inheritedCopy.members;
|
|
716
|
-
const [me, setMe] =
|
|
717
|
-
const [error, setError] =
|
|
927
|
+
const [me, setMe] = useState9(null);
|
|
928
|
+
const [error, setError] = useState9(false);
|
|
718
929
|
const reload = async () => {
|
|
719
930
|
try {
|
|
720
931
|
setMe(await api("/api/me"));
|
|
@@ -722,25 +933,25 @@ function MembersArea(props) {
|
|
|
722
933
|
setError(true);
|
|
723
934
|
}
|
|
724
935
|
};
|
|
725
|
-
|
|
936
|
+
useEffect6(() => {
|
|
726
937
|
void reload();
|
|
727
938
|
}, []);
|
|
728
|
-
if (error) return /* @__PURE__ */
|
|
729
|
-
if (!me) return /* @__PURE__ */
|
|
939
|
+
if (error) return /* @__PURE__ */ jsx11("p", { className: "meeting-note", children: copy.loadFailed });
|
|
940
|
+
if (!me) return /* @__PURE__ */ jsx11("p", { className: "meeting-note", children: inheritedCopy.common.loading });
|
|
730
941
|
const role = me.role || "provisional";
|
|
731
|
-
return /* @__PURE__ */
|
|
732
|
-
/* @__PURE__ */
|
|
733
|
-
/* @__PURE__ */
|
|
734
|
-
/* @__PURE__ */
|
|
735
|
-
/* @__PURE__ */
|
|
942
|
+
return /* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
943
|
+
/* @__PURE__ */ jsxs11("div", { className: "card", children: [
|
|
944
|
+
/* @__PURE__ */ jsxs11("div", { className: "member-row", children: [
|
|
945
|
+
/* @__PURE__ */ jsx11("span", { className: "member-email", children: me.email }),
|
|
946
|
+
/* @__PURE__ */ jsx11("span", { className: "role-badge " + role, children: role })
|
|
736
947
|
] }),
|
|
737
|
-
/* @__PURE__ */
|
|
738
|
-
/* @__PURE__ */
|
|
739
|
-
me.authorized || me.superAdmin ? /* @__PURE__ */
|
|
948
|
+
/* @__PURE__ */ jsxs11("div", { className: "account-actions", children: [
|
|
949
|
+
/* @__PURE__ */ jsx11("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
|
|
950
|
+
me.authorized || me.superAdmin ? /* @__PURE__ */ jsx11("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
|
|
740
951
|
] })
|
|
741
952
|
] }),
|
|
742
|
-
me.memberAccess !== true ? (() => {
|
|
743
|
-
const defaultContent = /* @__PURE__ */
|
|
953
|
+
me.memberAccess !== true && me.membershipRestart?.eligible && me.application ? /* @__PURE__ */ jsx11(MemberRestart, { api, application: me.application, applicationId: me.membershipRestart.applicationId, onComplete: reload }) : me.memberAccess !== true ? (() => {
|
|
954
|
+
const defaultContent = /* @__PURE__ */ jsx11(
|
|
744
955
|
ProvisionalCard,
|
|
745
956
|
{
|
|
746
957
|
api,
|
|
@@ -757,128 +968,30 @@ function MembersArea(props) {
|
|
|
757
968
|
reload,
|
|
758
969
|
defaultContent
|
|
759
970
|
}) ?? defaultContent;
|
|
760
|
-
})() : memberContent ?? (memberPages ? /* @__PURE__ */
|
|
971
|
+
})() : memberContent ?? (memberPages ? /* @__PURE__ */ jsx11(
|
|
761
972
|
MemberContentArea,
|
|
762
973
|
{
|
|
763
974
|
api,
|
|
764
975
|
...memberPages === true ? {} : memberPages
|
|
765
976
|
}
|
|
766
|
-
) : /* @__PURE__ */
|
|
767
|
-
/* @__PURE__ */
|
|
768
|
-
me.namedSeatsEnabled ? /* @__PURE__ */
|
|
977
|
+
) : /* @__PURE__ */ jsx11("div", { className: "card", children: /* @__PURE__ */ jsx11("div", { className: "card-label", children: copy.full.welcome }) })),
|
|
978
|
+
/* @__PURE__ */ jsx11(GiftPurchases, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment }),
|
|
979
|
+
me.namedSeatsEnabled ? /* @__PURE__ */ jsx11(NamedSeatPurchase, { api }) : null
|
|
769
980
|
] });
|
|
770
981
|
}
|
|
771
982
|
|
|
772
983
|
// src/ui/join.tsx
|
|
773
|
-
import { useEffect as
|
|
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
|
-
}
|
|
984
|
+
import { useEffect as useEffect10, useRef as useRef3, useState as useState16 } from "preact/hooks";
|
|
872
985
|
|
|
873
986
|
// src/ui/join-booking.tsx
|
|
874
|
-
import { useEffect as
|
|
875
|
-
import { jsx as
|
|
987
|
+
import { useEffect as useEffect7, useState as useState10 } from "preact/hooks";
|
|
988
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
|
|
876
989
|
function JoinBooking(props) {
|
|
877
990
|
const { applicationId, copy, onBooked, simulation } = props;
|
|
878
|
-
const [state, setState] =
|
|
879
|
-
const [msg, setMsg] =
|
|
880
|
-
const [busy, setBusy] =
|
|
881
|
-
const [selected, setSelected] =
|
|
991
|
+
const [state, setState] = useState10(null);
|
|
992
|
+
const [msg, setMsg] = useState10(null);
|
|
993
|
+
const [busy, setBusy] = useState10(false);
|
|
994
|
+
const [selected, setSelected] = useState10(null);
|
|
882
995
|
const load = async () => {
|
|
883
996
|
setMsg(null);
|
|
884
997
|
try {
|
|
@@ -903,7 +1016,7 @@ function JoinBooking(props) {
|
|
|
903
1016
|
setMsg(copy.loadFailed);
|
|
904
1017
|
}
|
|
905
1018
|
};
|
|
906
|
-
|
|
1019
|
+
useEffect7(() => {
|
|
907
1020
|
void load();
|
|
908
1021
|
}, [simulation]);
|
|
909
1022
|
const book = async () => {
|
|
@@ -935,9 +1048,11 @@ function JoinBooking(props) {
|
|
|
935
1048
|
setBusy(false);
|
|
936
1049
|
}
|
|
937
1050
|
};
|
|
938
|
-
if (!state) return /* @__PURE__ */
|
|
939
|
-
return /* @__PURE__ */
|
|
940
|
-
/* @__PURE__ */
|
|
1051
|
+
if (!state) return /* @__PURE__ */ jsx12("p", { className: "slots-status", children: msg ?? copy.loading });
|
|
1052
|
+
return /* @__PURE__ */ jsxs12("div", { className: "join-book", children: [
|
|
1053
|
+
/* @__PURE__ */ jsx12("h2", { children: copy.title ?? DEFAULT_JOIN_COPY.booking.title }),
|
|
1054
|
+
/* @__PURE__ */ jsx12("p", { children: copy.intro ?? DEFAULT_JOIN_COPY.booking.intro }),
|
|
1055
|
+
/* @__PURE__ */ jsx12(
|
|
941
1056
|
SlotPicker,
|
|
942
1057
|
{
|
|
943
1058
|
slots: state.slots,
|
|
@@ -947,29 +1062,29 @@ function JoinBooking(props) {
|
|
|
947
1062
|
onDayChange: () => setSelected(null)
|
|
948
1063
|
}
|
|
949
1064
|
),
|
|
950
|
-
/* @__PURE__ */
|
|
951
|
-
/* @__PURE__ */
|
|
952
|
-
msg ? /* @__PURE__ */
|
|
1065
|
+
/* @__PURE__ */ jsxs12("div", { className: "slot-confirm", hidden: !selected, children: [
|
|
1066
|
+
/* @__PURE__ */ jsx12("button", { className: "submit-btn", disabled: busy, onClick: () => void book(), children: busy ? copy.booking : copy.book }),
|
|
1067
|
+
msg ? /* @__PURE__ */ jsx12("p", { className: "step2-note", children: msg }) : null
|
|
953
1068
|
] })
|
|
954
1069
|
] });
|
|
955
1070
|
}
|
|
956
1071
|
|
|
957
1072
|
// src/ui/join-accepted.tsx
|
|
958
|
-
import { jsx as
|
|
1073
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
|
|
959
1074
|
function JoinAccepted(props) {
|
|
960
|
-
return /* @__PURE__ */
|
|
961
|
-
/* @__PURE__ */
|
|
962
|
-
/* @__PURE__ */
|
|
963
|
-
/* @__PURE__ */
|
|
1075
|
+
return /* @__PURE__ */ jsxs13("div", { className: "join-done card", children: [
|
|
1076
|
+
/* @__PURE__ */ jsx13("div", { className: "card-label", children: props.copy.accepted.label }),
|
|
1077
|
+
/* @__PURE__ */ jsx13("p", { className: "meeting-note", children: props.copy.accepted.body }),
|
|
1078
|
+
/* @__PURE__ */ jsx13("a", { className: "apply-link", href: props.membersHref, children: props.copy.done.memberArea })
|
|
964
1079
|
] });
|
|
965
1080
|
}
|
|
966
1081
|
|
|
967
1082
|
// src/ui/gift-claim-card.tsx
|
|
968
|
-
import { useState as
|
|
969
|
-
import { Fragment as Fragment6, jsx as
|
|
1083
|
+
import { useState as useState11 } from "preact/hooks";
|
|
1084
|
+
import { Fragment as Fragment6, jsx as jsx14, jsxs as jsxs14 } from "preact/jsx-runtime";
|
|
970
1085
|
function GiftClaimCard(props) {
|
|
971
|
-
const [code, setCode] =
|
|
972
|
-
const [error, setError] =
|
|
1086
|
+
const [code, setCode] = useState11(props.initialCode ?? "");
|
|
1087
|
+
const [error, setError] = useState11(false);
|
|
973
1088
|
const rotate = async () => {
|
|
974
1089
|
if (!props.claimId) return;
|
|
975
1090
|
setError(false);
|
|
@@ -982,15 +1097,72 @@ function GiftClaimCard(props) {
|
|
|
982
1097
|
if (response.ok && body.code) setCode(body.code);
|
|
983
1098
|
else setError(true);
|
|
984
1099
|
};
|
|
985
|
-
return /* @__PURE__ */
|
|
986
|
-
/* @__PURE__ */
|
|
987
|
-
/* @__PURE__ */
|
|
988
|
-
code ? /* @__PURE__ */
|
|
989
|
-
/* @__PURE__ */
|
|
990
|
-
/* @__PURE__ */
|
|
1100
|
+
return /* @__PURE__ */ jsxs14("div", { className: "join-done card", children: [
|
|
1101
|
+
/* @__PURE__ */ jsx14("div", { className: "card-label", children: props.copy.label }),
|
|
1102
|
+
/* @__PURE__ */ jsx14("p", { className: "meeting-note", children: props.copy.body }),
|
|
1103
|
+
code ? /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
1104
|
+
/* @__PURE__ */ jsx14("output", { className: "gift-code", children: code }),
|
|
1105
|
+
/* @__PURE__ */ jsx14("p", { children: props.copy.save })
|
|
991
1106
|
] }) : null,
|
|
992
|
-
!code && props.claimId ? /* @__PURE__ */
|
|
993
|
-
error ? /* @__PURE__ */
|
|
1107
|
+
!code && props.claimId ? /* @__PURE__ */ jsx14("button", { type: "button", className: "btn secondary", onClick: () => void rotate(), children: props.copy.rotate }) : null,
|
|
1108
|
+
error ? /* @__PURE__ */ jsx14("p", { role: "alert", children: props.copy.rotateFailed }) : null
|
|
1109
|
+
] });
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
// src/ui/join-tiers.tsx
|
|
1113
|
+
import { useState as useState12 } from "preact/hooks";
|
|
1114
|
+
import { jsx as jsx15, jsxs as jsxs15 } from "preact/jsx-runtime";
|
|
1115
|
+
function useTierSelection(tiers, initialTierId) {
|
|
1116
|
+
const [selectedTierId, setSelectedTierId] = useState12(() => {
|
|
1117
|
+
const preset = tiers.find((tier) => tier.id === initialTierId);
|
|
1118
|
+
if (preset) return preset.id;
|
|
1119
|
+
return tiers.length === 1 ? tiers[0].id : null;
|
|
1120
|
+
});
|
|
1121
|
+
return {
|
|
1122
|
+
tiers,
|
|
1123
|
+
selected: tiers.find((tier) => tier.id === selectedTierId) ?? null,
|
|
1124
|
+
selectedTierId,
|
|
1125
|
+
selectTier: (tierId) => {
|
|
1126
|
+
if (tiers.some((tier) => tier.id === tierId)) setSelectedTierId(tierId);
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
function TierPlaceholder(context) {
|
|
1131
|
+
return /* @__PURE__ */ jsxs15("fieldset", { "data-chapter-placeholder": "tiers", children: [
|
|
1132
|
+
/* @__PURE__ */ jsx15("legend", { children: "Membership (placeholder \u2014 pass renderTiers to style this)" }),
|
|
1133
|
+
context.tiers.map((tier) => /* @__PURE__ */ jsxs15("label", { children: [
|
|
1134
|
+
/* @__PURE__ */ jsx15(
|
|
1135
|
+
"input",
|
|
1136
|
+
{
|
|
1137
|
+
type: "radio",
|
|
1138
|
+
name: "__chapterTier",
|
|
1139
|
+
value: tier.id,
|
|
1140
|
+
checked: context.selectedTierId === tier.id,
|
|
1141
|
+
onChange: () => context.selectTier(tier.id)
|
|
1142
|
+
}
|
|
1143
|
+
),
|
|
1144
|
+
tier.name
|
|
1145
|
+
] }, tier.id))
|
|
1146
|
+
] });
|
|
1147
|
+
}
|
|
1148
|
+
function tierNeedsPayment(selected, paymentsReady) {
|
|
1149
|
+
return selected ? !selected.free && paymentsReady : paymentsReady;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
// src/ui/join-application-form.tsx
|
|
1153
|
+
import { jsx as jsx16, jsxs as jsxs16 } from "preact/jsx-runtime";
|
|
1154
|
+
function JoinApplicationForm({ props, copy, invitation, requestedSeat, tierSelection, giftOfferId, selectGift, submitting, error, submit }) {
|
|
1155
|
+
const disabled = submitting || props.submitDisabled === true;
|
|
1156
|
+
return /* @__PURE__ */ jsxs16("form", { className: "join-form", onSubmit: (event) => void submit(event), children: [
|
|
1157
|
+
!requestedSeat && (props.config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs16("fieldset", { children: [
|
|
1158
|
+
/* @__PURE__ */ jsx16("legend", { children: copy.gift.optionsLabel }),
|
|
1159
|
+
/* @__PURE__ */ jsx16("button", { type: "button", className: "btn secondary", "aria-pressed": !giftOfferId, onClick: () => selectGift(null), children: copy.gift.chooseSelf }),
|
|
1160
|
+
/* @__PURE__ */ jsx16(GiftOfferCards, { offers: props.config.giftOffers ?? [], mode: "select", selectedOfferId: giftOfferId, onSelect: selectGift })
|
|
1161
|
+
] }) : null,
|
|
1162
|
+
!requestedSeat && (props.config.tiers?.length ?? 0) > 1 ? props.renderTiers?.(tierSelection) ?? TierPlaceholder(tierSelection) : null,
|
|
1163
|
+
typeof props.children === "function" ? props.children({ invitation }) : props.children,
|
|
1164
|
+
error ? /* @__PURE__ */ jsx16("p", { className: "join-error", role: "alert", children: error }) : null,
|
|
1165
|
+
props.renderSubmit?.({ submitting, disabled }) ?? /* @__PURE__ */ jsx16("button", { className: "submit-btn", type: "submit", disabled, children: submitting ? copy.form.submitting : copy.form.submit })
|
|
994
1166
|
] });
|
|
995
1167
|
}
|
|
996
1168
|
|
|
@@ -1015,8 +1187,8 @@ function joinStateFromApplicationResponse(data, fallbackNeedsPayment, submittedG
|
|
|
1015
1187
|
|
|
1016
1188
|
// src/ui/gift-code-redeemer.tsx
|
|
1017
1189
|
import { InlineActionField } from "@odla-ai/ui/components";
|
|
1018
|
-
import { useState as
|
|
1019
|
-
import { Fragment as Fragment7, jsx as
|
|
1190
|
+
import { useState as useState13 } from "preact/hooks";
|
|
1191
|
+
import { Fragment as Fragment7, jsx as jsx17, jsxs as jsxs17 } from "preact/jsx-runtime";
|
|
1020
1192
|
var GIFT_CODE_REDEEMER_CSS = `
|
|
1021
1193
|
.gift-code-redeemer{container-type:inline-size;display:grid;gap:var(--ui-space-1,.35rem);margin:0}
|
|
1022
1194
|
.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}
|
|
@@ -1031,10 +1203,10 @@ var GIFT_CODE_REDEEMER_CSS = `
|
|
|
1031
1203
|
@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%}}
|
|
1032
1204
|
`;
|
|
1033
1205
|
function GiftCodeRedeemer({ api, applicationId, copy, id, onRedeemed }) {
|
|
1034
|
-
const [code, setCode] =
|
|
1035
|
-
const [loading, setLoading] =
|
|
1036
|
-
const [message, setMessage] =
|
|
1037
|
-
const [messageTone, setMessageTone] =
|
|
1206
|
+
const [code, setCode] = useState13("");
|
|
1207
|
+
const [loading, setLoading] = useState13(false);
|
|
1208
|
+
const [message, setMessage] = useState13("");
|
|
1209
|
+
const [messageTone, setMessageTone] = useState13("neutral");
|
|
1038
1210
|
const normalizedCode = code.trim();
|
|
1039
1211
|
const redeem = async () => {
|
|
1040
1212
|
if (!normalizedCode || loading) return;
|
|
@@ -1061,9 +1233,9 @@ function GiftCodeRedeemer({ api, applicationId, copy, id, onRedeemed }) {
|
|
|
1061
1233
|
setLoading(false);
|
|
1062
1234
|
}
|
|
1063
1235
|
};
|
|
1064
|
-
return /* @__PURE__ */
|
|
1065
|
-
/* @__PURE__ */
|
|
1066
|
-
/* @__PURE__ */
|
|
1236
|
+
return /* @__PURE__ */ jsxs17(Fragment7, { children: [
|
|
1237
|
+
/* @__PURE__ */ jsx17("style", { children: GIFT_CODE_REDEEMER_CSS }),
|
|
1238
|
+
/* @__PURE__ */ jsx17(
|
|
1067
1239
|
InlineActionField,
|
|
1068
1240
|
{
|
|
1069
1241
|
id,
|
|
@@ -1119,12 +1291,12 @@ async function loadJoinResume(applicationId, fetcher = fetch) {
|
|
|
1119
1291
|
}
|
|
1120
1292
|
|
|
1121
1293
|
// src/ui/join-gift-claim.tsx
|
|
1122
|
-
import { jsx as
|
|
1294
|
+
import { jsx as jsx18, jsxs as jsxs18 } from "preact/jsx-runtime";
|
|
1123
1295
|
function JoinGiftClaim(props) {
|
|
1124
|
-
return /* @__PURE__ */
|
|
1125
|
-
/* @__PURE__ */
|
|
1126
|
-
/* @__PURE__ */
|
|
1127
|
-
/* @__PURE__ */
|
|
1296
|
+
return /* @__PURE__ */ jsxs18("section", { className: "join-gift-claim card", children: [
|
|
1297
|
+
/* @__PURE__ */ jsx18("div", { className: "card-label", children: props.copy.claimTitle }),
|
|
1298
|
+
/* @__PURE__ */ jsx18("p", { children: props.copy.claimBody }),
|
|
1299
|
+
/* @__PURE__ */ jsx18(
|
|
1128
1300
|
GiftCodeRedeemer,
|
|
1129
1301
|
{
|
|
1130
1302
|
api: props.api,
|
|
@@ -1148,24 +1320,21 @@ function JoinGiftClaim(props) {
|
|
|
1148
1320
|
}
|
|
1149
1321
|
|
|
1150
1322
|
// src/ui/join-named-seat.tsx
|
|
1151
|
-
import { useState as
|
|
1152
|
-
import { jsx as
|
|
1323
|
+
import { useState as useState14 } from "preact/hooks";
|
|
1324
|
+
import { jsx as jsx19, jsxs as jsxs19 } from "preact/jsx-runtime";
|
|
1153
1325
|
function JoinNamedSeat(props) {
|
|
1154
|
-
const
|
|
1155
|
-
const
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
/* @__PURE__ */
|
|
1159
|
-
/* @__PURE__ */
|
|
1160
|
-
|
|
1161
|
-
/* @__PURE__ */
|
|
1326
|
+
const seatId = props.seatId ?? "";
|
|
1327
|
+
const inherited = useChapterCopy(), copy = props.copy ?? inherited.join.namedSeat;
|
|
1328
|
+
const [accepted, setAccepted] = useState14(false), [busy, setBusy] = useState14(false), [error, setError] = useState14("");
|
|
1329
|
+
return /* @__PURE__ */ jsxs19("section", { className: "join-named-seat card", children: [
|
|
1330
|
+
/* @__PURE__ */ jsx19("h2", { children: copy.title }),
|
|
1331
|
+
/* @__PURE__ */ jsx19("p", { children: copy.body }),
|
|
1332
|
+
/* @__PURE__ */ jsxs19("label", { className: "journey-consent", children: [
|
|
1333
|
+
/* @__PURE__ */ jsx19("input", { type: "checkbox", checked: accepted, disabled: busy, onChange: (event) => setAccepted(event.currentTarget.checked) }),
|
|
1334
|
+
/* @__PURE__ */ jsx19("span", { children: copy.consent })
|
|
1162
1335
|
] }),
|
|
1163
|
-
/* @__PURE__ */
|
|
1164
|
-
|
|
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 () => {
|
|
1336
|
+
error ? /* @__PURE__ */ jsx19("p", { role: "alert", children: error }) : null,
|
|
1337
|
+
/* @__PURE__ */ jsx19("button", { type: "button", className: "btn btn-primary", disabled: busy || !accepted || !seatId.trim(), onClick: async () => {
|
|
1169
1338
|
setBusy(true);
|
|
1170
1339
|
setError("");
|
|
1171
1340
|
try {
|
|
@@ -1175,59 +1344,54 @@ function JoinNamedSeat(props) {
|
|
|
1175
1344
|
});
|
|
1176
1345
|
if (!result.ok || result.applicationId !== props.applicationId || !["booking", "accepted", "paymentPending"].includes(result.state)) throw new Error("acceptance pending");
|
|
1177
1346
|
props.onState({ step: result.state, applicationId: result.applicationId });
|
|
1178
|
-
} catch {
|
|
1179
|
-
setError(
|
|
1347
|
+
} catch (error2) {
|
|
1348
|
+
setError(error2 instanceof Error && error2.message && error2.message !== "acceptance pending" ? error2.message.slice(0, 400) : copy.failure);
|
|
1180
1349
|
} finally {
|
|
1181
1350
|
setBusy(false);
|
|
1182
1351
|
}
|
|
1183
|
-
}, children: busy ?
|
|
1352
|
+
}, children: busy ? copy.accepting : copy.accept })
|
|
1184
1353
|
] });
|
|
1185
1354
|
}
|
|
1186
1355
|
|
|
1187
|
-
// src/ui/join-
|
|
1188
|
-
import { useState as
|
|
1189
|
-
import { jsx as
|
|
1190
|
-
function
|
|
1191
|
-
const [
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1356
|
+
// src/ui/join-invitation.tsx
|
|
1357
|
+
import { useEffect as useEffect8, useState as useState15 } from "preact/hooks";
|
|
1358
|
+
import { jsx as jsx20, jsxs as jsxs20 } from "preact/jsx-runtime";
|
|
1359
|
+
function useJoinInvitation(seatId, api, fallback) {
|
|
1360
|
+
const [invitation, setInvitation] = useState15(null);
|
|
1361
|
+
const [error, setError] = useState15("");
|
|
1362
|
+
const [revision, setRevision] = useState15(0);
|
|
1363
|
+
useEffect8(() => {
|
|
1364
|
+
let live = true;
|
|
1365
|
+
setInvitation(null);
|
|
1366
|
+
setError("");
|
|
1367
|
+
if (!seatId) return;
|
|
1368
|
+
if (!api) {
|
|
1369
|
+
setError(fallback);
|
|
1370
|
+
return;
|
|
1202
1371
|
}
|
|
1203
|
-
|
|
1372
|
+
void api(`/api/named-seat/invitation?seat=${encodeURIComponent(seatId)}`).then((value) => {
|
|
1373
|
+
if (value.seatId !== seatId || !value.skuId || !value.purchaserName) throw new Error(fallback);
|
|
1374
|
+
if (live) setInvitation(value);
|
|
1375
|
+
}).catch((error2) => {
|
|
1376
|
+
if (live) setError(error2 instanceof Error ? error2.message.slice(0, 400) : fallback);
|
|
1377
|
+
});
|
|
1378
|
+
return () => {
|
|
1379
|
+
live = false;
|
|
1380
|
+
};
|
|
1381
|
+
}, [seatId, api, revision]);
|
|
1382
|
+
return { invitation: invitation?.seatId === seatId ? invitation : null, error, retry: () => setRevision((value) => value + 1) };
|
|
1204
1383
|
}
|
|
1205
|
-
function
|
|
1206
|
-
return /* @__PURE__ */
|
|
1207
|
-
/* @__PURE__ */
|
|
1208
|
-
|
|
1209
|
-
/* @__PURE__ */ jsx16(
|
|
1210
|
-
"input",
|
|
1211
|
-
{
|
|
1212
|
-
type: "radio",
|
|
1213
|
-
name: "__chapterTier",
|
|
1214
|
-
value: tier.id,
|
|
1215
|
-
checked: context.selectedTierId === tier.id,
|
|
1216
|
-
onChange: () => context.selectTier(tier.id)
|
|
1217
|
-
}
|
|
1218
|
-
),
|
|
1219
|
-
tier.name
|
|
1220
|
-
] }, tier.id))
|
|
1384
|
+
function JoinInvitationNotice(props) {
|
|
1385
|
+
return /* @__PURE__ */ jsxs20("aside", { className: "journey-invitation", "aria-label": props.copy.title, children: [
|
|
1386
|
+
/* @__PURE__ */ jsx20("p", { children: /* @__PURE__ */ jsx20("strong", { children: formatChapterCopy(props.copy.from, { purchaserName: props.invitation.purchaserName }) }) }),
|
|
1387
|
+
/* @__PURE__ */ jsx20("p", { children: formatChapterCopy(props.copy.prepaid, { tierName: props.tierName }) })
|
|
1221
1388
|
] });
|
|
1222
1389
|
}
|
|
1223
|
-
function tierNeedsPayment(selected, paymentsReady) {
|
|
1224
|
-
return selected ? !selected.free && paymentsReady : paymentsReady;
|
|
1225
|
-
}
|
|
1226
1390
|
|
|
1227
1391
|
// src/ui/join-pending.ts
|
|
1228
|
-
import { useEffect as
|
|
1392
|
+
import { useEffect as useEffect9 } from "preact/hooks";
|
|
1229
1393
|
function useJoinPending(state, loadResume, setState) {
|
|
1230
|
-
|
|
1394
|
+
useEffect9(() => {
|
|
1231
1395
|
if (state.step !== "paymentPending") return;
|
|
1232
1396
|
let live = true;
|
|
1233
1397
|
let timer;
|
|
@@ -1250,27 +1414,33 @@ function useJoinPending(state, loadResume, setState) {
|
|
|
1250
1414
|
}
|
|
1251
1415
|
|
|
1252
1416
|
// src/ui/join.tsx
|
|
1253
|
-
import { Fragment as Fragment8, jsx as
|
|
1417
|
+
import { Fragment as Fragment8, jsx as jsx21, jsxs as jsxs21 } from "preact/jsx-runtime";
|
|
1254
1418
|
function JoinIsland(props) {
|
|
1419
|
+
return /* @__PURE__ */ jsx21(JourneyFrame, { children: /* @__PURE__ */ jsx21(JoinFlow, { ...props }) });
|
|
1420
|
+
}
|
|
1421
|
+
function JoinFlow(props) {
|
|
1255
1422
|
const inheritedCopy = useChapterCopy();
|
|
1256
1423
|
const {
|
|
1257
1424
|
config,
|
|
1258
|
-
children,
|
|
1259
1425
|
membersHref = "/members/",
|
|
1260
1426
|
renderStepHeader,
|
|
1261
1427
|
renderDone,
|
|
1262
1428
|
renderAccepted,
|
|
1263
|
-
renderGift
|
|
1264
|
-
renderSubmit
|
|
1429
|
+
renderGift
|
|
1265
1430
|
} = props;
|
|
1266
1431
|
const copy = props.copy ?? config.copy ?? inheritedCopy.join;
|
|
1432
|
+
const seatCopy = copy.namedSeat ?? inheritedCopy.join.namedSeat;
|
|
1267
1433
|
const tiers = config.tiers ?? [];
|
|
1268
1434
|
const tierSelection = useTierSelection(tiers, props.initialTierId);
|
|
1269
|
-
const
|
|
1270
|
-
const
|
|
1271
|
-
const
|
|
1272
|
-
const
|
|
1273
|
-
const
|
|
1435
|
+
const requestedSeat = props.simulation ? void 0 : props.initialNamedSeatId;
|
|
1436
|
+
const invitationState = useJoinInvitation(requestedSeat, props.namedSeatClaimApi, seatCopy.unavailable);
|
|
1437
|
+
const invitation = invitationState.invitation;
|
|
1438
|
+
const selectedTierId = invitation?.skuId ?? tierSelection.selectedTierId;
|
|
1439
|
+
const selectedTier = tiers.find((tier) => tier.id === selectedTierId) ?? tierSelection.selected;
|
|
1440
|
+
const [state, setState] = useState16(requestedSeat ? { step: "form" } : props.initialState ?? { step: "form" });
|
|
1441
|
+
const [error, setError] = useState16(null);
|
|
1442
|
+
const [submitting, setSubmitting] = useState16(false);
|
|
1443
|
+
const [giftOfferId, setGiftOfferId] = useState16(props.initialGiftOfferId ?? null);
|
|
1274
1444
|
const simulatedPayment = props.simulation ? props.simulation.payment ?? {
|
|
1275
1445
|
lineItems: {
|
|
1276
1446
|
standardCents: selectedTier?.priceCents ?? 0,
|
|
@@ -1280,9 +1450,9 @@ function JoinIsland(props) {
|
|
|
1280
1450
|
} : void 0;
|
|
1281
1451
|
const simulatedBooking = props.simulation ? props.simulation.booking ?? { slots: [], timezone: "UTC" } : void 0;
|
|
1282
1452
|
const submissionId = useRef3(null);
|
|
1283
|
-
|
|
1453
|
+
useEffect10(() => {
|
|
1284
1454
|
if (props.simulation) return;
|
|
1285
|
-
const resolver = props.loadResume ?? (() => {
|
|
1455
|
+
const resolver = requestedSeat ? () => invitation?.applicationId ? loadJoinResume(invitation.applicationId) : Promise.resolve(null) : props.loadResume ?? (() => {
|
|
1286
1456
|
if (typeof window === "undefined") return Promise.resolve(null);
|
|
1287
1457
|
const applicationId = new URL(window.location.href).searchParams.get("application");
|
|
1288
1458
|
return applicationId ? loadJoinResume(applicationId) : Promise.resolve(null);
|
|
@@ -1296,17 +1466,21 @@ function JoinIsland(props) {
|
|
|
1296
1466
|
return () => {
|
|
1297
1467
|
live = false;
|
|
1298
1468
|
};
|
|
1299
|
-
}, [props.loadResume, props.simulation]);
|
|
1300
|
-
useJoinPending(state, props.loadResume, setState);
|
|
1469
|
+
}, [props.loadResume, props.simulation, requestedSeat, invitation?.applicationId]);
|
|
1470
|
+
useJoinPending(state, requestedSeat ? void 0 : props.loadResume, setState);
|
|
1301
1471
|
const submit = async (e) => {
|
|
1302
1472
|
e.preventDefault();
|
|
1303
|
-
if (submitting || props.submitDisabled === true) return;
|
|
1473
|
+
if (submitting || props.submitDisabled === true || requestedSeat && !invitation) return;
|
|
1304
1474
|
setSubmitting(true);
|
|
1305
1475
|
setError(null);
|
|
1306
1476
|
try {
|
|
1307
1477
|
const fields = collectFormFields(new FormData(e.currentTarget));
|
|
1308
1478
|
fields.submissionId = submissionId.current ??= crypto.randomUUID();
|
|
1309
|
-
if (
|
|
1479
|
+
if (invitation) {
|
|
1480
|
+
fields.namedSeatId = invitation.seatId;
|
|
1481
|
+
fields.tierId = invitation.skuId;
|
|
1482
|
+
fields.email = invitation.recipientEmail;
|
|
1483
|
+
} else if (giftOfferId) fields.giftOfferId = giftOfferId;
|
|
1310
1484
|
else if (selectedTierId) fields.tierId = selectedTierId;
|
|
1311
1485
|
if (props.simulation) {
|
|
1312
1486
|
setState({
|
|
@@ -1317,6 +1491,16 @@ function JoinIsland(props) {
|
|
|
1317
1491
|
});
|
|
1318
1492
|
return;
|
|
1319
1493
|
}
|
|
1494
|
+
if (invitation && props.namedSeatClaimApi) {
|
|
1495
|
+
const result = await props.namedSeatClaimApi("/api/applications", {
|
|
1496
|
+
method: "POST",
|
|
1497
|
+
headers: { "content-type": "application/json" },
|
|
1498
|
+
body: JSON.stringify(fields)
|
|
1499
|
+
});
|
|
1500
|
+
if (!result.id) throw new Error(copy.form.submitFailed);
|
|
1501
|
+
setState(joinStateFromApplicationResponse(result, true, false));
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1320
1504
|
const res = await fetch("/api/applications", {
|
|
1321
1505
|
method: "POST",
|
|
1322
1506
|
headers: { "content-type": "application/json" },
|
|
@@ -1335,50 +1519,66 @@ function JoinIsland(props) {
|
|
|
1335
1519
|
setSubmitting(false);
|
|
1336
1520
|
}
|
|
1337
1521
|
};
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1522
|
+
if (requestedSeat && !invitation) return /* @__PURE__ */ jsxs21("section", { className: "card", "aria-live": "polite", children: [
|
|
1523
|
+
/* @__PURE__ */ jsx21("h2", { children: seatCopy.title }),
|
|
1524
|
+
/* @__PURE__ */ jsx21("p", { role: invitationState.error ? "alert" : "status", children: invitationState.error || seatCopy.loading }),
|
|
1525
|
+
invitationState.error ? /* @__PURE__ */ jsx21("button", { type: "button", onClick: invitationState.retry, children: seatCopy.retry }) : null
|
|
1526
|
+
] });
|
|
1527
|
+
const header = /* @__PURE__ */ jsxs21(Fragment8, { children: [
|
|
1528
|
+
invitation ? /* @__PURE__ */ jsx21(
|
|
1529
|
+
JoinInvitationNotice,
|
|
1530
|
+
{
|
|
1531
|
+
invitation,
|
|
1532
|
+
copy: seatCopy,
|
|
1533
|
+
tierName: selectedTier?.name ?? ""
|
|
1534
|
+
}
|
|
1535
|
+
) : null,
|
|
1536
|
+
renderStepHeader?.({
|
|
1537
|
+
state,
|
|
1538
|
+
...invitation ? { invitation } : {},
|
|
1539
|
+
..."applicationId" in state ? { applicationId: state.applicationId } : {}
|
|
1540
|
+
})
|
|
1541
|
+
] });
|
|
1342
1542
|
if (state.step === "closed") {
|
|
1343
|
-
return /* @__PURE__ */
|
|
1543
|
+
return /* @__PURE__ */ jsxs21(Fragment8, { children: [
|
|
1344
1544
|
header,
|
|
1345
|
-
/* @__PURE__ */
|
|
1346
|
-
/* @__PURE__ */
|
|
1347
|
-
/* @__PURE__ */
|
|
1348
|
-
/* @__PURE__ */
|
|
1545
|
+
/* @__PURE__ */ jsxs21("section", { className: "card", "aria-label": "Application closed", children: [
|
|
1546
|
+
/* @__PURE__ */ jsx21("h2", { children: "This application is closed" }),
|
|
1547
|
+
/* @__PURE__ */ jsx21("p", { children: "This link cannot resume payment or booking. Sign in to view your application status, or contact the chapter if you need help." }),
|
|
1548
|
+
/* @__PURE__ */ jsx21("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
|
|
1349
1549
|
] })
|
|
1350
1550
|
] });
|
|
1351
1551
|
}
|
|
1352
1552
|
if (state.step === "done") {
|
|
1353
|
-
const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */
|
|
1354
|
-
/* @__PURE__ */
|
|
1355
|
-
/* @__PURE__ */
|
|
1356
|
-
/* @__PURE__ */
|
|
1357
|
-
/* @__PURE__ */
|
|
1553
|
+
const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsxs21("div", { className: "join-done card", children: [
|
|
1554
|
+
/* @__PURE__ */ jsx21("div", { className: "card-label", children: copy.done.label }),
|
|
1555
|
+
/* @__PURE__ */ jsx21("p", { className: "meeting-date", children: fullLabel(state.booked.startAt, state.booked.timezone) }),
|
|
1556
|
+
/* @__PURE__ */ jsx21("p", { className: "meeting-note", children: copy.done.calendarInvite }),
|
|
1557
|
+
/* @__PURE__ */ jsx21("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
|
|
1358
1558
|
] });
|
|
1359
|
-
return /* @__PURE__ */
|
|
1559
|
+
return /* @__PURE__ */ jsxs21(Fragment8, { children: [
|
|
1360
1560
|
header,
|
|
1361
1561
|
body
|
|
1362
1562
|
] });
|
|
1363
1563
|
}
|
|
1364
1564
|
if (state.step === "accepted") {
|
|
1365
|
-
const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */
|
|
1366
|
-
return /* @__PURE__ */
|
|
1565
|
+
const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsx21(JoinAccepted, { copy, membersHref });
|
|
1566
|
+
return /* @__PURE__ */ jsxs21(Fragment8, { children: [
|
|
1367
1567
|
header,
|
|
1368
1568
|
body
|
|
1369
1569
|
] });
|
|
1370
1570
|
}
|
|
1371
1571
|
if (state.step === "gift") {
|
|
1372
|
-
const body = renderGift?.(state) ?? /* @__PURE__ */
|
|
1373
|
-
return /* @__PURE__ */
|
|
1572
|
+
const body = renderGift?.(state) ?? /* @__PURE__ */ jsx21(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
|
|
1573
|
+
return /* @__PURE__ */ jsxs21(Fragment8, { children: [
|
|
1374
1574
|
header,
|
|
1375
1575
|
body
|
|
1376
1576
|
] });
|
|
1377
1577
|
}
|
|
1378
1578
|
if (state.step === "booking") {
|
|
1379
|
-
return /* @__PURE__ */
|
|
1579
|
+
return /* @__PURE__ */ jsxs21(Fragment8, { children: [
|
|
1380
1580
|
header,
|
|
1381
|
-
/* @__PURE__ */
|
|
1581
|
+
/* @__PURE__ */ jsx21(
|
|
1382
1582
|
JoinBooking,
|
|
1383
1583
|
{
|
|
1384
1584
|
applicationId: state.applicationId,
|
|
@@ -1393,23 +1593,24 @@ function JoinIsland(props) {
|
|
|
1393
1593
|
}
|
|
1394
1594
|
if (state.step === "payment") {
|
|
1395
1595
|
if (props.namedSeatClaimApi && props.initialNamedSeatId && !props.simulation && !state.giftPurchase) {
|
|
1396
|
-
return /* @__PURE__ */
|
|
1596
|
+
return /* @__PURE__ */ jsxs21(Fragment8, { children: [
|
|
1397
1597
|
header,
|
|
1398
|
-
/* @__PURE__ */
|
|
1598
|
+
/* @__PURE__ */ jsx21(
|
|
1399
1599
|
JoinNamedSeat,
|
|
1400
1600
|
{
|
|
1401
1601
|
api: props.namedSeatClaimApi,
|
|
1402
1602
|
applicationId: state.applicationId,
|
|
1403
1603
|
seatId: props.initialNamedSeatId,
|
|
1604
|
+
copy: seatCopy,
|
|
1404
1605
|
onState: setState
|
|
1405
1606
|
}
|
|
1406
1607
|
)
|
|
1407
1608
|
] });
|
|
1408
1609
|
}
|
|
1409
1610
|
const Payment = state.giftPurchase || props.simulation ? PaymentStep : MembershipPaymentStep;
|
|
1410
|
-
return /* @__PURE__ */
|
|
1611
|
+
return /* @__PURE__ */ jsxs21(Fragment8, { children: [
|
|
1411
1612
|
header,
|
|
1412
|
-
props.giftClaimApi && !state.giftPurchase ? /* @__PURE__ */
|
|
1613
|
+
props.giftClaimApi && !state.giftPurchase ? /* @__PURE__ */ jsx21(
|
|
1413
1614
|
JoinGiftClaim,
|
|
1414
1615
|
{
|
|
1415
1616
|
api: props.giftClaimApi,
|
|
@@ -1420,7 +1621,7 @@ function JoinIsland(props) {
|
|
|
1420
1621
|
onError: () => setError(copy.form.unexpectedFailure)
|
|
1421
1622
|
}
|
|
1422
1623
|
) : null,
|
|
1423
|
-
/* @__PURE__ */
|
|
1624
|
+
/* @__PURE__ */ jsx21(
|
|
1424
1625
|
Payment,
|
|
1425
1626
|
{
|
|
1426
1627
|
applicationId: state.applicationId,
|
|
@@ -1449,39 +1650,42 @@ function JoinIsland(props) {
|
|
|
1449
1650
|
}
|
|
1450
1651
|
if (state.step === "paymentPending") {
|
|
1451
1652
|
if (props.namedSeatClaimApi && props.initialNamedSeatId && !props.simulation) {
|
|
1452
|
-
return /* @__PURE__ */
|
|
1653
|
+
return /* @__PURE__ */ jsxs21(Fragment8, { children: [
|
|
1453
1654
|
header,
|
|
1454
|
-
/* @__PURE__ */
|
|
1655
|
+
/* @__PURE__ */ jsx21(
|
|
1455
1656
|
JoinNamedSeat,
|
|
1456
1657
|
{
|
|
1457
1658
|
api: props.namedSeatClaimApi,
|
|
1458
1659
|
applicationId: state.applicationId,
|
|
1459
1660
|
seatId: props.initialNamedSeatId,
|
|
1661
|
+
copy: seatCopy,
|
|
1460
1662
|
onState: setState
|
|
1461
1663
|
}
|
|
1462
1664
|
)
|
|
1463
1665
|
] });
|
|
1464
1666
|
}
|
|
1465
|
-
return /* @__PURE__ */
|
|
1667
|
+
return /* @__PURE__ */ jsxs21(Fragment8, { children: [
|
|
1466
1668
|
header,
|
|
1467
|
-
/* @__PURE__ */
|
|
1669
|
+
/* @__PURE__ */ jsx21("p", { className: "pay-status", role: "status", children: copy.payment.pending })
|
|
1468
1670
|
] });
|
|
1469
1671
|
}
|
|
1470
|
-
|
|
1471
|
-
const tierChooser = tiers.length > 1 ? props.renderTiers?.(tierSelection) ?? TierPlaceholder(tierSelection) : null;
|
|
1472
|
-
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1672
|
+
return /* @__PURE__ */ jsxs21(Fragment8, { children: [
|
|
1473
1673
|
header,
|
|
1474
|
-
/* @__PURE__ */
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1674
|
+
/* @__PURE__ */ jsx21(
|
|
1675
|
+
JoinApplicationForm,
|
|
1676
|
+
{
|
|
1677
|
+
props,
|
|
1678
|
+
copy,
|
|
1679
|
+
invitation,
|
|
1680
|
+
requestedSeat,
|
|
1681
|
+
tierSelection,
|
|
1682
|
+
giftOfferId,
|
|
1683
|
+
selectGift: setGiftOfferId,
|
|
1684
|
+
submitting,
|
|
1685
|
+
error,
|
|
1686
|
+
submit
|
|
1687
|
+
}
|
|
1688
|
+
)
|
|
1485
1689
|
] });
|
|
1486
1690
|
}
|
|
1487
1691
|
|
|
@@ -1657,7 +1861,7 @@ function membershipPageDocument(input, options = {}) {
|
|
|
1657
1861
|
}
|
|
1658
1862
|
|
|
1659
1863
|
// src/ui/membership-cards.tsx
|
|
1660
|
-
import { jsx as
|
|
1864
|
+
import { jsx as jsx22, jsxs as jsxs22 } from "preact/jsx-runtime";
|
|
1661
1865
|
var MEMBERSHIP_CARD_TOKEN_DEFAULTS = Object.freeze({
|
|
1662
1866
|
"--ui-membership-grid-gap": "1.4rem",
|
|
1663
1867
|
"--ui-membership-card-padding": "2rem 1.7rem 1.8rem",
|
|
@@ -1726,67 +1930,67 @@ function membershipApplicationHref(applicationPath, tierId) {
|
|
|
1726
1930
|
}
|
|
1727
1931
|
function TierAction(props) {
|
|
1728
1932
|
if (props.mode === "select") {
|
|
1729
|
-
return /* @__PURE__ */
|
|
1933
|
+
return /* @__PURE__ */ jsxs22("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
|
|
1730
1934
|
props.label,
|
|
1731
|
-
/* @__PURE__ */
|
|
1935
|
+
/* @__PURE__ */ jsx22("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1732
1936
|
] });
|
|
1733
1937
|
}
|
|
1734
1938
|
if (props.mode === "preview") {
|
|
1735
|
-
return /* @__PURE__ */
|
|
1939
|
+
return /* @__PURE__ */ jsxs22("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
|
|
1736
1940
|
props.label,
|
|
1737
|
-
/* @__PURE__ */
|
|
1941
|
+
/* @__PURE__ */ jsx22("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1738
1942
|
] });
|
|
1739
1943
|
}
|
|
1740
|
-
return /* @__PURE__ */
|
|
1944
|
+
return /* @__PURE__ */ jsxs22("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
|
|
1741
1945
|
props.label,
|
|
1742
|
-
/* @__PURE__ */
|
|
1946
|
+
/* @__PURE__ */ jsx22("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1743
1947
|
] });
|
|
1744
1948
|
}
|
|
1745
1949
|
function TierCard(props) {
|
|
1746
1950
|
const { tier, presentation } = props;
|
|
1747
1951
|
const summary = presentation.summaryMarkdown ?? tier.blurb;
|
|
1748
1952
|
const action = presentation.ctaLabel ?? (tier.free ? "Join for free" : `Choose ${tier.name}`);
|
|
1749
|
-
return /* @__PURE__ */
|
|
1750
|
-
presentation.badge ? /* @__PURE__ */
|
|
1751
|
-
/* @__PURE__ */
|
|
1752
|
-
/* @__PURE__ */
|
|
1753
|
-
presentation.capacity ? /* @__PURE__ */
|
|
1754
|
-
/* @__PURE__ */
|
|
1755
|
-
/* @__PURE__ */
|
|
1953
|
+
return /* @__PURE__ */ jsxs22("article", { className: "chapter-membership-card", "data-tier-id": tier.id, "data-variant": presentation.variant ?? "standard", children: [
|
|
1954
|
+
presentation.badge ? /* @__PURE__ */ jsx22("div", { className: "chapter-membership-badge", children: presentation.badge }) : null,
|
|
1955
|
+
/* @__PURE__ */ jsx22("h3", { className: "chapter-membership-name", children: tier.name }),
|
|
1956
|
+
/* @__PURE__ */ jsxs22("div", { className: "chapter-membership-offer", "data-with-capacity": presentation.capacity ? "true" : void 0, children: [
|
|
1957
|
+
presentation.capacity ? /* @__PURE__ */ jsxs22("div", { className: "chapter-membership-capacity", "aria-label": `${presentation.capacity.total} ${presentation.capacity.label ?? "available"}`, children: [
|
|
1958
|
+
/* @__PURE__ */ jsx22("strong", { children: presentation.capacity.total.toLocaleString("en-US") }),
|
|
1959
|
+
/* @__PURE__ */ jsx22("small", { children: presentation.capacity.label ?? "available" })
|
|
1756
1960
|
] }) : null,
|
|
1757
|
-
/* @__PURE__ */
|
|
1758
|
-
presentation.priceEyebrow ? /* @__PURE__ */
|
|
1759
|
-
/* @__PURE__ */
|
|
1760
|
-
presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */
|
|
1761
|
-
/* @__PURE__ */
|
|
1762
|
-
!tier.free && presentation.billingLabel ? /* @__PURE__ */
|
|
1961
|
+
/* @__PURE__ */ jsxs22("div", { className: "chapter-membership-price-stack", children: [
|
|
1962
|
+
presentation.priceEyebrow ? /* @__PURE__ */ jsx22("p", { className: "chapter-membership-price-eyebrow", children: presentation.priceEyebrow }) : null,
|
|
1963
|
+
/* @__PURE__ */ jsxs22("div", { className: "chapter-membership-price-row", children: [
|
|
1964
|
+
presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */ jsx22("span", { className: "chapter-membership-compare", children: fmtMoney(presentation.compareAtPriceCents) }) : null,
|
|
1965
|
+
/* @__PURE__ */ jsx22("span", { className: "chapter-membership-price", children: tier.free ? "Free" : fmtMoney(tier.priceCents) }),
|
|
1966
|
+
!tier.free && presentation.billingLabel ? /* @__PURE__ */ jsx22("span", { className: "chapter-membership-billing", children: presentation.billingLabel }) : null
|
|
1763
1967
|
] })
|
|
1764
1968
|
] })
|
|
1765
1969
|
] }),
|
|
1766
|
-
presentation.priceNoteMarkdown ? /* @__PURE__ */
|
|
1767
|
-
summary ? /* @__PURE__ */
|
|
1768
|
-
presentation.benefits?.length ? /* @__PURE__ */
|
|
1769
|
-
/* @__PURE__ */
|
|
1770
|
-
/* @__PURE__ */
|
|
1970
|
+
presentation.priceNoteMarkdown ? /* @__PURE__ */ jsx22(Markdown2, { className: "chapter-membership-price-note", source: presentation.priceNoteMarkdown }) : null,
|
|
1971
|
+
summary ? /* @__PURE__ */ jsx22(Markdown2, { className: "chapter-membership-summary", source: summary }) : null,
|
|
1972
|
+
presentation.benefits?.length ? /* @__PURE__ */ jsx22("ul", { className: "chapter-membership-benefits", children: presentation.benefits.map((benefit, index) => /* @__PURE__ */ jsxs22("li", { children: [
|
|
1973
|
+
/* @__PURE__ */ jsx22("span", { className: "chapter-membership-check", "aria-hidden": "true", children: "\u2713" }),
|
|
1974
|
+
/* @__PURE__ */ jsx22(Markdown2, { className: "chapter-membership-benefit", source: benefit })
|
|
1771
1975
|
] }, `${tier.id}-benefit-${index}`)) }) : null,
|
|
1772
|
-
presentation.callout ? /* @__PURE__ */
|
|
1773
|
-
presentation.callout.label ? /* @__PURE__ */
|
|
1774
|
-
/* @__PURE__ */
|
|
1976
|
+
presentation.callout ? /* @__PURE__ */ jsxs22("aside", { className: "chapter-membership-callout", children: [
|
|
1977
|
+
presentation.callout.label ? /* @__PURE__ */ jsx22("p", { className: "chapter-membership-callout-label", children: presentation.callout.label }) : null,
|
|
1978
|
+
/* @__PURE__ */ jsx22(Markdown2, { source: presentation.callout.bodyMarkdown })
|
|
1775
1979
|
] }) : null,
|
|
1776
|
-
/* @__PURE__ */
|
|
1980
|
+
/* @__PURE__ */ jsx22(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
|
|
1777
1981
|
] });
|
|
1778
1982
|
}
|
|
1779
1983
|
function MembershipCards(props) {
|
|
1780
1984
|
const document2 = membershipPageDocument(props.document, { tiers: props.tiers });
|
|
1781
1985
|
const byId = new Map(props.tiers.map((tier) => [tier.id, tier]));
|
|
1782
1986
|
const mode = props.mode ?? "link";
|
|
1783
|
-
return /* @__PURE__ */
|
|
1784
|
-
/* @__PURE__ */
|
|
1785
|
-
/* @__PURE__ */
|
|
1987
|
+
return /* @__PURE__ */ jsxs22("section", { className: ["chapter-membership", props.className].filter(Boolean).join(" "), "data-chapter-membership": MEMBERSHIP_PAGE_RENDERER, "aria-label": props.ariaLabel ?? "Membership options", children: [
|
|
1988
|
+
/* @__PURE__ */ jsx22("style", { children: MEMBERSHIP_CARDS_CSS }),
|
|
1989
|
+
/* @__PURE__ */ jsx22("div", { className: "chapter-membership-grid", style: { "--chapter-membership-columns": String(Math.min(document2.tiers.length, 3)) }, children: document2.tiers.map((presentation) => {
|
|
1786
1990
|
const tier = byId.get(presentation.tierId);
|
|
1787
|
-
return /* @__PURE__ */
|
|
1991
|
+
return /* @__PURE__ */ jsx22(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
|
|
1788
1992
|
}) }),
|
|
1789
|
-
document2.footnoteMarkdown ? /* @__PURE__ */
|
|
1993
|
+
document2.footnoteMarkdown ? /* @__PURE__ */ jsx22(Markdown2, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
|
|
1790
1994
|
] });
|
|
1791
1995
|
}
|
|
1792
1996
|
|
|
@@ -1800,21 +2004,23 @@ export {
|
|
|
1800
2004
|
fmtDate,
|
|
1801
2005
|
groupSlotsByDay,
|
|
1802
2006
|
SlotPicker,
|
|
2007
|
+
PaymentStep,
|
|
2008
|
+
JourneyFrame,
|
|
2009
|
+
MemberRestart,
|
|
1803
2010
|
Rescheduler,
|
|
1804
2011
|
GiftOfferCards,
|
|
1805
|
-
PaymentStep,
|
|
1806
2012
|
GiftPurchases,
|
|
1807
2013
|
MemberGifts,
|
|
1808
2014
|
MemberContentArea,
|
|
1809
2015
|
MembersArea,
|
|
1810
|
-
GiftCodeRedeemer,
|
|
1811
|
-
loadJoinResume,
|
|
1812
2016
|
useTierSelection,
|
|
1813
2017
|
TierPlaceholder,
|
|
1814
2018
|
tierNeedsPayment,
|
|
2019
|
+
GiftCodeRedeemer,
|
|
2020
|
+
loadJoinResume,
|
|
1815
2021
|
JoinIsland,
|
|
1816
2022
|
MEMBERSHIP_CARD_TOKEN_DEFAULTS,
|
|
1817
2023
|
membershipApplicationHref,
|
|
1818
2024
|
MembershipCards
|
|
1819
2025
|
};
|
|
1820
|
-
//# sourceMappingURL=chunk-
|
|
2026
|
+
//# sourceMappingURL=chunk-KHDO2QFA.js.map
|