@odla-ai/chapter 0.35.0 → 0.36.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-UJIVBGL5.js → chunk-I45VYBUV.js} +441 -239
- package/dist/chunk-I45VYBUV.js.map +1 -0
- package/dist/{chunk-JAWTIROV.js → chunk-IAWBE5PX.js} +55 -1
- package/dist/chunk-IAWBE5PX.js.map +1 -0
- package/dist/{chunk-TXE5ZDI4.js → chunk-LWM32REV.js} +166 -59
- package/dist/chunk-LWM32REV.js.map +1 -0
- package/dist/{copy-context-c1tqPXOR.d.ts → copy-context-0k0-yWHL.d.ts} +6 -2
- package/dist/index.cjs +843 -293
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +200 -3
- package/dist/index.d.ts +200 -3
- package/dist/index.js +843 -293
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +10 -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 +86 -7
- package/dist/ui/member/index.js +6 -2
- package/dist/worker/index.cjs +1806 -710
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +102 -3
- package/dist/worker/index.d.ts +102 -3
- package/dist/worker/index.js +1824 -728
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-JAWTIROV.js.map +0 -1
- package/dist/chunk-TXE5ZDI4.js.map +0 -1
- package/dist/chunk-UJIVBGL5.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
formatChapterCopy,
|
|
3
3
|
useChapterCopy
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IAWBE5PX.js";
|
|
5
5
|
import {
|
|
6
6
|
collectFormFields
|
|
7
7
|
} from "./chunk-IVXVECKR.js";
|
|
@@ -105,7 +105,7 @@ function SlotPicker(props) {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
// src/ui/members.tsx
|
|
108
|
-
import { useEffect, useState as
|
|
108
|
+
import { useEffect as useEffect2, useState as useState5 } from "preact/hooks";
|
|
109
109
|
|
|
110
110
|
// src/ui/reschedule.tsx
|
|
111
111
|
import { useState as useState2 } from "preact/hooks";
|
|
@@ -189,143 +189,27 @@ function Rescheduler(props) {
|
|
|
189
189
|
] });
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
// src/ui/
|
|
193
|
-
import {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
return card(
|
|
207
|
-
copy,
|
|
208
|
-
copy.provisional.applicationNeeded,
|
|
209
|
-
/* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
210
|
-
/* @__PURE__ */ jsx3("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
|
|
211
|
-
/* @__PURE__ */ jsx3("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
|
|
212
|
-
] })
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
if (application.status === "refunded") {
|
|
216
|
-
return card(
|
|
217
|
-
copy,
|
|
218
|
-
copy.provisional.refunded,
|
|
219
|
-
/* @__PURE__ */ jsx3("div", { className: "meeting-note", children: copy.provisional.refundedBody })
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
const membership = application.paid ? /* @__PURE__ */ jsx3("div", { className: "meeting-note", children: application.renewalAt ? formatChapterCopy(copy.provisional.renews, { date: fmtDate(application.renewalAt) }) : copy.provisional.active }) : null;
|
|
223
|
-
if (application.meetingAt) {
|
|
224
|
-
return card(
|
|
225
|
-
copy,
|
|
226
|
-
copy.provisional.introductionCall,
|
|
227
|
-
/* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
228
|
-
/* @__PURE__ */ jsx3("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
|
|
229
|
-
/* @__PURE__ */ jsx3("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
|
|
230
|
-
application.meetUrl ? /* @__PURE__ */ jsx3("div", { className: "meeting-note", children: /* @__PURE__ */ jsx3("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
|
|
231
|
-
/* @__PURE__ */ jsx3(
|
|
232
|
-
Rescheduler,
|
|
233
|
-
{
|
|
234
|
-
api,
|
|
235
|
-
applicationId: application.id,
|
|
236
|
-
timezone: application.timezone,
|
|
237
|
-
copy: copy.reschedule,
|
|
238
|
-
onRescheduled: onReschedule
|
|
239
|
-
}
|
|
240
|
-
),
|
|
241
|
-
membership
|
|
242
|
-
] })
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
return card(
|
|
246
|
-
copy,
|
|
247
|
-
copy.provisional.bookCall,
|
|
248
|
-
/* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
249
|
-
/* @__PURE__ */ jsx3("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
|
|
250
|
-
/* @__PURE__ */ jsx3(
|
|
251
|
-
Rescheduler,
|
|
252
|
-
{
|
|
253
|
-
api,
|
|
254
|
-
applicationId: application.id,
|
|
255
|
-
timezone: application.timezone,
|
|
256
|
-
copy: copy.reschedule,
|
|
257
|
-
onRescheduled: onReschedule,
|
|
258
|
-
label: copy.provisional.chooseTime
|
|
259
|
-
}
|
|
260
|
-
),
|
|
261
|
-
membership
|
|
262
|
-
] })
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
function MembersArea(props) {
|
|
266
|
-
const inheritedCopy = useChapterCopy();
|
|
267
|
-
const {
|
|
268
|
-
api,
|
|
269
|
-
signOut,
|
|
270
|
-
adminHref = "/admin/",
|
|
271
|
-
applyHref = "/join.html",
|
|
272
|
-
memberContent,
|
|
273
|
-
renderProvisional
|
|
274
|
-
} = props;
|
|
275
|
-
const copy = props.copy ?? inheritedCopy.members;
|
|
276
|
-
const [me, setMe] = useState3(null);
|
|
277
|
-
const [error, setError] = useState3(false);
|
|
278
|
-
const reload = async () => {
|
|
279
|
-
try {
|
|
280
|
-
setMe(await api("/api/me"));
|
|
281
|
-
} catch {
|
|
282
|
-
setError(true);
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
useEffect(() => {
|
|
286
|
-
void reload();
|
|
287
|
-
}, []);
|
|
288
|
-
if (error) return /* @__PURE__ */ jsx3("p", { className: "meeting-note", children: copy.loadFailed });
|
|
289
|
-
if (!me) return /* @__PURE__ */ jsx3("p", { className: "meeting-note", children: inheritedCopy.common.loading });
|
|
290
|
-
const role = me.role || "provisional";
|
|
291
|
-
return /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
292
|
-
/* @__PURE__ */ jsxs3("div", { className: "card", children: [
|
|
293
|
-
/* @__PURE__ */ jsxs3("div", { className: "member-row", children: [
|
|
294
|
-
/* @__PURE__ */ jsx3("span", { className: "member-email", children: me.email }),
|
|
295
|
-
/* @__PURE__ */ jsx3("span", { className: "role-badge " + role, children: role })
|
|
296
|
-
] }),
|
|
297
|
-
/* @__PURE__ */ jsxs3("div", { className: "account-actions", children: [
|
|
298
|
-
/* @__PURE__ */ jsx3("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
|
|
299
|
-
role === "admin" ? /* @__PURE__ */ jsx3("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
|
|
300
|
-
] })
|
|
192
|
+
// src/ui/member-gifts.tsx
|
|
193
|
+
import { useEffect, useRef as useRef2, useState as useState4 } from "preact/hooks";
|
|
194
|
+
|
|
195
|
+
// src/ui/gift-offer-cards.tsx
|
|
196
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
197
|
+
var price = (cents, currency) => currency === "usd" ? fmtMoney(cents) : new Intl.NumberFormat(void 0, { style: "currency", currency: currency.toUpperCase() }).format(cents / 100);
|
|
198
|
+
function GiftOfferCards(props) {
|
|
199
|
+
const mode = props.mode ?? "preview";
|
|
200
|
+
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: [
|
|
201
|
+
/* @__PURE__ */ jsx3("div", { className: "card-label", children: offer.title }),
|
|
202
|
+
/* @__PURE__ */ jsx3("p", { children: offer.description }),
|
|
203
|
+
/* @__PURE__ */ jsxs3("p", { className: "meeting-date", children: [
|
|
204
|
+
price(offer.priceCents, offer.currency),
|
|
205
|
+
offer.billingMode === "subscription" ? " recurring" : ""
|
|
301
206
|
] }),
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
ProvisionalCard,
|
|
305
|
-
{
|
|
306
|
-
api,
|
|
307
|
-
application: me.application,
|
|
308
|
-
applyHref,
|
|
309
|
-
copy,
|
|
310
|
-
onReschedule: reload
|
|
311
|
-
}
|
|
312
|
-
);
|
|
313
|
-
return renderProvisional?.({
|
|
314
|
-
api,
|
|
315
|
-
application: me.application,
|
|
316
|
-
applyHref,
|
|
317
|
-
reload,
|
|
318
|
-
defaultContent
|
|
319
|
-
}) ?? defaultContent;
|
|
320
|
-
})() : memberContent ?? /* @__PURE__ */ jsx3("div", { className: "card", children: /* @__PURE__ */ jsx3("div", { className: "card-label", children: copy.full.welcome }) })
|
|
321
|
-
] });
|
|
207
|
+
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 })
|
|
208
|
+
] }, offer.id)) });
|
|
322
209
|
}
|
|
323
210
|
|
|
324
|
-
// src/ui/join.tsx
|
|
325
|
-
import { useEffect as useEffect3, useRef as useRef2, useState as useState7 } from "preact/hooks";
|
|
326
|
-
|
|
327
211
|
// src/ui/payment-step.tsx
|
|
328
|
-
import { useRef, useState as
|
|
212
|
+
import { useRef, useState as useState3 } from "preact/hooks";
|
|
329
213
|
import { jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
|
|
330
214
|
var loader = null;
|
|
331
215
|
function loadStripe() {
|
|
@@ -359,12 +243,13 @@ function PaymentStep(props) {
|
|
|
359
243
|
simulation
|
|
360
244
|
} = props;
|
|
361
245
|
const copy = props.copy ?? inheritedCopy.join.payment;
|
|
362
|
-
const [status, setStatus] =
|
|
363
|
-
const [error, setError] =
|
|
364
|
-
const [lineItems, setLineItems] =
|
|
246
|
+
const [status, setStatus] = useState3("idle");
|
|
247
|
+
const [error, setError] = useState3(null);
|
|
248
|
+
const [lineItems, setLineItems] = useState3(null);
|
|
365
249
|
const mountRef = useRef(null);
|
|
366
250
|
const stripeRef = useRef(null);
|
|
367
251
|
const elementsRef = useRef(null);
|
|
252
|
+
const completionRef = useRef({ gift: false });
|
|
368
253
|
const begin = async () => {
|
|
369
254
|
setStatus("loading");
|
|
370
255
|
setError(null);
|
|
@@ -374,13 +259,17 @@ function PaymentStep(props) {
|
|
|
374
259
|
setStatus("ready");
|
|
375
260
|
return;
|
|
376
261
|
}
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
262
|
+
const data = props.startCheckout ? await props.startCheckout() : await (async () => {
|
|
263
|
+
const res = await fetch("/api/payments/subscription", {
|
|
264
|
+
method: "POST",
|
|
265
|
+
headers: { "content-type": "application/json" },
|
|
266
|
+
body: JSON.stringify({ applicationId, refundPolicyAck: true })
|
|
267
|
+
});
|
|
268
|
+
const body = await res.json();
|
|
269
|
+
if (!res.ok) throw new Error(copy.setupFailed);
|
|
270
|
+
return body;
|
|
271
|
+
})();
|
|
272
|
+
if (!data.clientSecret || !data.publishableKey) throw new Error(copy.setupFailed);
|
|
384
273
|
const stripe = (await loadStripe())(data.publishableKey);
|
|
385
274
|
const elements = stripe.elements({
|
|
386
275
|
clientSecret: data.clientSecret,
|
|
@@ -392,6 +281,7 @@ function PaymentStep(props) {
|
|
|
392
281
|
stripeRef.current = stripe;
|
|
393
282
|
elementsRef.current = elements;
|
|
394
283
|
setLineItems(data.lineItems ?? null);
|
|
284
|
+
completionRef.current = { gift: data.gift === true, ...data.giftCode ? { giftCode: data.giftCode } : {} };
|
|
395
285
|
setStatus("ready");
|
|
396
286
|
} catch (e) {
|
|
397
287
|
setStatus("idle");
|
|
@@ -401,7 +291,7 @@ function PaymentStep(props) {
|
|
|
401
291
|
const pay = async () => {
|
|
402
292
|
if (simulation) {
|
|
403
293
|
setStatus("confirming");
|
|
404
|
-
onPaid();
|
|
294
|
+
onPaid({ gift: false });
|
|
405
295
|
return;
|
|
406
296
|
}
|
|
407
297
|
const stripe = stripeRef.current;
|
|
@@ -423,7 +313,7 @@ function PaymentStep(props) {
|
|
|
423
313
|
return;
|
|
424
314
|
}
|
|
425
315
|
const paid = result.paymentIntent?.status;
|
|
426
|
-
if (paid === "succeeded" || paid === "processing") onPaid();
|
|
316
|
+
if (paid === "succeeded" || paid === "processing") onPaid(completionRef.current);
|
|
427
317
|
else {
|
|
428
318
|
setError(copy.incomplete);
|
|
429
319
|
setStatus("ready");
|
|
@@ -471,15 +361,242 @@ function PaymentStep(props) {
|
|
|
471
361
|
] });
|
|
472
362
|
}
|
|
473
363
|
|
|
474
|
-
// src/ui/
|
|
475
|
-
import { useEffect as useEffect2, useState as useState5 } from "preact/hooks";
|
|
364
|
+
// src/ui/member-gifts.tsx
|
|
476
365
|
import { jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
|
|
366
|
+
function MemberGifts(props) {
|
|
367
|
+
const [data, setData] = useState4(null);
|
|
368
|
+
const [selected, setSelected] = useState4(null);
|
|
369
|
+
const [code, setCode] = useState4("");
|
|
370
|
+
const [redeemCode, setRedeemCode] = useState4("");
|
|
371
|
+
const [message, setMessage] = useState4("");
|
|
372
|
+
const purchaseId = useRef2(crypto.randomUUID());
|
|
373
|
+
const load = async () => setData(await props.api("/api/gifts"));
|
|
374
|
+
useEffect(() => {
|
|
375
|
+
void load().catch(() => setData({ offers: [], claims: [] }));
|
|
376
|
+
}, []);
|
|
377
|
+
const rotate = async (claimId) => {
|
|
378
|
+
try {
|
|
379
|
+
const result = await props.api(`/api/gifts/${encodeURIComponent(claimId)}/rotate`, { method: "POST" });
|
|
380
|
+
setCode(result.code);
|
|
381
|
+
setMessage(props.copy.rotated);
|
|
382
|
+
} catch {
|
|
383
|
+
setMessage(props.copy.rotateFailed);
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
const redeem = async () => {
|
|
387
|
+
try {
|
|
388
|
+
await props.api("/api/gifts/redeem", {
|
|
389
|
+
method: "POST",
|
|
390
|
+
headers: { "content-type": "application/json" },
|
|
391
|
+
body: JSON.stringify({ code: redeemCode })
|
|
392
|
+
});
|
|
393
|
+
setRedeemCode("");
|
|
394
|
+
setMessage(props.copy.redeemed);
|
|
395
|
+
await load();
|
|
396
|
+
} catch {
|
|
397
|
+
setMessage(props.copy.redeemFailed);
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
if (!data) return null;
|
|
401
|
+
const offer = data.offers.find((item) => item.id === selected);
|
|
402
|
+
return /* @__PURE__ */ jsxs5("section", { className: "member-gifts", children: [
|
|
403
|
+
/* @__PURE__ */ jsxs5("div", { className: "card", children: [
|
|
404
|
+
/* @__PURE__ */ jsx5("div", { className: "card-label", children: props.copy.title }),
|
|
405
|
+
/* @__PURE__ */ jsx5("p", { children: props.copy.body }),
|
|
406
|
+
data.offers.length ? /* @__PURE__ */ jsx5(GiftOfferCards, { offers: data.offers, mode: "select", selectedOfferId: selected, onSelect: (id) => {
|
|
407
|
+
setSelected(id);
|
|
408
|
+
setCode("");
|
|
409
|
+
purchaseId.current = crypto.randomUUID();
|
|
410
|
+
} }) : /* @__PURE__ */ jsx5("p", { children: props.copy.noneAvailable }),
|
|
411
|
+
offer ? /* @__PURE__ */ jsx5(
|
|
412
|
+
PaymentStep,
|
|
413
|
+
{
|
|
414
|
+
applicationId: purchaseId.current,
|
|
415
|
+
refundPolicyText: data.refundPolicyText ?? "",
|
|
416
|
+
copy: props.paymentCopy,
|
|
417
|
+
startCheckout: () => props.api("/api/gifts/checkout", {
|
|
418
|
+
method: "POST",
|
|
419
|
+
headers: { "content-type": "application/json" },
|
|
420
|
+
body: JSON.stringify({ offerId: offer.id, purchaseId: purchaseId.current })
|
|
421
|
+
}),
|
|
422
|
+
onPaid: (result) => {
|
|
423
|
+
if (result.giftCode) setCode(result.giftCode);
|
|
424
|
+
setMessage(props.copy.paid);
|
|
425
|
+
setSelected(null);
|
|
426
|
+
setTimeout(() => void load(), 1500);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
) : null,
|
|
430
|
+
code ? /* @__PURE__ */ jsxs5("div", { className: "gift-code-once", children: [
|
|
431
|
+
/* @__PURE__ */ jsx5("output", { children: code }),
|
|
432
|
+
/* @__PURE__ */ jsx5("p", { children: props.copy.saveCode })
|
|
433
|
+
] }) : null
|
|
434
|
+
] }),
|
|
435
|
+
/* @__PURE__ */ jsxs5("div", { className: "card", children: [
|
|
436
|
+
/* @__PURE__ */ jsx5("div", { className: "card-label", children: props.copy.purchases }),
|
|
437
|
+
data.claims.length ? data.claims.map((claim) => /* @__PURE__ */ jsxs5("div", { className: "member-row", children: [
|
|
438
|
+
/* @__PURE__ */ jsx5("span", { children: claim.offerId }),
|
|
439
|
+
/* @__PURE__ */ jsx5("span", { children: props.copy[claim.status] }),
|
|
440
|
+
claim.status === "pending" ? /* @__PURE__ */ jsx5("button", { className: "btn secondary mini", onClick: () => void rotate(claim.id), children: props.copy.rotate }) : null
|
|
441
|
+
] }, claim.id)) : /* @__PURE__ */ jsx5("p", { children: props.copy.noPurchases })
|
|
442
|
+
] }),
|
|
443
|
+
/* @__PURE__ */ jsxs5("div", { className: "card", children: [
|
|
444
|
+
/* @__PURE__ */ jsx5("div", { className: "card-label", children: props.copy.redeemTitle }),
|
|
445
|
+
/* @__PURE__ */ jsxs5("label", { children: [
|
|
446
|
+
props.copy.code,
|
|
447
|
+
/* @__PURE__ */ jsx5("input", { value: redeemCode, maxLength: 64, onInput: (event) => setRedeemCode(event.currentTarget.value) })
|
|
448
|
+
] }),
|
|
449
|
+
/* @__PURE__ */ jsx5("button", { className: "btn secondary", disabled: !redeemCode, onClick: () => void redeem(), children: props.copy.redeem }),
|
|
450
|
+
message ? /* @__PURE__ */ jsx5("p", { role: "status", children: message }) : null
|
|
451
|
+
] })
|
|
452
|
+
] });
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// src/ui/members.tsx
|
|
456
|
+
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
|
|
457
|
+
function card(copy, kicker, body) {
|
|
458
|
+
return /* @__PURE__ */ jsxs6("div", { className: "card", children: [
|
|
459
|
+
/* @__PURE__ */ jsx6("div", { className: "card-label", children: copy.provisional.cardLabel }),
|
|
460
|
+
/* @__PURE__ */ jsxs6("div", { className: "meeting-block", children: [
|
|
461
|
+
/* @__PURE__ */ jsx6("div", { className: "meeting-kicker", children: kicker }),
|
|
462
|
+
body
|
|
463
|
+
] })
|
|
464
|
+
] });
|
|
465
|
+
}
|
|
466
|
+
function ProvisionalCard(props) {
|
|
467
|
+
const { api, application, applyHref, copy, onReschedule } = props;
|
|
468
|
+
if (!application) {
|
|
469
|
+
return card(
|
|
470
|
+
copy,
|
|
471
|
+
copy.provisional.applicationNeeded,
|
|
472
|
+
/* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
473
|
+
/* @__PURE__ */ jsx6("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
|
|
474
|
+
/* @__PURE__ */ jsx6("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
|
|
475
|
+
] })
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
if (application.status === "refunded") {
|
|
479
|
+
return card(
|
|
480
|
+
copy,
|
|
481
|
+
copy.provisional.refunded,
|
|
482
|
+
/* @__PURE__ */ jsx6("div", { className: "meeting-note", children: copy.provisional.refundedBody })
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
const membership = application.paid ? /* @__PURE__ */ jsx6("div", { className: "meeting-note", children: application.renewalAt ? formatChapterCopy(copy.provisional.renews, { date: fmtDate(application.renewalAt) }) : copy.provisional.active }) : null;
|
|
486
|
+
if (application.meetingAt) {
|
|
487
|
+
return card(
|
|
488
|
+
copy,
|
|
489
|
+
copy.provisional.introductionCall,
|
|
490
|
+
/* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
491
|
+
/* @__PURE__ */ jsx6("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
|
|
492
|
+
/* @__PURE__ */ jsx6("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
|
|
493
|
+
application.meetUrl ? /* @__PURE__ */ jsx6("div", { className: "meeting-note", children: /* @__PURE__ */ jsx6("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
|
|
494
|
+
/* @__PURE__ */ jsx6(
|
|
495
|
+
Rescheduler,
|
|
496
|
+
{
|
|
497
|
+
api,
|
|
498
|
+
applicationId: application.id,
|
|
499
|
+
timezone: application.timezone,
|
|
500
|
+
copy: copy.reschedule,
|
|
501
|
+
onRescheduled: onReschedule
|
|
502
|
+
}
|
|
503
|
+
),
|
|
504
|
+
membership
|
|
505
|
+
] })
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
return card(
|
|
509
|
+
copy,
|
|
510
|
+
copy.provisional.bookCall,
|
|
511
|
+
/* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
512
|
+
/* @__PURE__ */ jsx6("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
|
|
513
|
+
/* @__PURE__ */ jsx6(
|
|
514
|
+
Rescheduler,
|
|
515
|
+
{
|
|
516
|
+
api,
|
|
517
|
+
applicationId: application.id,
|
|
518
|
+
timezone: application.timezone,
|
|
519
|
+
copy: copy.reschedule,
|
|
520
|
+
onRescheduled: onReschedule,
|
|
521
|
+
label: copy.provisional.chooseTime
|
|
522
|
+
}
|
|
523
|
+
),
|
|
524
|
+
membership
|
|
525
|
+
] })
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
function MembersArea(props) {
|
|
529
|
+
const inheritedCopy = useChapterCopy();
|
|
530
|
+
const {
|
|
531
|
+
api,
|
|
532
|
+
signOut,
|
|
533
|
+
adminHref = "/admin/",
|
|
534
|
+
applyHref = "/join.html",
|
|
535
|
+
memberContent,
|
|
536
|
+
renderProvisional
|
|
537
|
+
} = props;
|
|
538
|
+
const copy = props.copy ?? inheritedCopy.members;
|
|
539
|
+
const [me, setMe] = useState5(null);
|
|
540
|
+
const [error, setError] = useState5(false);
|
|
541
|
+
const reload = async () => {
|
|
542
|
+
try {
|
|
543
|
+
setMe(await api("/api/me"));
|
|
544
|
+
} catch {
|
|
545
|
+
setError(true);
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
useEffect2(() => {
|
|
549
|
+
void reload();
|
|
550
|
+
}, []);
|
|
551
|
+
if (error) return /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: copy.loadFailed });
|
|
552
|
+
if (!me) return /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: inheritedCopy.common.loading });
|
|
553
|
+
const role = me.role || "provisional";
|
|
554
|
+
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
555
|
+
/* @__PURE__ */ jsxs6("div", { className: "card", children: [
|
|
556
|
+
/* @__PURE__ */ jsxs6("div", { className: "member-row", children: [
|
|
557
|
+
/* @__PURE__ */ jsx6("span", { className: "member-email", children: me.email }),
|
|
558
|
+
/* @__PURE__ */ jsx6("span", { className: "role-badge " + role, children: role })
|
|
559
|
+
] }),
|
|
560
|
+
/* @__PURE__ */ jsxs6("div", { className: "account-actions", children: [
|
|
561
|
+
/* @__PURE__ */ jsx6("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
|
|
562
|
+
role === "admin" ? /* @__PURE__ */ jsx6("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
|
|
563
|
+
] })
|
|
564
|
+
] }),
|
|
565
|
+
role === "provisional" ? (() => {
|
|
566
|
+
const defaultContent = /* @__PURE__ */ jsx6(
|
|
567
|
+
ProvisionalCard,
|
|
568
|
+
{
|
|
569
|
+
api,
|
|
570
|
+
application: me.application,
|
|
571
|
+
applyHref,
|
|
572
|
+
copy,
|
|
573
|
+
onReschedule: reload
|
|
574
|
+
}
|
|
575
|
+
);
|
|
576
|
+
return renderProvisional?.({
|
|
577
|
+
api,
|
|
578
|
+
application: me.application,
|
|
579
|
+
applyHref,
|
|
580
|
+
reload,
|
|
581
|
+
defaultContent
|
|
582
|
+
}) ?? defaultContent;
|
|
583
|
+
})() : memberContent ?? /* @__PURE__ */ jsx6("div", { className: "card", children: /* @__PURE__ */ jsx6("div", { className: "card-label", children: copy.full.welcome }) }),
|
|
584
|
+
/* @__PURE__ */ jsx6(MemberGifts, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment })
|
|
585
|
+
] });
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// src/ui/join.tsx
|
|
589
|
+
import { useEffect as useEffect4, useRef as useRef3, useState as useState9 } from "preact/hooks";
|
|
590
|
+
|
|
591
|
+
// src/ui/join-booking.tsx
|
|
592
|
+
import { useEffect as useEffect3, useState as useState6 } from "preact/hooks";
|
|
593
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
|
|
477
594
|
function JoinBooking(props) {
|
|
478
595
|
const { applicationId, copy, onBooked, simulation } = props;
|
|
479
|
-
const [state, setState] =
|
|
480
|
-
const [msg, setMsg] =
|
|
481
|
-
const [busy, setBusy] =
|
|
482
|
-
const [selected, setSelected] =
|
|
596
|
+
const [state, setState] = useState6(null);
|
|
597
|
+
const [msg, setMsg] = useState6(null);
|
|
598
|
+
const [busy, setBusy] = useState6(false);
|
|
599
|
+
const [selected, setSelected] = useState6(null);
|
|
483
600
|
const load = async () => {
|
|
484
601
|
setMsg(null);
|
|
485
602
|
try {
|
|
@@ -504,7 +621,7 @@ function JoinBooking(props) {
|
|
|
504
621
|
setMsg(copy.loadFailed);
|
|
505
622
|
}
|
|
506
623
|
};
|
|
507
|
-
|
|
624
|
+
useEffect3(() => {
|
|
508
625
|
void load();
|
|
509
626
|
}, [simulation]);
|
|
510
627
|
const book = async () => {
|
|
@@ -536,9 +653,9 @@ function JoinBooking(props) {
|
|
|
536
653
|
setBusy(false);
|
|
537
654
|
}
|
|
538
655
|
};
|
|
539
|
-
if (!state) return /* @__PURE__ */
|
|
540
|
-
return /* @__PURE__ */
|
|
541
|
-
/* @__PURE__ */
|
|
656
|
+
if (!state) return /* @__PURE__ */ jsx7("p", { className: "slots-status", children: msg ?? copy.loading });
|
|
657
|
+
return /* @__PURE__ */ jsxs7("div", { className: "join-book", children: [
|
|
658
|
+
/* @__PURE__ */ jsx7(
|
|
542
659
|
SlotPicker,
|
|
543
660
|
{
|
|
544
661
|
slots: state.slots,
|
|
@@ -548,18 +665,58 @@ function JoinBooking(props) {
|
|
|
548
665
|
onDayChange: () => setSelected(null)
|
|
549
666
|
}
|
|
550
667
|
),
|
|
551
|
-
/* @__PURE__ */
|
|
552
|
-
/* @__PURE__ */
|
|
553
|
-
msg ? /* @__PURE__ */
|
|
668
|
+
/* @__PURE__ */ jsxs7("div", { className: "slot-confirm", hidden: !selected, children: [
|
|
669
|
+
/* @__PURE__ */ jsx7("button", { className: "submit-btn", disabled: busy, onClick: () => void book(), children: busy ? copy.booking : copy.book }),
|
|
670
|
+
msg ? /* @__PURE__ */ jsx7("p", { className: "step2-note", children: msg }) : null
|
|
554
671
|
] })
|
|
555
672
|
] });
|
|
556
673
|
}
|
|
557
674
|
|
|
675
|
+
// src/ui/join-accepted.tsx
|
|
676
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
|
|
677
|
+
function JoinAccepted(props) {
|
|
678
|
+
return /* @__PURE__ */ jsxs8("div", { className: "join-done card", children: [
|
|
679
|
+
/* @__PURE__ */ jsx8("div", { className: "card-label", children: props.copy.accepted.label }),
|
|
680
|
+
/* @__PURE__ */ jsx8("p", { className: "meeting-note", children: props.copy.accepted.body }),
|
|
681
|
+
/* @__PURE__ */ jsx8("a", { className: "apply-link", href: props.membersHref, children: props.copy.done.memberArea })
|
|
682
|
+
] });
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// src/ui/gift-claim-card.tsx
|
|
686
|
+
import { useState as useState7 } from "preact/hooks";
|
|
687
|
+
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
|
|
688
|
+
function GiftClaimCard(props) {
|
|
689
|
+
const [code, setCode] = useState7(props.initialCode ?? "");
|
|
690
|
+
const [error, setError] = useState7(false);
|
|
691
|
+
const rotate = async () => {
|
|
692
|
+
if (!props.claimId) return;
|
|
693
|
+
setError(false);
|
|
694
|
+
const response = await fetch(`/api/gifts/${encodeURIComponent(props.claimId)}/rotate`, {
|
|
695
|
+
method: "POST",
|
|
696
|
+
headers: { "content-type": "application/json" },
|
|
697
|
+
body: JSON.stringify({ applicationId: props.applicationId })
|
|
698
|
+
});
|
|
699
|
+
const body = await response.json();
|
|
700
|
+
if (response.ok && body.code) setCode(body.code);
|
|
701
|
+
else setError(true);
|
|
702
|
+
};
|
|
703
|
+
return /* @__PURE__ */ jsxs9("div", { className: "join-done card", children: [
|
|
704
|
+
/* @__PURE__ */ jsx9("div", { className: "card-label", children: props.copy.label }),
|
|
705
|
+
/* @__PURE__ */ jsx9("p", { className: "meeting-note", children: props.copy.body }),
|
|
706
|
+
code ? /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
707
|
+
/* @__PURE__ */ jsx9("output", { className: "gift-code", children: code }),
|
|
708
|
+
/* @__PURE__ */ jsx9("p", { children: props.copy.save })
|
|
709
|
+
] }) : null,
|
|
710
|
+
!code && props.claimId ? /* @__PURE__ */ jsx9("button", { type: "button", className: "btn secondary", onClick: () => void rotate(), children: props.copy.rotate }) : null,
|
|
711
|
+
error ? /* @__PURE__ */ jsx9("p", { role: "alert", children: props.copy.rotateFailed }) : null
|
|
712
|
+
] });
|
|
713
|
+
}
|
|
714
|
+
|
|
558
715
|
// src/ui/join-tiers.tsx
|
|
559
|
-
import { useState as
|
|
560
|
-
import { jsx as
|
|
716
|
+
import { useState as useState8 } from "preact/hooks";
|
|
717
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
|
|
561
718
|
function useTierSelection(tiers, initialTierId) {
|
|
562
|
-
const [selectedTierId, setSelectedTierId] =
|
|
719
|
+
const [selectedTierId, setSelectedTierId] = useState8(() => {
|
|
563
720
|
const preset = tiers.find((tier) => tier.id === initialTierId);
|
|
564
721
|
if (preset) return preset.id;
|
|
565
722
|
return tiers.length === 1 ? tiers[0].id : null;
|
|
@@ -574,10 +731,10 @@ function useTierSelection(tiers, initialTierId) {
|
|
|
574
731
|
};
|
|
575
732
|
}
|
|
576
733
|
function TierPlaceholder(context) {
|
|
577
|
-
return /* @__PURE__ */
|
|
578
|
-
/* @__PURE__ */
|
|
579
|
-
context.tiers.map((tier) => /* @__PURE__ */
|
|
580
|
-
/* @__PURE__ */
|
|
734
|
+
return /* @__PURE__ */ jsxs10("fieldset", { "data-chapter-placeholder": "tiers", children: [
|
|
735
|
+
/* @__PURE__ */ jsx10("legend", { children: "Membership (placeholder \u2014 pass renderTiers to style this)" }),
|
|
736
|
+
context.tiers.map((tier) => /* @__PURE__ */ jsxs10("label", { children: [
|
|
737
|
+
/* @__PURE__ */ jsx10(
|
|
581
738
|
"input",
|
|
582
739
|
{
|
|
583
740
|
type: "radio",
|
|
@@ -595,23 +752,21 @@ function tierNeedsPayment(selected, paymentsReady) {
|
|
|
595
752
|
return selected ? !selected.free && paymentsReady : paymentsReady;
|
|
596
753
|
}
|
|
597
754
|
|
|
598
|
-
// src/ui/join.
|
|
599
|
-
import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
|
|
755
|
+
// src/ui/join-resume.ts
|
|
600
756
|
async function loadJoinResume(applicationId, fetcher = fetch) {
|
|
601
757
|
const res = await fetcher(`/api/join/resume?application=${encodeURIComponent(applicationId)}`);
|
|
602
758
|
const data = await res.json();
|
|
603
759
|
if (!res.ok) throw new Error(data.error ?? "The application could not be resumed.");
|
|
604
|
-
if (data.state === "done" && data.booked) {
|
|
605
|
-
|
|
606
|
-
}
|
|
607
|
-
if (data.state === "
|
|
608
|
-
|
|
609
|
-
}
|
|
610
|
-
if (data.state === "booking") {
|
|
611
|
-
return { step: "booking", applicationId: data.applicationId };
|
|
612
|
-
}
|
|
760
|
+
if (data.state === "done" && data.booked) return { step: "done", applicationId: data.applicationId, booked: data.booked };
|
|
761
|
+
if (data.state === "paymentPending") return { step: "paymentPending", applicationId: data.applicationId };
|
|
762
|
+
if (data.state === "booking") return { step: "booking", applicationId: data.applicationId };
|
|
763
|
+
if (data.state === "accepted") return { step: "accepted", applicationId: data.applicationId };
|
|
764
|
+
if (data.state === "gift") return { step: "gift", applicationId: data.applicationId, ...data.claimId ? { claimId: data.claimId } : {} };
|
|
613
765
|
return { step: "payment", applicationId: data.applicationId };
|
|
614
766
|
}
|
|
767
|
+
|
|
768
|
+
// src/ui/join.tsx
|
|
769
|
+
import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
|
|
615
770
|
function JoinIsland(props) {
|
|
616
771
|
const inheritedCopy = useChapterCopy();
|
|
617
772
|
const {
|
|
@@ -620,15 +775,18 @@ function JoinIsland(props) {
|
|
|
620
775
|
membersHref = "/members/",
|
|
621
776
|
renderStepHeader,
|
|
622
777
|
renderDone,
|
|
778
|
+
renderAccepted,
|
|
779
|
+
renderGift,
|
|
623
780
|
renderSubmit
|
|
624
781
|
} = props;
|
|
625
782
|
const copy = props.copy ?? config.copy ?? inheritedCopy.join;
|
|
626
783
|
const tiers = config.tiers ?? [];
|
|
627
784
|
const tierSelection = useTierSelection(tiers, props.initialTierId);
|
|
628
785
|
const { selectedTierId, selected: selectedTier } = tierSelection;
|
|
629
|
-
const [state, setState] =
|
|
630
|
-
const [error, setError] =
|
|
631
|
-
const [submitting, setSubmitting] =
|
|
786
|
+
const [state, setState] = useState9(props.initialState ?? { step: "form" });
|
|
787
|
+
const [error, setError] = useState9(null);
|
|
788
|
+
const [submitting, setSubmitting] = useState9(false);
|
|
789
|
+
const [giftOfferId, setGiftOfferId] = useState9(props.initialGiftOfferId ?? null);
|
|
632
790
|
const simulatedPayment = props.simulation ? props.simulation.payment ?? {
|
|
633
791
|
lineItems: {
|
|
634
792
|
standardCents: selectedTier?.priceCents ?? 0,
|
|
@@ -637,8 +795,8 @@ function JoinIsland(props) {
|
|
|
637
795
|
}
|
|
638
796
|
} : void 0;
|
|
639
797
|
const simulatedBooking = props.simulation ? props.simulation.booking ?? { slots: [], timezone: "UTC" } : void 0;
|
|
640
|
-
const submissionId =
|
|
641
|
-
|
|
798
|
+
const submissionId = useRef3(null);
|
|
799
|
+
useEffect4(() => {
|
|
642
800
|
if (props.simulation) return;
|
|
643
801
|
const resolver = props.loadResume ?? (() => {
|
|
644
802
|
if (typeof window === "undefined") return Promise.resolve(null);
|
|
@@ -655,7 +813,7 @@ function JoinIsland(props) {
|
|
|
655
813
|
live = false;
|
|
656
814
|
};
|
|
657
815
|
}, [props.loadResume, props.simulation]);
|
|
658
|
-
|
|
816
|
+
useEffect4(() => {
|
|
659
817
|
if (state.step !== "paymentPending") return;
|
|
660
818
|
let live = true;
|
|
661
819
|
let timer;
|
|
@@ -683,12 +841,13 @@ function JoinIsland(props) {
|
|
|
683
841
|
try {
|
|
684
842
|
const fields = collectFormFields(new FormData(e.currentTarget));
|
|
685
843
|
fields.submissionId = submissionId.current ??= crypto.randomUUID();
|
|
686
|
-
if (
|
|
844
|
+
if (giftOfferId) fields.giftOfferId = giftOfferId;
|
|
845
|
+
else if (selectedTierId) fields.tierId = selectedTierId;
|
|
687
846
|
if (props.simulation) {
|
|
688
847
|
setState({
|
|
689
848
|
// Preview the intended paid journey even before live Stripe wiring is
|
|
690
849
|
// ready. Production still uses the server-authoritative readiness bit.
|
|
691
|
-
step: tierNeedsPayment(selectedTier, true) ? "payment" : "booking",
|
|
850
|
+
step: giftOfferId || tierNeedsPayment(selectedTier, true) ? "payment" : "booking",
|
|
692
851
|
applicationId: props.simulation.applicationId ?? "simulation-application"
|
|
693
852
|
});
|
|
694
853
|
return;
|
|
@@ -700,6 +859,18 @@ function JoinIsland(props) {
|
|
|
700
859
|
});
|
|
701
860
|
const data = await res.json();
|
|
702
861
|
if (!res.ok || !data.id) throw new Error(data.error ?? copy.form.submitFailed);
|
|
862
|
+
if (data.state === "accepted") {
|
|
863
|
+
setState({ step: "accepted", applicationId: data.id });
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
if (data.state === "paymentPending") {
|
|
867
|
+
setState({ step: "paymentPending", applicationId: data.id });
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
if (data.state === "payment" || data.state === "booking") {
|
|
871
|
+
setState({ step: data.state, applicationId: data.id });
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
703
874
|
setState({
|
|
704
875
|
step: tierNeedsPayment(selectedTier, config.paymentsReady) ? "payment" : "booking",
|
|
705
876
|
applicationId: data.id
|
|
@@ -715,21 +886,35 @@ function JoinIsland(props) {
|
|
|
715
886
|
..."applicationId" in state ? { applicationId: state.applicationId } : {}
|
|
716
887
|
});
|
|
717
888
|
if (state.step === "done") {
|
|
718
|
-
const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */
|
|
719
|
-
/* @__PURE__ */
|
|
720
|
-
/* @__PURE__ */
|
|
721
|
-
/* @__PURE__ */
|
|
722
|
-
/* @__PURE__ */
|
|
889
|
+
const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsxs11("div", { className: "join-done card", children: [
|
|
890
|
+
/* @__PURE__ */ jsx11("div", { className: "card-label", children: copy.done.label }),
|
|
891
|
+
/* @__PURE__ */ jsx11("p", { className: "meeting-date", children: fullLabel(state.booked.startAt, state.booked.timezone) }),
|
|
892
|
+
/* @__PURE__ */ jsx11("p", { className: "meeting-note", children: copy.done.calendarInvite }),
|
|
893
|
+
/* @__PURE__ */ jsx11("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
|
|
723
894
|
] });
|
|
724
|
-
return /* @__PURE__ */
|
|
895
|
+
return /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
896
|
+
header,
|
|
897
|
+
body
|
|
898
|
+
] });
|
|
899
|
+
}
|
|
900
|
+
if (state.step === "accepted") {
|
|
901
|
+
const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsx11(JoinAccepted, { copy, membersHref });
|
|
902
|
+
return /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
903
|
+
header,
|
|
904
|
+
body
|
|
905
|
+
] });
|
|
906
|
+
}
|
|
907
|
+
if (state.step === "gift") {
|
|
908
|
+
const body = renderGift?.(state) ?? /* @__PURE__ */ jsx11(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
|
|
909
|
+
return /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
725
910
|
header,
|
|
726
911
|
body
|
|
727
912
|
] });
|
|
728
913
|
}
|
|
729
914
|
if (state.step === "booking") {
|
|
730
|
-
return /* @__PURE__ */
|
|
915
|
+
return /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
731
916
|
header,
|
|
732
|
-
/* @__PURE__ */
|
|
917
|
+
/* @__PURE__ */ jsx11(
|
|
733
918
|
JoinBooking,
|
|
734
919
|
{
|
|
735
920
|
applicationId: state.applicationId,
|
|
@@ -743,9 +928,9 @@ function JoinIsland(props) {
|
|
|
743
928
|
] });
|
|
744
929
|
}
|
|
745
930
|
if (state.step === "payment") {
|
|
746
|
-
return /* @__PURE__ */
|
|
931
|
+
return /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
747
932
|
header,
|
|
748
|
-
/* @__PURE__ */
|
|
933
|
+
/* @__PURE__ */ jsx11(
|
|
749
934
|
PaymentStep,
|
|
750
935
|
{
|
|
751
936
|
applicationId: state.applicationId,
|
|
@@ -755,27 +940,42 @@ function JoinIsland(props) {
|
|
|
755
940
|
fonts: props.payment?.fonts,
|
|
756
941
|
renderPriceLines: props.payment?.renderPriceLines,
|
|
757
942
|
simulation: simulatedPayment,
|
|
758
|
-
onPaid: () =>
|
|
943
|
+
onPaid: (result) => {
|
|
944
|
+
if (props.simulation) {
|
|
945
|
+
setState(giftOfferId ? { step: "gift", applicationId: state.applicationId, code: "gift1_simulation_only_not_a_real_claim_code" } : { step: "booking", applicationId: state.applicationId });
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
if (result.gift && result.giftCode) {
|
|
949
|
+
setState({ step: "gift", applicationId: state.applicationId, code: result.giftCode });
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
setState({ step: "paymentPending", applicationId: state.applicationId });
|
|
953
|
+
},
|
|
759
954
|
children: props.payment?.children
|
|
760
955
|
}
|
|
761
956
|
)
|
|
762
957
|
] });
|
|
763
958
|
}
|
|
764
959
|
if (state.step === "paymentPending") {
|
|
765
|
-
return /* @__PURE__ */
|
|
960
|
+
return /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
766
961
|
header,
|
|
767
|
-
/* @__PURE__ */
|
|
962
|
+
/* @__PURE__ */ jsx11("p", { className: "pay-status", role: "status", children: copy.payment.pending })
|
|
768
963
|
] });
|
|
769
964
|
}
|
|
770
965
|
const submitDisabled = submitting || props.submitDisabled === true;
|
|
771
966
|
const tierChooser = tiers.length > 1 ? props.renderTiers?.(tierSelection) ?? TierPlaceholder(tierSelection) : null;
|
|
772
|
-
return /* @__PURE__ */
|
|
967
|
+
return /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
773
968
|
header,
|
|
774
|
-
/* @__PURE__ */
|
|
969
|
+
/* @__PURE__ */ jsxs11("form", { className: "join-form", onSubmit: (e) => void submit(e), children: [
|
|
970
|
+
(config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs11("fieldset", { children: [
|
|
971
|
+
/* @__PURE__ */ jsx11("legend", { children: copy.gift.optionsLabel }),
|
|
972
|
+
/* @__PURE__ */ jsx11("button", { type: "button", className: "btn secondary", "aria-pressed": !giftOfferId, onClick: () => setGiftOfferId(null), children: copy.gift.chooseSelf }),
|
|
973
|
+
/* @__PURE__ */ jsx11(GiftOfferCards, { offers: config.giftOffers ?? [], mode: "select", selectedOfferId: giftOfferId, onSelect: setGiftOfferId })
|
|
974
|
+
] }) : null,
|
|
775
975
|
tierChooser,
|
|
776
976
|
children,
|
|
777
|
-
error ? /* @__PURE__ */
|
|
778
|
-
renderSubmit?.({ submitting, disabled: submitDisabled }) ?? /* @__PURE__ */
|
|
977
|
+
error ? /* @__PURE__ */ jsx11("p", { className: "join-error", children: error }) : null,
|
|
978
|
+
renderSubmit?.({ submitting, disabled: submitDisabled }) ?? /* @__PURE__ */ jsx11("button", { className: "submit-btn", type: "submit", disabled: submitDisabled, children: submitting ? copy.form.submitting : copy.form.submit })
|
|
779
979
|
] })
|
|
780
980
|
] });
|
|
781
981
|
}
|
|
@@ -952,7 +1152,7 @@ function membershipPageDocument(input, options = {}) {
|
|
|
952
1152
|
}
|
|
953
1153
|
|
|
954
1154
|
// src/ui/membership-cards.tsx
|
|
955
|
-
import { jsx as
|
|
1155
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
|
|
956
1156
|
var MEMBERSHIP_CARD_TOKEN_DEFAULTS = Object.freeze({
|
|
957
1157
|
"--ui-membership-grid-gap": "1.4rem",
|
|
958
1158
|
"--ui-membership-card-padding": "2rem 1.7rem 1.8rem",
|
|
@@ -1021,67 +1221,67 @@ function membershipApplicationHref(applicationPath, tierId) {
|
|
|
1021
1221
|
}
|
|
1022
1222
|
function TierAction(props) {
|
|
1023
1223
|
if (props.mode === "select") {
|
|
1024
|
-
return /* @__PURE__ */
|
|
1224
|
+
return /* @__PURE__ */ jsxs12("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
|
|
1025
1225
|
props.label,
|
|
1026
|
-
/* @__PURE__ */
|
|
1226
|
+
/* @__PURE__ */ jsx12("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1027
1227
|
] });
|
|
1028
1228
|
}
|
|
1029
1229
|
if (props.mode === "preview") {
|
|
1030
|
-
return /* @__PURE__ */
|
|
1230
|
+
return /* @__PURE__ */ jsxs12("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
|
|
1031
1231
|
props.label,
|
|
1032
|
-
/* @__PURE__ */
|
|
1232
|
+
/* @__PURE__ */ jsx12("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1033
1233
|
] });
|
|
1034
1234
|
}
|
|
1035
|
-
return /* @__PURE__ */
|
|
1235
|
+
return /* @__PURE__ */ jsxs12("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
|
|
1036
1236
|
props.label,
|
|
1037
|
-
/* @__PURE__ */
|
|
1237
|
+
/* @__PURE__ */ jsx12("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1038
1238
|
] });
|
|
1039
1239
|
}
|
|
1040
1240
|
function TierCard(props) {
|
|
1041
1241
|
const { tier, presentation } = props;
|
|
1042
1242
|
const summary = presentation.summaryMarkdown ?? tier.blurb;
|
|
1043
1243
|
const action = presentation.ctaLabel ?? (tier.free ? "Join for free" : `Choose ${tier.name}`);
|
|
1044
|
-
return /* @__PURE__ */
|
|
1045
|
-
presentation.badge ? /* @__PURE__ */
|
|
1046
|
-
/* @__PURE__ */
|
|
1047
|
-
/* @__PURE__ */
|
|
1048
|
-
presentation.capacity ? /* @__PURE__ */
|
|
1049
|
-
/* @__PURE__ */
|
|
1050
|
-
/* @__PURE__ */
|
|
1244
|
+
return /* @__PURE__ */ jsxs12("article", { className: "chapter-membership-card", "data-tier-id": tier.id, "data-variant": presentation.variant ?? "standard", children: [
|
|
1245
|
+
presentation.badge ? /* @__PURE__ */ jsx12("div", { className: "chapter-membership-badge", children: presentation.badge }) : null,
|
|
1246
|
+
/* @__PURE__ */ jsx12("h3", { className: "chapter-membership-name", children: tier.name }),
|
|
1247
|
+
/* @__PURE__ */ jsxs12("div", { className: "chapter-membership-offer", "data-with-capacity": presentation.capacity ? "true" : void 0, children: [
|
|
1248
|
+
presentation.capacity ? /* @__PURE__ */ jsxs12("div", { className: "chapter-membership-capacity", "aria-label": `${presentation.capacity.total} ${presentation.capacity.label ?? "available"}`, children: [
|
|
1249
|
+
/* @__PURE__ */ jsx12("strong", { children: presentation.capacity.total.toLocaleString("en-US") }),
|
|
1250
|
+
/* @__PURE__ */ jsx12("small", { children: presentation.capacity.label ?? "available" })
|
|
1051
1251
|
] }) : null,
|
|
1052
|
-
/* @__PURE__ */
|
|
1053
|
-
presentation.priceEyebrow ? /* @__PURE__ */
|
|
1054
|
-
/* @__PURE__ */
|
|
1055
|
-
presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */
|
|
1056
|
-
/* @__PURE__ */
|
|
1057
|
-
!tier.free && presentation.billingLabel ? /* @__PURE__ */
|
|
1252
|
+
/* @__PURE__ */ jsxs12("div", { className: "chapter-membership-price-stack", children: [
|
|
1253
|
+
presentation.priceEyebrow ? /* @__PURE__ */ jsx12("p", { className: "chapter-membership-price-eyebrow", children: presentation.priceEyebrow }) : null,
|
|
1254
|
+
/* @__PURE__ */ jsxs12("div", { className: "chapter-membership-price-row", children: [
|
|
1255
|
+
presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */ jsx12("span", { className: "chapter-membership-compare", children: fmtMoney(presentation.compareAtPriceCents) }) : null,
|
|
1256
|
+
/* @__PURE__ */ jsx12("span", { className: "chapter-membership-price", children: tier.free ? "Free" : fmtMoney(tier.priceCents) }),
|
|
1257
|
+
!tier.free && presentation.billingLabel ? /* @__PURE__ */ jsx12("span", { className: "chapter-membership-billing", children: presentation.billingLabel }) : null
|
|
1058
1258
|
] })
|
|
1059
1259
|
] })
|
|
1060
1260
|
] }),
|
|
1061
|
-
presentation.priceNoteMarkdown ? /* @__PURE__ */
|
|
1062
|
-
summary ? /* @__PURE__ */
|
|
1063
|
-
presentation.benefits?.length ? /* @__PURE__ */
|
|
1064
|
-
/* @__PURE__ */
|
|
1065
|
-
/* @__PURE__ */
|
|
1261
|
+
presentation.priceNoteMarkdown ? /* @__PURE__ */ jsx12(Markdown, { className: "chapter-membership-price-note", source: presentation.priceNoteMarkdown }) : null,
|
|
1262
|
+
summary ? /* @__PURE__ */ jsx12(Markdown, { className: "chapter-membership-summary", source: summary }) : null,
|
|
1263
|
+
presentation.benefits?.length ? /* @__PURE__ */ jsx12("ul", { className: "chapter-membership-benefits", children: presentation.benefits.map((benefit, index) => /* @__PURE__ */ jsxs12("li", { children: [
|
|
1264
|
+
/* @__PURE__ */ jsx12("span", { className: "chapter-membership-check", "aria-hidden": "true", children: "\u2713" }),
|
|
1265
|
+
/* @__PURE__ */ jsx12(Markdown, { className: "chapter-membership-benefit", source: benefit })
|
|
1066
1266
|
] }, `${tier.id}-benefit-${index}`)) }) : null,
|
|
1067
|
-
presentation.callout ? /* @__PURE__ */
|
|
1068
|
-
presentation.callout.label ? /* @__PURE__ */
|
|
1069
|
-
/* @__PURE__ */
|
|
1267
|
+
presentation.callout ? /* @__PURE__ */ jsxs12("aside", { className: "chapter-membership-callout", children: [
|
|
1268
|
+
presentation.callout.label ? /* @__PURE__ */ jsx12("p", { className: "chapter-membership-callout-label", children: presentation.callout.label }) : null,
|
|
1269
|
+
/* @__PURE__ */ jsx12(Markdown, { source: presentation.callout.bodyMarkdown })
|
|
1070
1270
|
] }) : null,
|
|
1071
|
-
/* @__PURE__ */
|
|
1271
|
+
/* @__PURE__ */ jsx12(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
|
|
1072
1272
|
] });
|
|
1073
1273
|
}
|
|
1074
1274
|
function MembershipCards(props) {
|
|
1075
1275
|
const document2 = membershipPageDocument(props.document, { tiers: props.tiers });
|
|
1076
1276
|
const byId = new Map(props.tiers.map((tier) => [tier.id, tier]));
|
|
1077
1277
|
const mode = props.mode ?? "link";
|
|
1078
|
-
return /* @__PURE__ */
|
|
1079
|
-
/* @__PURE__ */
|
|
1080
|
-
/* @__PURE__ */
|
|
1278
|
+
return /* @__PURE__ */ jsxs12("section", { className: ["chapter-membership", props.className].filter(Boolean).join(" "), "data-chapter-membership": MEMBERSHIP_PAGE_RENDERER, "aria-label": props.ariaLabel ?? "Membership options", children: [
|
|
1279
|
+
/* @__PURE__ */ jsx12("style", { children: MEMBERSHIP_CARDS_CSS }),
|
|
1280
|
+
/* @__PURE__ */ jsx12("div", { className: "chapter-membership-grid", style: { "--chapter-membership-columns": String(Math.min(document2.tiers.length, 3)) }, children: document2.tiers.map((presentation) => {
|
|
1081
1281
|
const tier = byId.get(presentation.tierId);
|
|
1082
|
-
return /* @__PURE__ */
|
|
1282
|
+
return /* @__PURE__ */ jsx12(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
|
|
1083
1283
|
}) }),
|
|
1084
|
-
document2.footnoteMarkdown ? /* @__PURE__ */
|
|
1284
|
+
document2.footnoteMarkdown ? /* @__PURE__ */ jsx12(Markdown, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
|
|
1085
1285
|
] });
|
|
1086
1286
|
}
|
|
1087
1287
|
|
|
@@ -1096,8 +1296,10 @@ export {
|
|
|
1096
1296
|
groupSlotsByDay,
|
|
1097
1297
|
SlotPicker,
|
|
1098
1298
|
Rescheduler,
|
|
1099
|
-
|
|
1299
|
+
GiftOfferCards,
|
|
1100
1300
|
PaymentStep,
|
|
1301
|
+
MemberGifts,
|
|
1302
|
+
MembersArea,
|
|
1101
1303
|
useTierSelection,
|
|
1102
1304
|
TierPlaceholder,
|
|
1103
1305
|
tierNeedsPayment,
|
|
@@ -1107,4 +1309,4 @@ export {
|
|
|
1107
1309
|
membershipApplicationHref,
|
|
1108
1310
|
MembershipCards
|
|
1109
1311
|
};
|
|
1110
|
-
//# sourceMappingURL=chunk-
|
|
1312
|
+
//# sourceMappingURL=chunk-I45VYBUV.js.map
|