@odla-ai/chapter 0.48.3 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -2
- package/dist/{chunk-MQ4OPZCS.js → chunk-4EA5V4JE.js} +994 -648
- package/dist/chunk-4EA5V4JE.js.map +1 -0
- package/dist/{chunk-4HS2JPE2.js → chunk-JXX4BFDP.js} +21 -2
- package/dist/chunk-JXX4BFDP.js.map +1 -0
- package/dist/{chunk-KZ2AXEZW.js → chunk-OS46ZE46.js} +765 -543
- package/dist/chunk-OS46ZE46.js.map +1 -0
- package/dist/{copy-context-CMupQL9h.d.ts → copy-context-Ddat__H5.d.ts} +16 -3
- package/dist/index.cjs +591 -158
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +101 -8
- package/dist/index.d.ts +101 -8
- package/dist/index.js +587 -154
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +64 -5
- package/dist/ui/admin/index.js +14 -2
- package/dist/ui/index.d.ts +3 -3
- package/dist/ui/index.js +19 -3
- package/dist/ui/member/index.d.ts +44 -4
- package/dist/ui/member/index.js +6 -2
- package/dist/worker/index.cjs +5114 -4064
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +105 -6
- package/dist/worker/index.d.ts +105 -6
- package/dist/worker/index.js +5104 -4054
- 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-JXX4BFDP.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
|
|
114
|
-
|
|
115
|
-
// src/ui/reschedule.tsx
|
|
116
|
-
import { useState as useState2 } from "preact/hooks";
|
|
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";
|
|
113
|
+
// src/ui/member-restart.tsx
|
|
114
|
+
import { useEffect as useEffect2, useState as useState4 } from "preact/hooks";
|
|
199
115
|
|
|
200
|
-
// src/ui/
|
|
201
|
-
import {
|
|
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,353 @@ 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
|
+
quote.founding ? /* @__PURE__ */ jsx3("p", { className: "payment-founding", role: "note", "aria-label": "Founding member", children: copy.foundingMember }) : null,
|
|
324
|
+
props.renderPriceLines ? props.renderPriceLines(quote.lineItems) : /* @__PURE__ */ jsxs3("dl", { children: [
|
|
325
|
+
/* @__PURE__ */ jsx3("dt", { children: "Membership price" }),
|
|
326
|
+
/* @__PURE__ */ jsxs3("dd", { children: [
|
|
327
|
+
amount(quote.lineItems.standardCents),
|
|
328
|
+
" per ",
|
|
329
|
+
quote.interval
|
|
330
|
+
] }),
|
|
331
|
+
quote.lineItems.discountCents > 0 ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
332
|
+
/* @__PURE__ */ jsx3("dt", { children: quote.founding || quote.presentation ? copy.foundingDiscount : "Discount" }),
|
|
333
|
+
/* @__PURE__ */ jsx3("dd", { children: amount(quote.lineItems.discountCents) })
|
|
334
|
+
] }) : null,
|
|
335
|
+
/* @__PURE__ */ jsx3("dt", { children: "Due today" }),
|
|
336
|
+
/* @__PURE__ */ jsx3("dd", { children: amount(quote.lineItems.dueTodayCents) })
|
|
337
|
+
] }),
|
|
338
|
+
quote.commercial ? /* @__PURE__ */ jsxs3("div", { role: "note", "aria-label": "Renewal terms", children: [
|
|
339
|
+
quote.commercial.initialTermEndsAt !== void 0 ? /* @__PURE__ */ jsxs3("p", { children: [
|
|
340
|
+
"First renewal: ",
|
|
341
|
+
new Intl.DateTimeFormat("en-US", {
|
|
342
|
+
dateStyle: "long",
|
|
343
|
+
timeZone: "UTC"
|
|
344
|
+
}).format(quote.commercial.initialTermEndsAt),
|
|
345
|
+
"."
|
|
346
|
+
] }) : null,
|
|
347
|
+
/* @__PURE__ */ jsxs3("p", { children: [
|
|
348
|
+
"Renews automatically at ",
|
|
349
|
+
amount(quote.commercial.renewalCents),
|
|
350
|
+
" per ",
|
|
351
|
+
quote.interval,
|
|
352
|
+
" unless canceled before renewal."
|
|
353
|
+
] }),
|
|
354
|
+
quote.commercial.discountDuration === "first_term" ? /* @__PURE__ */ jsx3("p", { children: "The discount applies to your first paid term only." }) : null,
|
|
355
|
+
quote.commercial.discountDuration === "while_active" ? /* @__PURE__ */ jsx3("p", { children: "The discounted rate continues while this membership stays active." }) : null
|
|
356
|
+
] }) : null,
|
|
357
|
+
quote.trustCopy ? /* @__PURE__ */ jsx3("p", { className: "pay-trust", children: quote.trustCopy }) : null
|
|
358
|
+
] }),
|
|
359
|
+
/* @__PURE__ */ jsx3(
|
|
360
|
+
PaymentStep,
|
|
361
|
+
{
|
|
362
|
+
...props,
|
|
363
|
+
refundPolicyText: quote.refundPolicyText,
|
|
364
|
+
merchantDisclosureText: quote.merchantDisclosureText,
|
|
365
|
+
renderPriceLines: void 0,
|
|
366
|
+
startCheckout
|
|
367
|
+
}
|
|
368
|
+
)
|
|
369
|
+
] });
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// src/ui/journey-frame.tsx
|
|
373
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
|
|
374
|
+
var styles = `
|
|
375
|
+
.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}
|
|
376
|
+
.chapter-journey *{box-sizing:border-box}
|
|
377
|
+
.chapter-journey :where(h2,h3,p){margin:0 0 1rem}
|
|
378
|
+
.chapter-journey :where(h2,h3){font-family:var(--ui-font-display,inherit);line-height:1.2;letter-spacing:-.025em;text-transform:none}
|
|
379
|
+
.chapter-journey h2{font-size:clamp(1.6rem,3vw,2.15rem)}
|
|
380
|
+
.chapter-journey h3{font-size:1.3rem}
|
|
381
|
+
.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}
|
|
382
|
+
.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}
|
|
383
|
+
.chapter-journey :where(form,.journey-fields){display:grid;gap:1.25rem}
|
|
384
|
+
.chapter-journey :where(label){display:block;font-size:.95rem;font-weight:500;letter-spacing:normal;text-transform:none;line-height:1.55}
|
|
385
|
+
.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}
|
|
386
|
+
.chapter-journey :where(input,textarea,button,a,select):focus-visible{outline:3px solid var(--ui-accent,#3d6a60);outline-offset:3px}
|
|
387
|
+
.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)}
|
|
388
|
+
.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}
|
|
389
|
+
.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)}
|
|
390
|
+
.chapter-journey :where(button.secondary,.journey-secondary){background:transparent;color:var(--ui-text,#202827);border-color:var(--ui-border,#dfe3df)}
|
|
391
|
+
.chapter-journey :is(.slot-time,.slot-day){background:var(--ui-surface,#fff);color:var(--ui-text,#202827);border-color:var(--ui-border,#dfe3df)}
|
|
392
|
+
.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)}
|
|
393
|
+
.chapter-journey :is(.slot-time,.slot-day)[aria-pressed=true]{background:var(--ui-accent,#285c50);color:var(--ui-on-accent,#fff)}
|
|
394
|
+
.chapter-journey button:disabled{opacity:.55;cursor:default}
|
|
395
|
+
.chapter-journey :where(.compliance-box,.journey-note){padding:1.2rem;background:var(--ui-surface-2,#f3f5f2);border-radius:10px;margin-block:1.2rem}
|
|
396
|
+
.chapter-journey :where(.compliance-box p:last-child,.journey-note p:last-child,.card p:last-child){margin-bottom:0}
|
|
397
|
+
.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}
|
|
398
|
+
.chapter-journey .journey-invitation p{margin:0}
|
|
399
|
+
.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}
|
|
400
|
+
.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)}
|
|
401
|
+
.chapter-journey :where(dd){margin:0;text-align:right;font-variant-numeric:tabular-nums}
|
|
402
|
+
.chapter-journey :where(.pay-status,.meeting-note,.slots-status){color:var(--ui-text-muted,#536360)}
|
|
403
|
+
.chapter-journey .journey-actions{display:flex;gap:.75rem;flex-wrap:wrap;margin-top:1.25rem}
|
|
404
|
+
.chapter-journey fieldset{min-width:0;border:0;padding:0;margin:0}
|
|
405
|
+
@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}}
|
|
406
|
+
`;
|
|
407
|
+
function JourneyFrame({ children }) {
|
|
408
|
+
return /* @__PURE__ */ jsxs4("div", { className: "chapter-journey", children: [
|
|
409
|
+
/* @__PURE__ */ jsx4("style", { children: styles }),
|
|
410
|
+
children
|
|
411
|
+
] });
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// src/ui/member-restart.tsx
|
|
372
415
|
import { jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
|
|
416
|
+
function MemberRestart(props) {
|
|
417
|
+
const [id, setId] = useState4(props.applicationId);
|
|
418
|
+
const [busy, setBusy] = useState4(false);
|
|
419
|
+
const [error, setError] = useState4("");
|
|
420
|
+
const [paid, setPaid] = useState4(false);
|
|
421
|
+
const [checking, setChecking] = useState4(false);
|
|
422
|
+
const [revision, setRevision] = useState4(0);
|
|
423
|
+
useEffect2(() => {
|
|
424
|
+
if (!paid) return;
|
|
425
|
+
let live = true, timer, attempt = 0;
|
|
426
|
+
setChecking(true);
|
|
427
|
+
const check = async () => {
|
|
428
|
+
try {
|
|
429
|
+
const me = await props.api("/api/me");
|
|
430
|
+
if (!live) return;
|
|
431
|
+
if (me.memberAccess === true) {
|
|
432
|
+
await props.onComplete();
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
} catch {
|
|
436
|
+
}
|
|
437
|
+
if (!live) return;
|
|
438
|
+
if (++attempt < 12) timer = setTimeout(() => void check(), 2500);
|
|
439
|
+
else setChecking(false);
|
|
440
|
+
};
|
|
441
|
+
void check();
|
|
442
|
+
return () => {
|
|
443
|
+
live = false;
|
|
444
|
+
clearTimeout(timer);
|
|
445
|
+
};
|
|
446
|
+
}, [paid, revision]);
|
|
447
|
+
const start = async () => {
|
|
448
|
+
setBusy(true);
|
|
449
|
+
setError("");
|
|
450
|
+
try {
|
|
451
|
+
const result = await props.api("/api/membership/restart", { method: "POST" });
|
|
452
|
+
if (!result.applicationId) throw new Error("We could not prepare your subscription. Please retry.");
|
|
453
|
+
setId(result.applicationId);
|
|
454
|
+
} catch (cause) {
|
|
455
|
+
setError(cause instanceof Error ? cause.message.slice(0, 300) : "We could not prepare your subscription. Please retry.");
|
|
456
|
+
} finally {
|
|
457
|
+
setBusy(false);
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
return /* @__PURE__ */ jsx5(JourneyFrame, { children: /* @__PURE__ */ jsxs5("section", { className: "card", "aria-label": "Restart membership", children: [
|
|
461
|
+
/* @__PURE__ */ jsx5("p", { className: "card-label", children: "Welcome back" }),
|
|
462
|
+
/* @__PURE__ */ jsx5("h2", { children: "Restart your membership" }),
|
|
463
|
+
/* @__PURE__ */ jsx5("p", { children: "Your account is ready, and your previous approval still counts. No new application or interview is needed." }),
|
|
464
|
+
/* @__PURE__ */ jsxs5("dl", { className: "journey-summary", children: [
|
|
465
|
+
/* @__PURE__ */ jsx5("dt", { children: "Name" }),
|
|
466
|
+
/* @__PURE__ */ jsx5("dd", { children: [props.application.firstName, props.application.lastName].filter(Boolean).join(" ") }),
|
|
467
|
+
/* @__PURE__ */ jsx5("dt", { children: "Email" }),
|
|
468
|
+
/* @__PURE__ */ jsx5("dd", { children: props.application.email })
|
|
469
|
+
] }),
|
|
470
|
+
paid ? /* @__PURE__ */ jsxs5("div", { role: "status", children: [
|
|
471
|
+
/* @__PURE__ */ jsx5("h3", { children: "Confirming your membership" }),
|
|
472
|
+
/* @__PURE__ */ jsx5("p", { children: "We\u2019re waiting for payment confirmation. Your membership will open here as soon as it arrives." }),
|
|
473
|
+
!checking ? /* @__PURE__ */ jsx5("button", { type: "button", onClick: () => setRevision((value) => value + 1), children: "Check membership" }) : null
|
|
474
|
+
] }) : 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" }),
|
|
475
|
+
error ? /* @__PURE__ */ jsx5("p", { role: "alert", children: error }) : null
|
|
476
|
+
] }) });
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// src/ui/members.tsx
|
|
480
|
+
import { useEffect as useEffect6, useState as useState9 } from "preact/hooks";
|
|
481
|
+
|
|
482
|
+
// src/ui/reschedule.tsx
|
|
483
|
+
import { useState as useState5 } from "preact/hooks";
|
|
484
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
|
|
485
|
+
function Rescheduler(props) {
|
|
486
|
+
const inheritedCopy = useChapterCopy();
|
|
487
|
+
const copy = props.copy ?? inheritedCopy.members.reschedule;
|
|
488
|
+
const { api, applicationId, timezone, onRescheduled, label = copy.changeTime } = props;
|
|
489
|
+
const [open, setOpen] = useState5(false);
|
|
490
|
+
const [slots, setSlots] = useState5(null);
|
|
491
|
+
const [tz, setTz] = useState5(timezone);
|
|
492
|
+
const [busy, setBusy] = useState5(false);
|
|
493
|
+
const [msg, setMsg] = useState5(null);
|
|
494
|
+
const start = async () => {
|
|
495
|
+
setOpen(true);
|
|
496
|
+
setSlots(null);
|
|
497
|
+
setMsg(null);
|
|
498
|
+
try {
|
|
499
|
+
const r = await api("/api/schedule/slots");
|
|
500
|
+
if (r.schedulingReady === false) {
|
|
501
|
+
setSlots([]);
|
|
502
|
+
setMsg(copy.unavailable);
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
setSlots(r.slots ?? []);
|
|
506
|
+
if (r.timezone) setTz(r.timezone);
|
|
507
|
+
} catch {
|
|
508
|
+
setSlots([]);
|
|
509
|
+
setMsg(copy.loadFailed);
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
const pick = async (slot) => {
|
|
513
|
+
setBusy(true);
|
|
514
|
+
setMsg(null);
|
|
515
|
+
try {
|
|
516
|
+
await api("/api/schedule/book", { method: "POST", body: JSON.stringify({ applicationId, startAt: slot.startAt }) });
|
|
517
|
+
setOpen(false);
|
|
518
|
+
await onRescheduled();
|
|
519
|
+
} catch (e) {
|
|
520
|
+
setMsg(e instanceof Error ? e.message : copy.slotGone);
|
|
521
|
+
} finally {
|
|
522
|
+
setBusy(false);
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
if (!open) {
|
|
526
|
+
return /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: /* @__PURE__ */ jsx6(
|
|
527
|
+
"a",
|
|
528
|
+
{
|
|
529
|
+
href: "#",
|
|
530
|
+
onClick: (e) => {
|
|
531
|
+
e.preventDefault();
|
|
532
|
+
void start();
|
|
533
|
+
},
|
|
534
|
+
children: label
|
|
535
|
+
}
|
|
536
|
+
) });
|
|
537
|
+
}
|
|
538
|
+
return /* @__PURE__ */ jsxs6("div", { className: "msched", children: [
|
|
539
|
+
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(
|
|
540
|
+
SlotPicker,
|
|
541
|
+
{
|
|
542
|
+
slots,
|
|
543
|
+
timezone: tz,
|
|
544
|
+
classes: { days: "msched-days", day: "msched-day", times: "msched-times", time: "msched-time" },
|
|
545
|
+
onPick: (s) => void pick(s)
|
|
546
|
+
}
|
|
547
|
+
),
|
|
548
|
+
busy ? /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: copy.rescheduling }) : null,
|
|
549
|
+
msg && slots && slots.length > 0 ? /* @__PURE__ */ jsx6("p", { className: "meeting-note error", children: msg }) : null,
|
|
550
|
+
/* @__PURE__ */ jsx6("p", { className: "meeting-note", children: /* @__PURE__ */ jsx6(
|
|
551
|
+
"a",
|
|
552
|
+
{
|
|
553
|
+
href: "#",
|
|
554
|
+
onClick: (e) => {
|
|
555
|
+
e.preventDefault();
|
|
556
|
+
setOpen(false);
|
|
557
|
+
},
|
|
558
|
+
children: copy.keepTime
|
|
559
|
+
}
|
|
560
|
+
) })
|
|
561
|
+
] });
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// src/ui/member-gifts.tsx
|
|
565
|
+
import { useEffect as useEffect3, useRef as useRef2, useState as useState6 } from "preact/hooks";
|
|
566
|
+
|
|
567
|
+
// src/ui/gift-offer-cards.tsx
|
|
568
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
|
|
569
|
+
var price = (cents, currency) => currency === "usd" ? fmtMoney(cents) : new Intl.NumberFormat(void 0, { style: "currency", currency: currency.toUpperCase() }).format(cents / 100);
|
|
570
|
+
function GiftOfferCards(props) {
|
|
571
|
+
const mode = props.mode ?? "preview";
|
|
572
|
+
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: [
|
|
573
|
+
/* @__PURE__ */ jsx7("div", { className: "card-label", children: offer.title }),
|
|
574
|
+
/* @__PURE__ */ jsx7("p", { children: offer.description }),
|
|
575
|
+
/* @__PURE__ */ jsxs7("p", { className: "meeting-date", children: [
|
|
576
|
+
price(offer.priceCents, offer.currency),
|
|
577
|
+
offer.billingMode === "subscription" ? " recurring" : ""
|
|
578
|
+
] }),
|
|
579
|
+
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 })
|
|
580
|
+
] }, offer.id)) });
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// src/ui/member-gifts.tsx
|
|
584
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
|
|
373
585
|
function GiftPurchases(props) {
|
|
374
|
-
const [data, setData] =
|
|
375
|
-
const [selected, setSelected] =
|
|
376
|
-
const [code, setCode] =
|
|
377
|
-
const [message, setMessage] =
|
|
586
|
+
const [data, setData] = useState6(null);
|
|
587
|
+
const [selected, setSelected] = useState6(null);
|
|
588
|
+
const [code, setCode] = useState6("");
|
|
589
|
+
const [message, setMessage] = useState6("");
|
|
378
590
|
const purchaseId = useRef2(crypto.randomUUID());
|
|
379
591
|
const load = async () => setData(await props.api("/api/gifts"));
|
|
380
|
-
|
|
592
|
+
useEffect3(() => {
|
|
381
593
|
void load().catch(() => setData({ offers: [], claims: [] }));
|
|
382
594
|
}, []);
|
|
383
595
|
const rotate = async (claimId) => {
|
|
@@ -392,16 +604,16 @@ function GiftPurchases(props) {
|
|
|
392
604
|
if (!data) return null;
|
|
393
605
|
if (data.offers.length === 0 && data.claims.length === 0) return null;
|
|
394
606
|
const offer = data.offers.find((item) => item.id === selected);
|
|
395
|
-
return /* @__PURE__ */
|
|
396
|
-
data.offers.length ? /* @__PURE__ */
|
|
397
|
-
/* @__PURE__ */
|
|
398
|
-
/* @__PURE__ */
|
|
399
|
-
/* @__PURE__ */
|
|
607
|
+
return /* @__PURE__ */ jsxs8("section", { className: "member-gifts", children: [
|
|
608
|
+
data.offers.length ? /* @__PURE__ */ jsxs8("div", { className: "card", children: [
|
|
609
|
+
/* @__PURE__ */ jsx8("div", { className: "card-label", children: props.copy.title }),
|
|
610
|
+
/* @__PURE__ */ jsx8("p", { children: props.copy.body }),
|
|
611
|
+
/* @__PURE__ */ jsx8(GiftOfferCards, { offers: data.offers, mode: "select", selectedOfferId: selected, onSelect: (id) => {
|
|
400
612
|
setSelected(id);
|
|
401
613
|
setCode("");
|
|
402
614
|
purchaseId.current = crypto.randomUUID();
|
|
403
615
|
} }),
|
|
404
|
-
offer ? /* @__PURE__ */
|
|
616
|
+
offer ? /* @__PURE__ */ jsx8(
|
|
405
617
|
PaymentStep,
|
|
406
618
|
{
|
|
407
619
|
applicationId: purchaseId.current,
|
|
@@ -421,31 +633,31 @@ function GiftPurchases(props) {
|
|
|
421
633
|
}
|
|
422
634
|
}
|
|
423
635
|
) : null,
|
|
424
|
-
code ? /* @__PURE__ */
|
|
425
|
-
/* @__PURE__ */
|
|
426
|
-
/* @__PURE__ */
|
|
636
|
+
code ? /* @__PURE__ */ jsxs8("div", { className: "gift-code-once", children: [
|
|
637
|
+
/* @__PURE__ */ jsx8("output", { children: code }),
|
|
638
|
+
/* @__PURE__ */ jsx8("p", { children: props.copy.saveCode })
|
|
427
639
|
] }) : null
|
|
428
640
|
] }) : 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__ */
|
|
641
|
+
/* @__PURE__ */ jsxs8("div", { className: "card", children: [
|
|
642
|
+
/* @__PURE__ */ jsx8("div", { className: "card-label", children: props.copy.purchases }),
|
|
643
|
+
data.claims.length ? data.claims.map((claim) => /* @__PURE__ */ jsxs8("div", { className: "member-row", children: [
|
|
644
|
+
/* @__PURE__ */ jsx8("span", { children: claim.offerId }),
|
|
645
|
+
/* @__PURE__ */ jsx8("span", { children: props.copy[claim.status] }),
|
|
646
|
+
claim.status === "pending" ? /* @__PURE__ */ jsx8("button", { className: "btn secondary mini", onClick: () => void rotate(claim.id), children: props.copy.rotate }) : null
|
|
647
|
+
] }, claim.id)) : /* @__PURE__ */ jsx8("p", { children: props.copy.noPurchases }),
|
|
648
|
+
message ? /* @__PURE__ */ jsx8("p", { role: "status", children: message }) : null
|
|
437
649
|
] })
|
|
438
650
|
] });
|
|
439
651
|
}
|
|
440
652
|
var MemberGifts = GiftPurchases;
|
|
441
653
|
|
|
442
654
|
// src/ui/member-named-seat.tsx
|
|
443
|
-
import { useEffect as
|
|
444
|
-
import { Fragment as
|
|
655
|
+
import { useEffect as useEffect4, useState as useState7 } from "preact/hooks";
|
|
656
|
+
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
|
|
445
657
|
function NamedSeatPurchase({ api }) {
|
|
446
|
-
const [data, setData] =
|
|
447
|
-
const [name, setName] =
|
|
448
|
-
const [terms, setTerms] =
|
|
658
|
+
const [data, setData] = useState7(null), [error, setError] = useState7("");
|
|
659
|
+
const [name, setName] = useState7(""), [email, setEmail] = useState7(""), [reviewing, setReviewing] = useState7(false);
|
|
660
|
+
const [terms, setTerms] = useState7(false), [pending, setPending] = useState7(false);
|
|
449
661
|
const load = async () => {
|
|
450
662
|
try {
|
|
451
663
|
const value = await api("/api/named-seat");
|
|
@@ -459,23 +671,23 @@ function NamedSeatPurchase({ api }) {
|
|
|
459
671
|
setError("The named-seat service is unavailable. Refresh to check your purchase before trying again.");
|
|
460
672
|
}
|
|
461
673
|
};
|
|
462
|
-
|
|
674
|
+
useEffect4(() => {
|
|
463
675
|
void load();
|
|
464
676
|
}, []);
|
|
465
677
|
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__ */
|
|
678
|
+
return /* @__PURE__ */ jsx9(JourneyFrame, { children: /* @__PURE__ */ jsxs9("section", { className: "card member-named-seat", "aria-label": "Named additional seat", children: [
|
|
679
|
+
/* @__PURE__ */ jsx9("h2", { children: "Named additional seat" }),
|
|
680
|
+
error ? /* @__PURE__ */ jsx9("p", { role: "alert", children: error }) : null,
|
|
681
|
+
data ? /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
682
|
+
data.seat ? /* @__PURE__ */ jsxs9("p", { children: [
|
|
471
683
|
data.seat.recipientName,
|
|
472
684
|
" \xB7 ",
|
|
473
685
|
data.seat.recipientEmail,
|
|
474
686
|
" \xB7 ",
|
|
475
687
|
data.seat.status.replaceAll("_", " ")
|
|
476
688
|
] }) : null,
|
|
477
|
-
data.eligible ? /* @__PURE__ */
|
|
478
|
-
/* @__PURE__ */
|
|
689
|
+
data.eligible ? /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
690
|
+
/* @__PURE__ */ jsxs9("p", { children: [
|
|
479
691
|
money,
|
|
480
692
|
" paid in full now. This seat ",
|
|
481
693
|
data.autoRenew ? "renews with your primary membership" : "ends with your primary membership",
|
|
@@ -486,38 +698,38 @@ function NamedSeatPurchase({ api }) {
|
|
|
486
698
|
" ",
|
|
487
699
|
"It belongs to one named person and cannot be reassigned."
|
|
488
700
|
] }),
|
|
489
|
-
/* @__PURE__ */
|
|
490
|
-
!reviewing ? /* @__PURE__ */
|
|
701
|
+
/* @__PURE__ */ jsx9("p", { children: "The recipient must accept and complete their own application and any required interview. The seat stays open for them while your membership is paid; it is not refunded automatically. Contact the chapter if you need a refund." }),
|
|
702
|
+
!reviewing ? /* @__PURE__ */ jsxs9("form", { onSubmit: (event) => {
|
|
491
703
|
event.preventDefault();
|
|
492
704
|
setReviewing(true);
|
|
493
705
|
setTerms(false);
|
|
494
706
|
}, children: [
|
|
495
|
-
/* @__PURE__ */
|
|
707
|
+
/* @__PURE__ */ jsxs9("label", { children: [
|
|
496
708
|
"Recipient name",
|
|
497
|
-
/* @__PURE__ */
|
|
709
|
+
/* @__PURE__ */ jsx9("input", { required: true, maxLength: 160, value: name, disabled: Boolean(data.seat), onInput: (event) => setName(event.currentTarget.value) })
|
|
498
710
|
] }),
|
|
499
|
-
/* @__PURE__ */
|
|
711
|
+
/* @__PURE__ */ jsxs9("label", { children: [
|
|
500
712
|
"Recipient email",
|
|
501
|
-
/* @__PURE__ */
|
|
713
|
+
/* @__PURE__ */ jsx9("input", { required: true, type: "email", maxLength: 254, value: email, disabled: Boolean(data.seat), onInput: (event) => setEmail(event.currentTarget.value) })
|
|
502
714
|
] }),
|
|
503
|
-
/* @__PURE__ */
|
|
504
|
-
] }) : /* @__PURE__ */
|
|
505
|
-
/* @__PURE__ */
|
|
715
|
+
/* @__PURE__ */ jsx9("button", { className: "btn primary", type: "submit", children: "Review named seat" })
|
|
716
|
+
] }) : /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
717
|
+
/* @__PURE__ */ jsxs9("p", { children: [
|
|
506
718
|
"For ",
|
|
507
719
|
name,
|
|
508
720
|
" \xB7 ",
|
|
509
721
|
email
|
|
510
722
|
] }),
|
|
511
|
-
/* @__PURE__ */
|
|
723
|
+
/* @__PURE__ */ jsx9("button", { className: "btn secondary", type: "button", onClick: () => {
|
|
512
724
|
setReviewing(false);
|
|
513
725
|
setTerms(false);
|
|
514
726
|
void load();
|
|
515
727
|
}, 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."
|
|
728
|
+
/* @__PURE__ */ jsxs9("label", { className: "journey-consent", children: [
|
|
729
|
+
/* @__PURE__ */ jsx9("input", { type: "checkbox", checked: terms, onChange: (event) => setTerms(event.currentTarget.checked) }),
|
|
730
|
+
/* @__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
731
|
] }),
|
|
520
|
-
terms ? /* @__PURE__ */
|
|
732
|
+
terms ? /* @__PURE__ */ jsx9(
|
|
521
733
|
PaymentStep,
|
|
522
734
|
{
|
|
523
735
|
applicationId: data.membershipId,
|
|
@@ -536,17 +748,21 @@ function NamedSeatPurchase({ api }) {
|
|
|
536
748
|
}
|
|
537
749
|
) : null
|
|
538
750
|
] })
|
|
539
|
-
] }) : !data.seat ? /* @__PURE__ */
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
751
|
+
] }) : !data.seat ? /* @__PURE__ */ jsxs9("p", { children: [
|
|
752
|
+
"Additional seats can be purchased until ",
|
|
753
|
+
new Date(data.purchaseEndsAt).toLocaleDateString("en-US", { timeZone: "UTC" }),
|
|
754
|
+
"."
|
|
755
|
+
] }) : null,
|
|
756
|
+
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
|
|
757
|
+
] }) : !error ? /* @__PURE__ */ jsx9("p", { children: "Loading your seat terms\u2026" }) : null,
|
|
758
|
+
/* @__PURE__ */ jsx9("button", { className: "btn secondary", onClick: () => void load(), children: "Refresh seat status" })
|
|
759
|
+
] }) });
|
|
544
760
|
}
|
|
545
761
|
|
|
546
762
|
// src/ui/member-content.tsx
|
|
547
|
-
import { useEffect as
|
|
763
|
+
import { useEffect as useEffect5, useMemo as useMemo2, useState as useState8 } from "preact/hooks";
|
|
548
764
|
import { Markdown } from "@odla-ai/ui/components";
|
|
549
|
-
import { Fragment as
|
|
765
|
+
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
|
|
550
766
|
var pageLabel = (page) => `${page.title}${page.access === "locked" ? " \xB7 Locked" : ""}`;
|
|
551
767
|
function MemberContentArea(props) {
|
|
552
768
|
const {
|
|
@@ -554,15 +770,15 @@ function MemberContentArea(props) {
|
|
|
554
770
|
path = "/api/member-content",
|
|
555
771
|
upsellHref,
|
|
556
772
|
onUpsell,
|
|
557
|
-
loadingContent = /* @__PURE__ */
|
|
558
|
-
emptyContent = /* @__PURE__ */
|
|
773
|
+
loadingContent = /* @__PURE__ */ jsx10("p", { className: "meeting-note", children: "Loading member pages\u2026" }),
|
|
774
|
+
emptyContent = /* @__PURE__ */ jsx10("p", { className: "meeting-note", children: "No member pages have been published yet." })
|
|
559
775
|
} = props;
|
|
560
|
-
const [data, setData] =
|
|
561
|
-
const [error, setError] =
|
|
562
|
-
const [selectedId, setSelectedId] =
|
|
776
|
+
const [data, setData] = useState8(props.initialData ?? null);
|
|
777
|
+
const [error, setError] = useState8(null);
|
|
778
|
+
const [selectedId, setSelectedId] = useState8(
|
|
563
779
|
props.initialPageId ?? props.initialData?.pages[0]?.id ?? ""
|
|
564
780
|
);
|
|
565
|
-
|
|
781
|
+
useEffect5(() => {
|
|
566
782
|
if (props.initialData) return;
|
|
567
783
|
let live = true;
|
|
568
784
|
setError(null);
|
|
@@ -584,18 +800,18 @@ function MemberContentArea(props) {
|
|
|
584
800
|
}
|
|
585
801
|
return [...result.entries()];
|
|
586
802
|
}, [data]);
|
|
587
|
-
if (error) return /* @__PURE__ */
|
|
803
|
+
if (error) return /* @__PURE__ */ jsxs10("p", { className: "meeting-note", role: "alert", children: [
|
|
588
804
|
"Member pages could not be loaded: ",
|
|
589
805
|
error
|
|
590
806
|
] });
|
|
591
|
-
if (!data) return /* @__PURE__ */
|
|
592
|
-
if (data.pages.length === 0) return /* @__PURE__ */
|
|
807
|
+
if (!data) return /* @__PURE__ */ jsx10(Fragment4, { children: loadingContent });
|
|
808
|
+
if (data.pages.length === 0) return /* @__PURE__ */ jsx10(Fragment4, { children: emptyContent });
|
|
593
809
|
const selected = data.pages.find((page) => page.id === selectedId) ?? data.pages[0];
|
|
594
810
|
const href = selected.upsell && upsellHref ? upsellHref(selected.upsell.tierId, selected) : void 0;
|
|
595
|
-
return /* @__PURE__ */
|
|
596
|
-
/* @__PURE__ */
|
|
597
|
-
/* @__PURE__ */
|
|
598
|
-
/* @__PURE__ */
|
|
811
|
+
return /* @__PURE__ */ jsxs10("div", { className: "chapter-member-content", "data-member-content": true, children: [
|
|
812
|
+
/* @__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: [
|
|
813
|
+
/* @__PURE__ */ jsx10("h2", { children: section }),
|
|
814
|
+
/* @__PURE__ */ jsx10("ul", { children: pages.map((page) => /* @__PURE__ */ jsx10("li", { "data-parent-page": page.navigation.parentId ?? void 0, children: /* @__PURE__ */ jsx10(
|
|
599
815
|
"button",
|
|
600
816
|
{
|
|
601
817
|
type: "button",
|
|
@@ -605,23 +821,23 @@ function MemberContentArea(props) {
|
|
|
605
821
|
}
|
|
606
822
|
) }, page.id)) })
|
|
607
823
|
] }, section)) }),
|
|
608
|
-
/* @__PURE__ */
|
|
609
|
-
/* @__PURE__ */
|
|
610
|
-
/* @__PURE__ */
|
|
824
|
+
/* @__PURE__ */ jsxs10("article", { className: "chapter-member-content-page", "data-access": selected.access, children: [
|
|
825
|
+
/* @__PURE__ */ jsxs10("header", { children: [
|
|
826
|
+
/* @__PURE__ */ jsxs10("div", { className: "card-label", children: [
|
|
611
827
|
selected.source.type === "parent" ? "Parent" : "Chapter",
|
|
612
828
|
" \xB7 ",
|
|
613
829
|
selected.access
|
|
614
830
|
] }),
|
|
615
|
-
/* @__PURE__ */
|
|
616
|
-
selected.summary ? /* @__PURE__ */
|
|
831
|
+
/* @__PURE__ */ jsx10("h1", { children: selected.title }),
|
|
832
|
+
selected.summary ? /* @__PURE__ */ jsx10("p", { children: selected.summary }) : null
|
|
617
833
|
] }),
|
|
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__ */
|
|
834
|
+
selected.access === "allowed" && selected.bodyMarkdown ? /* @__PURE__ */ jsx10(Markdown, { source: selected.bodyMarkdown }) : /* @__PURE__ */ jsxs10("div", { className: "chapter-member-content-locked", children: [
|
|
835
|
+
selected.teaserMarkdown ? /* @__PURE__ */ jsx10(Markdown, { source: selected.teaserMarkdown }) : /* @__PURE__ */ jsx10("p", { children: "This page is not included in your current membership." }),
|
|
836
|
+
selected.upsell ? /* @__PURE__ */ jsxs10("aside", { className: "chapter-member-content-upsell", "aria-label": selected.upsell.label ?? "Membership option", children: [
|
|
837
|
+
/* @__PURE__ */ jsx10("h2", { children: selected.upsell.label ?? selected.upsell.tierName }),
|
|
838
|
+
/* @__PURE__ */ jsx10("p", { children: fmtMoney(selected.upsell.priceCents) }),
|
|
839
|
+
selected.upsell.bodyMarkdown ? /* @__PURE__ */ jsx10(Markdown, { source: selected.upsell.bodyMarkdown }) : null,
|
|
840
|
+
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
841
|
] }) : null
|
|
626
842
|
] })
|
|
627
843
|
] })
|
|
@@ -629,12 +845,12 @@ function MemberContentArea(props) {
|
|
|
629
845
|
}
|
|
630
846
|
|
|
631
847
|
// src/ui/members.tsx
|
|
632
|
-
import { Fragment as
|
|
848
|
+
import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
|
|
633
849
|
function card(copy, kicker, body) {
|
|
634
|
-
return /* @__PURE__ */
|
|
635
|
-
/* @__PURE__ */
|
|
636
|
-
/* @__PURE__ */
|
|
637
|
-
/* @__PURE__ */
|
|
850
|
+
return /* @__PURE__ */ jsxs11("div", { className: "card", children: [
|
|
851
|
+
/* @__PURE__ */ jsx11("div", { className: "card-label", children: copy.provisional.cardLabel }),
|
|
852
|
+
/* @__PURE__ */ jsxs11("div", { className: "meeting-block", children: [
|
|
853
|
+
/* @__PURE__ */ jsx11("div", { className: "meeting-kicker", children: kicker }),
|
|
638
854
|
body
|
|
639
855
|
] })
|
|
640
856
|
] });
|
|
@@ -645,9 +861,9 @@ function ProvisionalCard(props) {
|
|
|
645
861
|
return card(
|
|
646
862
|
copy,
|
|
647
863
|
copy.provisional.applicationNeeded,
|
|
648
|
-
/* @__PURE__ */
|
|
649
|
-
/* @__PURE__ */
|
|
650
|
-
/* @__PURE__ */
|
|
864
|
+
/* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
865
|
+
/* @__PURE__ */ jsx11("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
|
|
866
|
+
/* @__PURE__ */ jsx11("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
|
|
651
867
|
] })
|
|
652
868
|
);
|
|
653
869
|
}
|
|
@@ -655,19 +871,19 @@ function ProvisionalCard(props) {
|
|
|
655
871
|
return card(
|
|
656
872
|
copy,
|
|
657
873
|
copy.provisional.refunded,
|
|
658
|
-
/* @__PURE__ */
|
|
874
|
+
/* @__PURE__ */ jsx11("div", { className: "meeting-note", children: copy.provisional.refundedBody })
|
|
659
875
|
);
|
|
660
876
|
}
|
|
661
|
-
const membership = application.paid ? /* @__PURE__ */
|
|
877
|
+
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
878
|
if (application.meetingAt) {
|
|
663
879
|
return card(
|
|
664
880
|
copy,
|
|
665
881
|
copy.provisional.introductionCall,
|
|
666
|
-
/* @__PURE__ */
|
|
667
|
-
/* @__PURE__ */
|
|
668
|
-
/* @__PURE__ */
|
|
669
|
-
application.meetUrl ? /* @__PURE__ */
|
|
670
|
-
/* @__PURE__ */
|
|
882
|
+
/* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
883
|
+
/* @__PURE__ */ jsx11("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
|
|
884
|
+
/* @__PURE__ */ jsx11("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
|
|
885
|
+
application.meetUrl ? /* @__PURE__ */ jsx11("div", { className: "meeting-note", children: /* @__PURE__ */ jsx11("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
|
|
886
|
+
/* @__PURE__ */ jsx11(
|
|
671
887
|
Rescheduler,
|
|
672
888
|
{
|
|
673
889
|
api,
|
|
@@ -684,9 +900,9 @@ function ProvisionalCard(props) {
|
|
|
684
900
|
return card(
|
|
685
901
|
copy,
|
|
686
902
|
copy.provisional.bookCall,
|
|
687
|
-
/* @__PURE__ */
|
|
688
|
-
/* @__PURE__ */
|
|
689
|
-
/* @__PURE__ */
|
|
903
|
+
/* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
904
|
+
/* @__PURE__ */ jsx11("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
|
|
905
|
+
/* @__PURE__ */ jsx11(
|
|
690
906
|
Rescheduler,
|
|
691
907
|
{
|
|
692
908
|
api,
|
|
@@ -713,8 +929,8 @@ function MembersArea(props) {
|
|
|
713
929
|
renderProvisional
|
|
714
930
|
} = props;
|
|
715
931
|
const copy = props.copy ?? inheritedCopy.members;
|
|
716
|
-
const [me, setMe] =
|
|
717
|
-
const [error, setError] =
|
|
932
|
+
const [me, setMe] = useState9(null);
|
|
933
|
+
const [error, setError] = useState9(false);
|
|
718
934
|
const reload = async () => {
|
|
719
935
|
try {
|
|
720
936
|
setMe(await api("/api/me"));
|
|
@@ -722,25 +938,25 @@ function MembersArea(props) {
|
|
|
722
938
|
setError(true);
|
|
723
939
|
}
|
|
724
940
|
};
|
|
725
|
-
|
|
941
|
+
useEffect6(() => {
|
|
726
942
|
void reload();
|
|
727
943
|
}, []);
|
|
728
|
-
if (error) return /* @__PURE__ */
|
|
729
|
-
if (!me) return /* @__PURE__ */
|
|
944
|
+
if (error) return /* @__PURE__ */ jsx11("p", { className: "meeting-note", children: copy.loadFailed });
|
|
945
|
+
if (!me) return /* @__PURE__ */ jsx11("p", { className: "meeting-note", children: inheritedCopy.common.loading });
|
|
730
946
|
const role = me.role || "provisional";
|
|
731
|
-
return /* @__PURE__ */
|
|
732
|
-
/* @__PURE__ */
|
|
733
|
-
/* @__PURE__ */
|
|
734
|
-
/* @__PURE__ */
|
|
735
|
-
/* @__PURE__ */
|
|
947
|
+
return /* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
948
|
+
/* @__PURE__ */ jsxs11("div", { className: "card", children: [
|
|
949
|
+
/* @__PURE__ */ jsxs11("div", { className: "member-row", children: [
|
|
950
|
+
/* @__PURE__ */ jsx11("span", { className: "member-email", children: me.email }),
|
|
951
|
+
/* @__PURE__ */ jsx11("span", { className: "role-badge " + role, children: role })
|
|
736
952
|
] }),
|
|
737
|
-
/* @__PURE__ */
|
|
738
|
-
/* @__PURE__ */
|
|
739
|
-
me.authorized || me.superAdmin ? /* @__PURE__ */
|
|
953
|
+
/* @__PURE__ */ jsxs11("div", { className: "account-actions", children: [
|
|
954
|
+
/* @__PURE__ */ jsx11("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
|
|
955
|
+
me.authorized || me.superAdmin ? /* @__PURE__ */ jsx11("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
|
|
740
956
|
] })
|
|
741
957
|
] }),
|
|
742
|
-
me.memberAccess !== true ? (() => {
|
|
743
|
-
const defaultContent = /* @__PURE__ */
|
|
958
|
+
me.memberAccess !== true && me.membershipRestart?.eligible && me.application ? /* @__PURE__ */ jsx11(MemberRestart, { api, application: me.application, applicationId: me.membershipRestart.applicationId, onComplete: reload }) : me.memberAccess !== true ? (() => {
|
|
959
|
+
const defaultContent = /* @__PURE__ */ jsx11(
|
|
744
960
|
ProvisionalCard,
|
|
745
961
|
{
|
|
746
962
|
api,
|
|
@@ -757,128 +973,30 @@ function MembersArea(props) {
|
|
|
757
973
|
reload,
|
|
758
974
|
defaultContent
|
|
759
975
|
}) ?? defaultContent;
|
|
760
|
-
})() : memberContent ?? (memberPages ? /* @__PURE__ */
|
|
976
|
+
})() : memberContent ?? (memberPages ? /* @__PURE__ */ jsx11(
|
|
761
977
|
MemberContentArea,
|
|
762
978
|
{
|
|
763
979
|
api,
|
|
764
980
|
...memberPages === true ? {} : memberPages
|
|
765
981
|
}
|
|
766
|
-
) : /* @__PURE__ */
|
|
767
|
-
/* @__PURE__ */
|
|
768
|
-
me.namedSeatsEnabled ? /* @__PURE__ */
|
|
982
|
+
) : /* @__PURE__ */ jsx11("div", { className: "card", children: /* @__PURE__ */ jsx11("div", { className: "card-label", children: copy.full.welcome }) })),
|
|
983
|
+
/* @__PURE__ */ jsx11(GiftPurchases, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment }),
|
|
984
|
+
me.namedSeatsEnabled ? /* @__PURE__ */ jsx11(NamedSeatPurchase, { api }) : null
|
|
769
985
|
] });
|
|
770
986
|
}
|
|
771
987
|
|
|
772
988
|
// 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
|
-
}
|
|
989
|
+
import { useEffect as useEffect10, useRef as useRef3, useState as useState16 } from "preact/hooks";
|
|
872
990
|
|
|
873
991
|
// src/ui/join-booking.tsx
|
|
874
|
-
import { useEffect as
|
|
875
|
-
import { jsx as
|
|
992
|
+
import { useEffect as useEffect7, useState as useState10 } from "preact/hooks";
|
|
993
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
|
|
876
994
|
function JoinBooking(props) {
|
|
877
995
|
const { applicationId, copy, onBooked, simulation } = props;
|
|
878
|
-
const [state, setState] =
|
|
879
|
-
const [msg, setMsg] =
|
|
880
|
-
const [busy, setBusy] =
|
|
881
|
-
const [selected, setSelected] =
|
|
996
|
+
const [state, setState] = useState10(null);
|
|
997
|
+
const [msg, setMsg] = useState10(null);
|
|
998
|
+
const [busy, setBusy] = useState10(false);
|
|
999
|
+
const [selected, setSelected] = useState10(null);
|
|
882
1000
|
const load = async () => {
|
|
883
1001
|
setMsg(null);
|
|
884
1002
|
try {
|
|
@@ -903,7 +1021,7 @@ function JoinBooking(props) {
|
|
|
903
1021
|
setMsg(copy.loadFailed);
|
|
904
1022
|
}
|
|
905
1023
|
};
|
|
906
|
-
|
|
1024
|
+
useEffect7(() => {
|
|
907
1025
|
void load();
|
|
908
1026
|
}, [simulation]);
|
|
909
1027
|
const book = async () => {
|
|
@@ -935,9 +1053,11 @@ function JoinBooking(props) {
|
|
|
935
1053
|
setBusy(false);
|
|
936
1054
|
}
|
|
937
1055
|
};
|
|
938
|
-
if (!state) return /* @__PURE__ */
|
|
939
|
-
return /* @__PURE__ */
|
|
940
|
-
/* @__PURE__ */
|
|
1056
|
+
if (!state) return /* @__PURE__ */ jsx12("p", { className: "slots-status", children: msg ?? copy.loading });
|
|
1057
|
+
return /* @__PURE__ */ jsxs12("div", { className: "join-book", children: [
|
|
1058
|
+
/* @__PURE__ */ jsx12("h2", { children: copy.title ?? DEFAULT_JOIN_COPY.booking.title }),
|
|
1059
|
+
/* @__PURE__ */ jsx12("p", { children: copy.intro ?? DEFAULT_JOIN_COPY.booking.intro }),
|
|
1060
|
+
/* @__PURE__ */ jsx12(
|
|
941
1061
|
SlotPicker,
|
|
942
1062
|
{
|
|
943
1063
|
slots: state.slots,
|
|
@@ -947,29 +1067,29 @@ function JoinBooking(props) {
|
|
|
947
1067
|
onDayChange: () => setSelected(null)
|
|
948
1068
|
}
|
|
949
1069
|
),
|
|
950
|
-
/* @__PURE__ */
|
|
951
|
-
/* @__PURE__ */
|
|
952
|
-
msg ? /* @__PURE__ */
|
|
1070
|
+
/* @__PURE__ */ jsxs12("div", { className: "slot-confirm", hidden: !selected, children: [
|
|
1071
|
+
/* @__PURE__ */ jsx12("button", { className: "submit-btn", disabled: busy, onClick: () => void book(), children: busy ? copy.booking : copy.book }),
|
|
1072
|
+
msg ? /* @__PURE__ */ jsx12("p", { className: "step2-note", children: msg }) : null
|
|
953
1073
|
] })
|
|
954
1074
|
] });
|
|
955
1075
|
}
|
|
956
1076
|
|
|
957
1077
|
// src/ui/join-accepted.tsx
|
|
958
|
-
import { jsx as
|
|
1078
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
|
|
959
1079
|
function JoinAccepted(props) {
|
|
960
|
-
return /* @__PURE__ */
|
|
961
|
-
/* @__PURE__ */
|
|
962
|
-
/* @__PURE__ */
|
|
963
|
-
/* @__PURE__ */
|
|
1080
|
+
return /* @__PURE__ */ jsxs13("div", { className: "join-done card", children: [
|
|
1081
|
+
/* @__PURE__ */ jsx13("div", { className: "card-label", children: props.copy.accepted.label }),
|
|
1082
|
+
/* @__PURE__ */ jsx13("p", { className: "meeting-note", children: props.copy.accepted.body }),
|
|
1083
|
+
/* @__PURE__ */ jsx13("a", { className: "apply-link", href: props.membersHref, children: props.copy.done.memberArea })
|
|
964
1084
|
] });
|
|
965
1085
|
}
|
|
966
1086
|
|
|
967
1087
|
// src/ui/gift-claim-card.tsx
|
|
968
|
-
import { useState as
|
|
969
|
-
import { Fragment as Fragment6, jsx as
|
|
1088
|
+
import { useState as useState11 } from "preact/hooks";
|
|
1089
|
+
import { Fragment as Fragment6, jsx as jsx14, jsxs as jsxs14 } from "preact/jsx-runtime";
|
|
970
1090
|
function GiftClaimCard(props) {
|
|
971
|
-
const [code, setCode] =
|
|
972
|
-
const [error, setError] =
|
|
1091
|
+
const [code, setCode] = useState11(props.initialCode ?? "");
|
|
1092
|
+
const [error, setError] = useState11(false);
|
|
973
1093
|
const rotate = async () => {
|
|
974
1094
|
if (!props.claimId) return;
|
|
975
1095
|
setError(false);
|
|
@@ -982,15 +1102,83 @@ function GiftClaimCard(props) {
|
|
|
982
1102
|
if (response.ok && body.code) setCode(body.code);
|
|
983
1103
|
else setError(true);
|
|
984
1104
|
};
|
|
985
|
-
return /* @__PURE__ */
|
|
986
|
-
/* @__PURE__ */
|
|
987
|
-
/* @__PURE__ */
|
|
988
|
-
code ? /* @__PURE__ */
|
|
989
|
-
/* @__PURE__ */
|
|
990
|
-
/* @__PURE__ */
|
|
1105
|
+
return /* @__PURE__ */ jsxs14("div", { className: "join-done card", children: [
|
|
1106
|
+
/* @__PURE__ */ jsx14("div", { className: "card-label", children: props.copy.label }),
|
|
1107
|
+
/* @__PURE__ */ jsx14("p", { className: "meeting-note", children: props.copy.body }),
|
|
1108
|
+
code ? /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
1109
|
+
/* @__PURE__ */ jsx14("output", { className: "gift-code", children: code }),
|
|
1110
|
+
/* @__PURE__ */ jsx14("p", { children: props.copy.save })
|
|
991
1111
|
] }) : null,
|
|
992
|
-
!code && props.claimId ? /* @__PURE__ */
|
|
993
|
-
error ? /* @__PURE__ */
|
|
1112
|
+
!code && props.claimId ? /* @__PURE__ */ jsx14("button", { type: "button", className: "btn secondary", onClick: () => void rotate(), children: props.copy.rotate }) : null,
|
|
1113
|
+
error ? /* @__PURE__ */ jsx14("p", { role: "alert", children: props.copy.rotateFailed }) : null
|
|
1114
|
+
] });
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// src/ui/join-tiers.tsx
|
|
1118
|
+
import { useState as useState12 } from "preact/hooks";
|
|
1119
|
+
import { Fragment as Fragment7, jsx as jsx15, jsxs as jsxs15 } from "preact/jsx-runtime";
|
|
1120
|
+
var joinTierMoney = (cents, currency = "usd") => new Intl.NumberFormat("en-US", { style: "currency", currency }).format(cents / 100);
|
|
1121
|
+
function useTierSelection(tiers, initialTierId) {
|
|
1122
|
+
const [selectedTierId, setSelectedTierId] = useState12(() => {
|
|
1123
|
+
const preset = tiers.find((tier) => tier.id === initialTierId);
|
|
1124
|
+
if (preset) return preset.id;
|
|
1125
|
+
return tiers.length === 1 ? tiers[0].id : null;
|
|
1126
|
+
});
|
|
1127
|
+
return {
|
|
1128
|
+
tiers,
|
|
1129
|
+
selected: tiers.find((tier) => tier.id === selectedTierId) ?? null,
|
|
1130
|
+
selectedTierId,
|
|
1131
|
+
selectTier: (tierId) => {
|
|
1132
|
+
if (tiers.some((tier) => tier.id === tierId)) setSelectedTierId(tierId);
|
|
1133
|
+
}
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
function TierPlaceholder(context) {
|
|
1137
|
+
return /* @__PURE__ */ jsxs15("fieldset", { "data-chapter-placeholder": "tiers", children: [
|
|
1138
|
+
/* @__PURE__ */ jsx15("legend", { children: "Membership (placeholder \u2014 pass renderTiers to style this)" }),
|
|
1139
|
+
context.tiers.map((tier) => /* @__PURE__ */ jsxs15("label", { children: [
|
|
1140
|
+
/* @__PURE__ */ jsx15(
|
|
1141
|
+
"input",
|
|
1142
|
+
{
|
|
1143
|
+
type: "radio",
|
|
1144
|
+
name: "__chapterTier",
|
|
1145
|
+
value: tier.id,
|
|
1146
|
+
checked: context.selectedTierId === tier.id,
|
|
1147
|
+
onChange: () => context.selectTier(tier.id)
|
|
1148
|
+
}
|
|
1149
|
+
),
|
|
1150
|
+
tier.name,
|
|
1151
|
+
tier.founding ? /* @__PURE__ */ jsxs15(Fragment7, { children: [
|
|
1152
|
+
" \u2014 ",
|
|
1153
|
+
joinTierMoney(tier.founding.dueTodayCents),
|
|
1154
|
+
" founding member rate (list ",
|
|
1155
|
+
joinTierMoney(tier.priceCents),
|
|
1156
|
+
")"
|
|
1157
|
+
] }) : tier.free ? " \u2014 free" : /* @__PURE__ */ jsxs15(Fragment7, { children: [
|
|
1158
|
+
" \u2014 ",
|
|
1159
|
+
joinTierMoney(tier.priceCents)
|
|
1160
|
+
] })
|
|
1161
|
+
] }, tier.id))
|
|
1162
|
+
] });
|
|
1163
|
+
}
|
|
1164
|
+
function tierNeedsPayment(selected, paymentsReady) {
|
|
1165
|
+
return selected ? !selected.free && paymentsReady : paymentsReady;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
// src/ui/join-application-form.tsx
|
|
1169
|
+
import { jsx as jsx16, jsxs as jsxs16 } from "preact/jsx-runtime";
|
|
1170
|
+
function JoinApplicationForm({ props, copy, invitation, requestedSeat, tierSelection, giftOfferId, selectGift, submitting, error, submit }) {
|
|
1171
|
+
const disabled = submitting || props.submitDisabled === true;
|
|
1172
|
+
return /* @__PURE__ */ jsxs16("form", { className: "join-form", onSubmit: (event) => void submit(event), children: [
|
|
1173
|
+
!requestedSeat && (props.config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs16("fieldset", { children: [
|
|
1174
|
+
/* @__PURE__ */ jsx16("legend", { children: copy.gift.optionsLabel }),
|
|
1175
|
+
/* @__PURE__ */ jsx16("button", { type: "button", className: "btn secondary", "aria-pressed": !giftOfferId, onClick: () => selectGift(null), children: copy.gift.chooseSelf }),
|
|
1176
|
+
/* @__PURE__ */ jsx16(GiftOfferCards, { offers: props.config.giftOffers ?? [], mode: "select", selectedOfferId: giftOfferId, onSelect: selectGift })
|
|
1177
|
+
] }) : null,
|
|
1178
|
+
!requestedSeat && (props.config.tiers?.length ?? 0) > 1 ? props.renderTiers?.(tierSelection) ?? TierPlaceholder(tierSelection) : null,
|
|
1179
|
+
typeof props.children === "function" ? props.children({ invitation }) : props.children,
|
|
1180
|
+
error ? /* @__PURE__ */ jsx16("p", { className: "join-error", role: "alert", children: error }) : null,
|
|
1181
|
+
props.renderSubmit?.({ submitting, disabled }) ?? /* @__PURE__ */ jsx16("button", { className: "submit-btn", type: "submit", disabled, children: submitting ? copy.form.submitting : copy.form.submit })
|
|
994
1182
|
] });
|
|
995
1183
|
}
|
|
996
1184
|
|
|
@@ -1015,8 +1203,8 @@ function joinStateFromApplicationResponse(data, fallbackNeedsPayment, submittedG
|
|
|
1015
1203
|
|
|
1016
1204
|
// src/ui/gift-code-redeemer.tsx
|
|
1017
1205
|
import { InlineActionField } from "@odla-ai/ui/components";
|
|
1018
|
-
import { useState as
|
|
1019
|
-
import { Fragment as
|
|
1206
|
+
import { useState as useState13 } from "preact/hooks";
|
|
1207
|
+
import { Fragment as Fragment8, jsx as jsx17, jsxs as jsxs17 } from "preact/jsx-runtime";
|
|
1020
1208
|
var GIFT_CODE_REDEEMER_CSS = `
|
|
1021
1209
|
.gift-code-redeemer{container-type:inline-size;display:grid;gap:var(--ui-space-1,.35rem);margin:0}
|
|
1022
1210
|
.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 +1219,10 @@ var GIFT_CODE_REDEEMER_CSS = `
|
|
|
1031
1219
|
@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
1220
|
`;
|
|
1033
1221
|
function GiftCodeRedeemer({ api, applicationId, copy, id, onRedeemed }) {
|
|
1034
|
-
const [code, setCode] =
|
|
1035
|
-
const [loading, setLoading] =
|
|
1036
|
-
const [message, setMessage] =
|
|
1037
|
-
const [messageTone, setMessageTone] =
|
|
1222
|
+
const [code, setCode] = useState13("");
|
|
1223
|
+
const [loading, setLoading] = useState13(false);
|
|
1224
|
+
const [message, setMessage] = useState13("");
|
|
1225
|
+
const [messageTone, setMessageTone] = useState13("neutral");
|
|
1038
1226
|
const normalizedCode = code.trim();
|
|
1039
1227
|
const redeem = async () => {
|
|
1040
1228
|
if (!normalizedCode || loading) return;
|
|
@@ -1061,9 +1249,9 @@ function GiftCodeRedeemer({ api, applicationId, copy, id, onRedeemed }) {
|
|
|
1061
1249
|
setLoading(false);
|
|
1062
1250
|
}
|
|
1063
1251
|
};
|
|
1064
|
-
return /* @__PURE__ */
|
|
1065
|
-
/* @__PURE__ */
|
|
1066
|
-
/* @__PURE__ */
|
|
1252
|
+
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1253
|
+
/* @__PURE__ */ jsx17("style", { children: GIFT_CODE_REDEEMER_CSS }),
|
|
1254
|
+
/* @__PURE__ */ jsx17(
|
|
1067
1255
|
InlineActionField,
|
|
1068
1256
|
{
|
|
1069
1257
|
id,
|
|
@@ -1119,12 +1307,12 @@ async function loadJoinResume(applicationId, fetcher = fetch) {
|
|
|
1119
1307
|
}
|
|
1120
1308
|
|
|
1121
1309
|
// src/ui/join-gift-claim.tsx
|
|
1122
|
-
import { jsx as
|
|
1310
|
+
import { jsx as jsx18, jsxs as jsxs18 } from "preact/jsx-runtime";
|
|
1123
1311
|
function JoinGiftClaim(props) {
|
|
1124
|
-
return /* @__PURE__ */
|
|
1125
|
-
/* @__PURE__ */
|
|
1126
|
-
/* @__PURE__ */
|
|
1127
|
-
/* @__PURE__ */
|
|
1312
|
+
return /* @__PURE__ */ jsxs18("section", { className: "join-gift-claim card", children: [
|
|
1313
|
+
/* @__PURE__ */ jsx18("div", { className: "card-label", children: props.copy.claimTitle }),
|
|
1314
|
+
/* @__PURE__ */ jsx18("p", { children: props.copy.claimBody }),
|
|
1315
|
+
/* @__PURE__ */ jsx18(
|
|
1128
1316
|
GiftCodeRedeemer,
|
|
1129
1317
|
{
|
|
1130
1318
|
api: props.api,
|
|
@@ -1148,24 +1336,21 @@ function JoinGiftClaim(props) {
|
|
|
1148
1336
|
}
|
|
1149
1337
|
|
|
1150
1338
|
// src/ui/join-named-seat.tsx
|
|
1151
|
-
import { useState as
|
|
1152
|
-
import { jsx as
|
|
1339
|
+
import { useState as useState14 } from "preact/hooks";
|
|
1340
|
+
import { jsx as jsx19, jsxs as jsxs19 } from "preact/jsx-runtime";
|
|
1153
1341
|
function JoinNamedSeat(props) {
|
|
1154
|
-
const
|
|
1155
|
-
const
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
/* @__PURE__ */
|
|
1159
|
-
/* @__PURE__ */
|
|
1160
|
-
|
|
1161
|
-
/* @__PURE__ */
|
|
1162
|
-
|
|
1163
|
-
/* @__PURE__ */ jsxs15("label", { children: [
|
|
1164
|
-
/* @__PURE__ */ jsx15("input", { type: "checkbox", checked: accepted, disabled: busy, onChange: (event) => setAccepted(event.currentTarget.checked) }),
|
|
1165
|
-
"I accept this seat for myself. It cannot be reassigned and lasts only while the purchaser\u2019s membership and my seat are current."
|
|
1342
|
+
const seatId = props.seatId ?? "";
|
|
1343
|
+
const inherited = useChapterCopy(), copy = props.copy ?? inherited.join.namedSeat;
|
|
1344
|
+
const [accepted, setAccepted] = useState14(false), [busy, setBusy] = useState14(false), [error, setError] = useState14("");
|
|
1345
|
+
return /* @__PURE__ */ jsxs19("section", { className: "join-named-seat card", children: [
|
|
1346
|
+
/* @__PURE__ */ jsx19("h2", { children: copy.title }),
|
|
1347
|
+
/* @__PURE__ */ jsx19("p", { children: copy.body }),
|
|
1348
|
+
/* @__PURE__ */ jsxs19("label", { className: "journey-consent", children: [
|
|
1349
|
+
/* @__PURE__ */ jsx19("input", { type: "checkbox", checked: accepted, disabled: busy, onChange: (event) => setAccepted(event.currentTarget.checked) }),
|
|
1350
|
+
/* @__PURE__ */ jsx19("span", { children: copy.consent })
|
|
1166
1351
|
] }),
|
|
1167
|
-
error ? /* @__PURE__ */
|
|
1168
|
-
/* @__PURE__ */
|
|
1352
|
+
error ? /* @__PURE__ */ jsx19("p", { role: "alert", children: error }) : null,
|
|
1353
|
+
/* @__PURE__ */ jsx19("button", { type: "button", className: "btn btn-primary", disabled: busy || !accepted || !seatId.trim(), onClick: async () => {
|
|
1169
1354
|
setBusy(true);
|
|
1170
1355
|
setError("");
|
|
1171
1356
|
try {
|
|
@@ -1175,59 +1360,54 @@ function JoinNamedSeat(props) {
|
|
|
1175
1360
|
});
|
|
1176
1361
|
if (!result.ok || result.applicationId !== props.applicationId || !["booking", "accepted", "paymentPending"].includes(result.state)) throw new Error("acceptance pending");
|
|
1177
1362
|
props.onState({ step: result.state, applicationId: result.applicationId });
|
|
1178
|
-
} catch {
|
|
1179
|
-
setError(
|
|
1363
|
+
} catch (error2) {
|
|
1364
|
+
setError(error2 instanceof Error && error2.message && error2.message !== "acceptance pending" ? error2.message.slice(0, 400) : copy.failure);
|
|
1180
1365
|
} finally {
|
|
1181
1366
|
setBusy(false);
|
|
1182
1367
|
}
|
|
1183
|
-
}, children: busy ?
|
|
1368
|
+
}, children: busy ? copy.accepting : copy.accept })
|
|
1184
1369
|
] });
|
|
1185
1370
|
}
|
|
1186
1371
|
|
|
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
|
-
|
|
1372
|
+
// src/ui/join-invitation.tsx
|
|
1373
|
+
import { useEffect as useEffect8, useState as useState15 } from "preact/hooks";
|
|
1374
|
+
import { jsx as jsx20, jsxs as jsxs20 } from "preact/jsx-runtime";
|
|
1375
|
+
function useJoinInvitation(seatId, api, fallback) {
|
|
1376
|
+
const [invitation, setInvitation] = useState15(null);
|
|
1377
|
+
const [error, setError] = useState15("");
|
|
1378
|
+
const [revision, setRevision] = useState15(0);
|
|
1379
|
+
useEffect8(() => {
|
|
1380
|
+
let live = true;
|
|
1381
|
+
setInvitation(null);
|
|
1382
|
+
setError("");
|
|
1383
|
+
if (!seatId) return;
|
|
1384
|
+
if (!api) {
|
|
1385
|
+
setError(fallback);
|
|
1386
|
+
return;
|
|
1202
1387
|
}
|
|
1203
|
-
|
|
1388
|
+
void api(`/api/named-seat/invitation?seat=${encodeURIComponent(seatId)}`).then((value) => {
|
|
1389
|
+
if (value.seatId !== seatId || !value.skuId || !value.purchaserName) throw new Error(fallback);
|
|
1390
|
+
if (live) setInvitation(value);
|
|
1391
|
+
}).catch((error2) => {
|
|
1392
|
+
if (live) setError(error2 instanceof Error ? error2.message.slice(0, 400) : fallback);
|
|
1393
|
+
});
|
|
1394
|
+
return () => {
|
|
1395
|
+
live = false;
|
|
1396
|
+
};
|
|
1397
|
+
}, [seatId, api, revision]);
|
|
1398
|
+
return { invitation: invitation?.seatId === seatId ? invitation : null, error, retry: () => setRevision((value) => value + 1) };
|
|
1204
1399
|
}
|
|
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))
|
|
1400
|
+
function JoinInvitationNotice(props) {
|
|
1401
|
+
return /* @__PURE__ */ jsxs20("aside", { className: "journey-invitation", "aria-label": props.copy.title, children: [
|
|
1402
|
+
/* @__PURE__ */ jsx20("p", { children: /* @__PURE__ */ jsx20("strong", { children: formatChapterCopy(props.copy.from, { purchaserName: props.invitation.purchaserName }) }) }),
|
|
1403
|
+
/* @__PURE__ */ jsx20("p", { children: formatChapterCopy(props.copy.prepaid, { tierName: props.tierName }) })
|
|
1221
1404
|
] });
|
|
1222
1405
|
}
|
|
1223
|
-
function tierNeedsPayment(selected, paymentsReady) {
|
|
1224
|
-
return selected ? !selected.free && paymentsReady : paymentsReady;
|
|
1225
|
-
}
|
|
1226
1406
|
|
|
1227
1407
|
// src/ui/join-pending.ts
|
|
1228
|
-
import { useEffect as
|
|
1408
|
+
import { useEffect as useEffect9 } from "preact/hooks";
|
|
1229
1409
|
function useJoinPending(state, loadResume, setState) {
|
|
1230
|
-
|
|
1410
|
+
useEffect9(() => {
|
|
1231
1411
|
if (state.step !== "paymentPending") return;
|
|
1232
1412
|
let live = true;
|
|
1233
1413
|
let timer;
|
|
@@ -1250,27 +1430,33 @@ function useJoinPending(state, loadResume, setState) {
|
|
|
1250
1430
|
}
|
|
1251
1431
|
|
|
1252
1432
|
// src/ui/join.tsx
|
|
1253
|
-
import { Fragment as
|
|
1433
|
+
import { Fragment as Fragment9, jsx as jsx21, jsxs as jsxs21 } from "preact/jsx-runtime";
|
|
1254
1434
|
function JoinIsland(props) {
|
|
1435
|
+
return /* @__PURE__ */ jsx21(JourneyFrame, { children: /* @__PURE__ */ jsx21(JoinFlow, { ...props }) });
|
|
1436
|
+
}
|
|
1437
|
+
function JoinFlow(props) {
|
|
1255
1438
|
const inheritedCopy = useChapterCopy();
|
|
1256
1439
|
const {
|
|
1257
1440
|
config,
|
|
1258
|
-
children,
|
|
1259
1441
|
membersHref = "/members/",
|
|
1260
1442
|
renderStepHeader,
|
|
1261
1443
|
renderDone,
|
|
1262
1444
|
renderAccepted,
|
|
1263
|
-
renderGift
|
|
1264
|
-
renderSubmit
|
|
1445
|
+
renderGift
|
|
1265
1446
|
} = props;
|
|
1266
1447
|
const copy = props.copy ?? config.copy ?? inheritedCopy.join;
|
|
1448
|
+
const seatCopy = copy.namedSeat ?? inheritedCopy.join.namedSeat;
|
|
1267
1449
|
const tiers = config.tiers ?? [];
|
|
1268
1450
|
const tierSelection = useTierSelection(tiers, props.initialTierId);
|
|
1269
|
-
const
|
|
1270
|
-
const
|
|
1271
|
-
const
|
|
1272
|
-
const
|
|
1273
|
-
const
|
|
1451
|
+
const requestedSeat = props.simulation ? void 0 : props.initialNamedSeatId;
|
|
1452
|
+
const invitationState = useJoinInvitation(requestedSeat, props.namedSeatClaimApi, seatCopy.unavailable);
|
|
1453
|
+
const invitation = invitationState.invitation;
|
|
1454
|
+
const selectedTierId = invitation?.skuId ?? tierSelection.selectedTierId;
|
|
1455
|
+
const selectedTier = tiers.find((tier) => tier.id === selectedTierId) ?? tierSelection.selected;
|
|
1456
|
+
const [state, setState] = useState16(requestedSeat ? { step: "form" } : props.initialState ?? { step: "form" });
|
|
1457
|
+
const [error, setError] = useState16(null);
|
|
1458
|
+
const [submitting, setSubmitting] = useState16(false);
|
|
1459
|
+
const [giftOfferId, setGiftOfferId] = useState16(props.initialGiftOfferId ?? null);
|
|
1274
1460
|
const simulatedPayment = props.simulation ? props.simulation.payment ?? {
|
|
1275
1461
|
lineItems: {
|
|
1276
1462
|
standardCents: selectedTier?.priceCents ?? 0,
|
|
@@ -1280,9 +1466,9 @@ function JoinIsland(props) {
|
|
|
1280
1466
|
} : void 0;
|
|
1281
1467
|
const simulatedBooking = props.simulation ? props.simulation.booking ?? { slots: [], timezone: "UTC" } : void 0;
|
|
1282
1468
|
const submissionId = useRef3(null);
|
|
1283
|
-
|
|
1469
|
+
useEffect10(() => {
|
|
1284
1470
|
if (props.simulation) return;
|
|
1285
|
-
const resolver = props.loadResume ?? (() => {
|
|
1471
|
+
const resolver = requestedSeat ? () => invitation?.applicationId ? loadJoinResume(invitation.applicationId) : Promise.resolve(null) : props.loadResume ?? (() => {
|
|
1286
1472
|
if (typeof window === "undefined") return Promise.resolve(null);
|
|
1287
1473
|
const applicationId = new URL(window.location.href).searchParams.get("application");
|
|
1288
1474
|
return applicationId ? loadJoinResume(applicationId) : Promise.resolve(null);
|
|
@@ -1296,17 +1482,21 @@ function JoinIsland(props) {
|
|
|
1296
1482
|
return () => {
|
|
1297
1483
|
live = false;
|
|
1298
1484
|
};
|
|
1299
|
-
}, [props.loadResume, props.simulation]);
|
|
1300
|
-
useJoinPending(state, props.loadResume, setState);
|
|
1485
|
+
}, [props.loadResume, props.simulation, requestedSeat, invitation?.applicationId]);
|
|
1486
|
+
useJoinPending(state, requestedSeat ? void 0 : props.loadResume, setState);
|
|
1301
1487
|
const submit = async (e) => {
|
|
1302
1488
|
e.preventDefault();
|
|
1303
|
-
if (submitting || props.submitDisabled === true) return;
|
|
1489
|
+
if (submitting || props.submitDisabled === true || requestedSeat && !invitation) return;
|
|
1304
1490
|
setSubmitting(true);
|
|
1305
1491
|
setError(null);
|
|
1306
1492
|
try {
|
|
1307
1493
|
const fields = collectFormFields(new FormData(e.currentTarget));
|
|
1308
1494
|
fields.submissionId = submissionId.current ??= crypto.randomUUID();
|
|
1309
|
-
if (
|
|
1495
|
+
if (invitation) {
|
|
1496
|
+
fields.namedSeatId = invitation.seatId;
|
|
1497
|
+
fields.tierId = invitation.skuId;
|
|
1498
|
+
fields.email = invitation.recipientEmail;
|
|
1499
|
+
} else if (giftOfferId) fields.giftOfferId = giftOfferId;
|
|
1310
1500
|
else if (selectedTierId) fields.tierId = selectedTierId;
|
|
1311
1501
|
if (props.simulation) {
|
|
1312
1502
|
setState({
|
|
@@ -1317,6 +1507,16 @@ function JoinIsland(props) {
|
|
|
1317
1507
|
});
|
|
1318
1508
|
return;
|
|
1319
1509
|
}
|
|
1510
|
+
if (invitation && props.namedSeatClaimApi) {
|
|
1511
|
+
const result = await props.namedSeatClaimApi("/api/applications", {
|
|
1512
|
+
method: "POST",
|
|
1513
|
+
headers: { "content-type": "application/json" },
|
|
1514
|
+
body: JSON.stringify(fields)
|
|
1515
|
+
});
|
|
1516
|
+
if (!result.id) throw new Error(copy.form.submitFailed);
|
|
1517
|
+
setState(joinStateFromApplicationResponse(result, true, false));
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1320
1520
|
const res = await fetch("/api/applications", {
|
|
1321
1521
|
method: "POST",
|
|
1322
1522
|
headers: { "content-type": "application/json" },
|
|
@@ -1335,50 +1535,66 @@ function JoinIsland(props) {
|
|
|
1335
1535
|
setSubmitting(false);
|
|
1336
1536
|
}
|
|
1337
1537
|
};
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1538
|
+
if (requestedSeat && !invitation) return /* @__PURE__ */ jsxs21("section", { className: "card", "aria-live": "polite", children: [
|
|
1539
|
+
/* @__PURE__ */ jsx21("h2", { children: seatCopy.title }),
|
|
1540
|
+
/* @__PURE__ */ jsx21("p", { role: invitationState.error ? "alert" : "status", children: invitationState.error || seatCopy.loading }),
|
|
1541
|
+
invitationState.error ? /* @__PURE__ */ jsx21("button", { type: "button", onClick: invitationState.retry, children: seatCopy.retry }) : null
|
|
1542
|
+
] });
|
|
1543
|
+
const header = /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
1544
|
+
invitation ? /* @__PURE__ */ jsx21(
|
|
1545
|
+
JoinInvitationNotice,
|
|
1546
|
+
{
|
|
1547
|
+
invitation,
|
|
1548
|
+
copy: seatCopy,
|
|
1549
|
+
tierName: selectedTier?.name ?? ""
|
|
1550
|
+
}
|
|
1551
|
+
) : null,
|
|
1552
|
+
renderStepHeader?.({
|
|
1553
|
+
state,
|
|
1554
|
+
...invitation ? { invitation } : {},
|
|
1555
|
+
..."applicationId" in state ? { applicationId: state.applicationId } : {}
|
|
1556
|
+
})
|
|
1557
|
+
] });
|
|
1342
1558
|
if (state.step === "closed") {
|
|
1343
|
-
return /* @__PURE__ */
|
|
1559
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
1344
1560
|
header,
|
|
1345
|
-
/* @__PURE__ */
|
|
1346
|
-
/* @__PURE__ */
|
|
1347
|
-
/* @__PURE__ */
|
|
1348
|
-
/* @__PURE__ */
|
|
1561
|
+
/* @__PURE__ */ jsxs21("section", { className: "card", "aria-label": "Application closed", children: [
|
|
1562
|
+
/* @__PURE__ */ jsx21("h2", { children: "This application is closed" }),
|
|
1563
|
+
/* @__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." }),
|
|
1564
|
+
/* @__PURE__ */ jsx21("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
|
|
1349
1565
|
] })
|
|
1350
1566
|
] });
|
|
1351
1567
|
}
|
|
1352
1568
|
if (state.step === "done") {
|
|
1353
|
-
const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */
|
|
1354
|
-
/* @__PURE__ */
|
|
1355
|
-
/* @__PURE__ */
|
|
1356
|
-
/* @__PURE__ */
|
|
1357
|
-
/* @__PURE__ */
|
|
1569
|
+
const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsxs21("div", { className: "join-done card", children: [
|
|
1570
|
+
/* @__PURE__ */ jsx21("div", { className: "card-label", children: copy.done.label }),
|
|
1571
|
+
/* @__PURE__ */ jsx21("p", { className: "meeting-date", children: fullLabel(state.booked.startAt, state.booked.timezone) }),
|
|
1572
|
+
/* @__PURE__ */ jsx21("p", { className: "meeting-note", children: copy.done.calendarInvite }),
|
|
1573
|
+
/* @__PURE__ */ jsx21("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
|
|
1358
1574
|
] });
|
|
1359
|
-
return /* @__PURE__ */
|
|
1575
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
1360
1576
|
header,
|
|
1361
1577
|
body
|
|
1362
1578
|
] });
|
|
1363
1579
|
}
|
|
1364
1580
|
if (state.step === "accepted") {
|
|
1365
|
-
const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */
|
|
1366
|
-
return /* @__PURE__ */
|
|
1581
|
+
const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsx21(JoinAccepted, { copy, membersHref });
|
|
1582
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
1367
1583
|
header,
|
|
1368
1584
|
body
|
|
1369
1585
|
] });
|
|
1370
1586
|
}
|
|
1371
1587
|
if (state.step === "gift") {
|
|
1372
|
-
const body = renderGift?.(state) ?? /* @__PURE__ */
|
|
1373
|
-
return /* @__PURE__ */
|
|
1588
|
+
const body = renderGift?.(state) ?? /* @__PURE__ */ jsx21(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
|
|
1589
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
1374
1590
|
header,
|
|
1375
1591
|
body
|
|
1376
1592
|
] });
|
|
1377
1593
|
}
|
|
1378
1594
|
if (state.step === "booking") {
|
|
1379
|
-
return /* @__PURE__ */
|
|
1595
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
1380
1596
|
header,
|
|
1381
|
-
/* @__PURE__ */
|
|
1597
|
+
/* @__PURE__ */ jsx21(
|
|
1382
1598
|
JoinBooking,
|
|
1383
1599
|
{
|
|
1384
1600
|
applicationId: state.applicationId,
|
|
@@ -1393,23 +1609,24 @@ function JoinIsland(props) {
|
|
|
1393
1609
|
}
|
|
1394
1610
|
if (state.step === "payment") {
|
|
1395
1611
|
if (props.namedSeatClaimApi && props.initialNamedSeatId && !props.simulation && !state.giftPurchase) {
|
|
1396
|
-
return /* @__PURE__ */
|
|
1612
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
1397
1613
|
header,
|
|
1398
|
-
/* @__PURE__ */
|
|
1614
|
+
/* @__PURE__ */ jsx21(
|
|
1399
1615
|
JoinNamedSeat,
|
|
1400
1616
|
{
|
|
1401
1617
|
api: props.namedSeatClaimApi,
|
|
1402
1618
|
applicationId: state.applicationId,
|
|
1403
1619
|
seatId: props.initialNamedSeatId,
|
|
1620
|
+
copy: seatCopy,
|
|
1404
1621
|
onState: setState
|
|
1405
1622
|
}
|
|
1406
1623
|
)
|
|
1407
1624
|
] });
|
|
1408
1625
|
}
|
|
1409
1626
|
const Payment = state.giftPurchase || props.simulation ? PaymentStep : MembershipPaymentStep;
|
|
1410
|
-
return /* @__PURE__ */
|
|
1627
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
1411
1628
|
header,
|
|
1412
|
-
props.giftClaimApi && !state.giftPurchase ? /* @__PURE__ */
|
|
1629
|
+
props.giftClaimApi && !state.giftPurchase ? /* @__PURE__ */ jsx21(
|
|
1413
1630
|
JoinGiftClaim,
|
|
1414
1631
|
{
|
|
1415
1632
|
api: props.giftClaimApi,
|
|
@@ -1420,7 +1637,7 @@ function JoinIsland(props) {
|
|
|
1420
1637
|
onError: () => setError(copy.form.unexpectedFailure)
|
|
1421
1638
|
}
|
|
1422
1639
|
) : null,
|
|
1423
|
-
/* @__PURE__ */
|
|
1640
|
+
/* @__PURE__ */ jsx21(
|
|
1424
1641
|
Payment,
|
|
1425
1642
|
{
|
|
1426
1643
|
applicationId: state.applicationId,
|
|
@@ -1449,39 +1666,42 @@ function JoinIsland(props) {
|
|
|
1449
1666
|
}
|
|
1450
1667
|
if (state.step === "paymentPending") {
|
|
1451
1668
|
if (props.namedSeatClaimApi && props.initialNamedSeatId && !props.simulation) {
|
|
1452
|
-
return /* @__PURE__ */
|
|
1669
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
1453
1670
|
header,
|
|
1454
|
-
/* @__PURE__ */
|
|
1671
|
+
/* @__PURE__ */ jsx21(
|
|
1455
1672
|
JoinNamedSeat,
|
|
1456
1673
|
{
|
|
1457
1674
|
api: props.namedSeatClaimApi,
|
|
1458
1675
|
applicationId: state.applicationId,
|
|
1459
1676
|
seatId: props.initialNamedSeatId,
|
|
1677
|
+
copy: seatCopy,
|
|
1460
1678
|
onState: setState
|
|
1461
1679
|
}
|
|
1462
1680
|
)
|
|
1463
1681
|
] });
|
|
1464
1682
|
}
|
|
1465
|
-
return /* @__PURE__ */
|
|
1683
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
1466
1684
|
header,
|
|
1467
|
-
/* @__PURE__ */
|
|
1685
|
+
/* @__PURE__ */ jsx21("p", { className: "pay-status", role: "status", children: copy.payment.pending })
|
|
1468
1686
|
] });
|
|
1469
1687
|
}
|
|
1470
|
-
|
|
1471
|
-
const tierChooser = tiers.length > 1 ? props.renderTiers?.(tierSelection) ?? TierPlaceholder(tierSelection) : null;
|
|
1472
|
-
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1688
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
1473
1689
|
header,
|
|
1474
|
-
/* @__PURE__ */
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1690
|
+
/* @__PURE__ */ jsx21(
|
|
1691
|
+
JoinApplicationForm,
|
|
1692
|
+
{
|
|
1693
|
+
props,
|
|
1694
|
+
copy,
|
|
1695
|
+
invitation,
|
|
1696
|
+
requestedSeat,
|
|
1697
|
+
tierSelection,
|
|
1698
|
+
giftOfferId,
|
|
1699
|
+
selectGift: setGiftOfferId,
|
|
1700
|
+
submitting,
|
|
1701
|
+
error,
|
|
1702
|
+
submit
|
|
1703
|
+
}
|
|
1704
|
+
)
|
|
1485
1705
|
] });
|
|
1486
1706
|
}
|
|
1487
1707
|
|
|
@@ -1657,7 +1877,7 @@ function membershipPageDocument(input, options = {}) {
|
|
|
1657
1877
|
}
|
|
1658
1878
|
|
|
1659
1879
|
// src/ui/membership-cards.tsx
|
|
1660
|
-
import { jsx as
|
|
1880
|
+
import { jsx as jsx22, jsxs as jsxs22 } from "preact/jsx-runtime";
|
|
1661
1881
|
var MEMBERSHIP_CARD_TOKEN_DEFAULTS = Object.freeze({
|
|
1662
1882
|
"--ui-membership-grid-gap": "1.4rem",
|
|
1663
1883
|
"--ui-membership-card-padding": "2rem 1.7rem 1.8rem",
|
|
@@ -1726,67 +1946,67 @@ function membershipApplicationHref(applicationPath, tierId) {
|
|
|
1726
1946
|
}
|
|
1727
1947
|
function TierAction(props) {
|
|
1728
1948
|
if (props.mode === "select") {
|
|
1729
|
-
return /* @__PURE__ */
|
|
1949
|
+
return /* @__PURE__ */ jsxs22("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
|
|
1730
1950
|
props.label,
|
|
1731
|
-
/* @__PURE__ */
|
|
1951
|
+
/* @__PURE__ */ jsx22("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1732
1952
|
] });
|
|
1733
1953
|
}
|
|
1734
1954
|
if (props.mode === "preview") {
|
|
1735
|
-
return /* @__PURE__ */
|
|
1955
|
+
return /* @__PURE__ */ jsxs22("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
|
|
1736
1956
|
props.label,
|
|
1737
|
-
/* @__PURE__ */
|
|
1957
|
+
/* @__PURE__ */ jsx22("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1738
1958
|
] });
|
|
1739
1959
|
}
|
|
1740
|
-
return /* @__PURE__ */
|
|
1960
|
+
return /* @__PURE__ */ jsxs22("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
|
|
1741
1961
|
props.label,
|
|
1742
|
-
/* @__PURE__ */
|
|
1962
|
+
/* @__PURE__ */ jsx22("span", { "aria-hidden": "true", children: "\u2192" })
|
|
1743
1963
|
] });
|
|
1744
1964
|
}
|
|
1745
1965
|
function TierCard(props) {
|
|
1746
1966
|
const { tier, presentation } = props;
|
|
1747
1967
|
const summary = presentation.summaryMarkdown ?? tier.blurb;
|
|
1748
1968
|
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__ */
|
|
1969
|
+
return /* @__PURE__ */ jsxs22("article", { className: "chapter-membership-card", "data-tier-id": tier.id, "data-variant": presentation.variant ?? "standard", children: [
|
|
1970
|
+
presentation.badge ? /* @__PURE__ */ jsx22("div", { className: "chapter-membership-badge", children: presentation.badge }) : null,
|
|
1971
|
+
/* @__PURE__ */ jsx22("h3", { className: "chapter-membership-name", children: tier.name }),
|
|
1972
|
+
/* @__PURE__ */ jsxs22("div", { className: "chapter-membership-offer", "data-with-capacity": presentation.capacity ? "true" : void 0, children: [
|
|
1973
|
+
presentation.capacity ? /* @__PURE__ */ jsxs22("div", { className: "chapter-membership-capacity", "aria-label": `${presentation.capacity.total} ${presentation.capacity.label ?? "available"}`, children: [
|
|
1974
|
+
/* @__PURE__ */ jsx22("strong", { children: presentation.capacity.total.toLocaleString("en-US") }),
|
|
1975
|
+
/* @__PURE__ */ jsx22("small", { children: presentation.capacity.label ?? "available" })
|
|
1756
1976
|
] }) : null,
|
|
1757
|
-
/* @__PURE__ */
|
|
1758
|
-
presentation.priceEyebrow ? /* @__PURE__ */
|
|
1759
|
-
/* @__PURE__ */
|
|
1760
|
-
presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */
|
|
1761
|
-
/* @__PURE__ */
|
|
1762
|
-
!tier.free && presentation.billingLabel ? /* @__PURE__ */
|
|
1977
|
+
/* @__PURE__ */ jsxs22("div", { className: "chapter-membership-price-stack", children: [
|
|
1978
|
+
presentation.priceEyebrow ? /* @__PURE__ */ jsx22("p", { className: "chapter-membership-price-eyebrow", children: presentation.priceEyebrow }) : tier.founding ? /* @__PURE__ */ jsx22("p", { className: "chapter-membership-price-eyebrow", children: "Founding member rate" }) : null,
|
|
1979
|
+
/* @__PURE__ */ jsxs22("div", { className: "chapter-membership-price-row", children: [
|
|
1980
|
+
tier.founding ? /* @__PURE__ */ jsx22("span", { className: "chapter-membership-compare", children: fmtMoney(tier.priceCents) }) : presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */ jsx22("span", { className: "chapter-membership-compare", children: fmtMoney(presentation.compareAtPriceCents) }) : null,
|
|
1981
|
+
/* @__PURE__ */ jsx22("span", { className: "chapter-membership-price", children: tier.free ? "Free" : fmtMoney(tier.founding ? tier.founding.dueTodayCents : tier.priceCents) }),
|
|
1982
|
+
!tier.free && presentation.billingLabel ? /* @__PURE__ */ jsx22("span", { className: "chapter-membership-billing", children: presentation.billingLabel }) : null
|
|
1763
1983
|
] })
|
|
1764
1984
|
] })
|
|
1765
1985
|
] }),
|
|
1766
|
-
presentation.priceNoteMarkdown ? /* @__PURE__ */
|
|
1767
|
-
summary ? /* @__PURE__ */
|
|
1768
|
-
presentation.benefits?.length ? /* @__PURE__ */
|
|
1769
|
-
/* @__PURE__ */
|
|
1770
|
-
/* @__PURE__ */
|
|
1986
|
+
presentation.priceNoteMarkdown ? /* @__PURE__ */ jsx22(Markdown2, { className: "chapter-membership-price-note", source: presentation.priceNoteMarkdown }) : null,
|
|
1987
|
+
summary ? /* @__PURE__ */ jsx22(Markdown2, { className: "chapter-membership-summary", source: summary }) : null,
|
|
1988
|
+
presentation.benefits?.length ? /* @__PURE__ */ jsx22("ul", { className: "chapter-membership-benefits", children: presentation.benefits.map((benefit, index) => /* @__PURE__ */ jsxs22("li", { children: [
|
|
1989
|
+
/* @__PURE__ */ jsx22("span", { className: "chapter-membership-check", "aria-hidden": "true", children: "\u2713" }),
|
|
1990
|
+
/* @__PURE__ */ jsx22(Markdown2, { className: "chapter-membership-benefit", source: benefit })
|
|
1771
1991
|
] }, `${tier.id}-benefit-${index}`)) }) : null,
|
|
1772
|
-
presentation.callout ? /* @__PURE__ */
|
|
1773
|
-
presentation.callout.label ? /* @__PURE__ */
|
|
1774
|
-
/* @__PURE__ */
|
|
1992
|
+
presentation.callout ? /* @__PURE__ */ jsxs22("aside", { className: "chapter-membership-callout", children: [
|
|
1993
|
+
presentation.callout.label ? /* @__PURE__ */ jsx22("p", { className: "chapter-membership-callout-label", children: presentation.callout.label }) : null,
|
|
1994
|
+
/* @__PURE__ */ jsx22(Markdown2, { source: presentation.callout.bodyMarkdown })
|
|
1775
1995
|
] }) : null,
|
|
1776
|
-
/* @__PURE__ */
|
|
1996
|
+
/* @__PURE__ */ jsx22(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
|
|
1777
1997
|
] });
|
|
1778
1998
|
}
|
|
1779
1999
|
function MembershipCards(props) {
|
|
1780
2000
|
const document2 = membershipPageDocument(props.document, { tiers: props.tiers });
|
|
1781
2001
|
const byId = new Map(props.tiers.map((tier) => [tier.id, tier]));
|
|
1782
2002
|
const mode = props.mode ?? "link";
|
|
1783
|
-
return /* @__PURE__ */
|
|
1784
|
-
/* @__PURE__ */
|
|
1785
|
-
/* @__PURE__ */
|
|
2003
|
+
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: [
|
|
2004
|
+
/* @__PURE__ */ jsx22("style", { children: MEMBERSHIP_CARDS_CSS }),
|
|
2005
|
+
/* @__PURE__ */ jsx22("div", { className: "chapter-membership-grid", style: { "--chapter-membership-columns": String(Math.min(document2.tiers.length, 3)) }, children: document2.tiers.map((presentation) => {
|
|
1786
2006
|
const tier = byId.get(presentation.tierId);
|
|
1787
|
-
return /* @__PURE__ */
|
|
2007
|
+
return /* @__PURE__ */ jsx22(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
|
|
1788
2008
|
}) }),
|
|
1789
|
-
document2.footnoteMarkdown ? /* @__PURE__ */
|
|
2009
|
+
document2.footnoteMarkdown ? /* @__PURE__ */ jsx22(Markdown2, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
|
|
1790
2010
|
] });
|
|
1791
2011
|
}
|
|
1792
2012
|
|
|
@@ -1800,21 +2020,23 @@ export {
|
|
|
1800
2020
|
fmtDate,
|
|
1801
2021
|
groupSlotsByDay,
|
|
1802
2022
|
SlotPicker,
|
|
2023
|
+
PaymentStep,
|
|
2024
|
+
JourneyFrame,
|
|
2025
|
+
MemberRestart,
|
|
1803
2026
|
Rescheduler,
|
|
1804
2027
|
GiftOfferCards,
|
|
1805
|
-
PaymentStep,
|
|
1806
2028
|
GiftPurchases,
|
|
1807
2029
|
MemberGifts,
|
|
1808
2030
|
MemberContentArea,
|
|
1809
2031
|
MembersArea,
|
|
1810
|
-
GiftCodeRedeemer,
|
|
1811
|
-
loadJoinResume,
|
|
1812
2032
|
useTierSelection,
|
|
1813
2033
|
TierPlaceholder,
|
|
1814
2034
|
tierNeedsPayment,
|
|
2035
|
+
GiftCodeRedeemer,
|
|
2036
|
+
loadJoinResume,
|
|
1815
2037
|
JoinIsland,
|
|
1816
2038
|
MEMBERSHIP_CARD_TOKEN_DEFAULTS,
|
|
1817
2039
|
membershipApplicationHref,
|
|
1818
2040
|
MembershipCards
|
|
1819
2041
|
};
|
|
1820
|
-
//# sourceMappingURL=chunk-
|
|
2042
|
+
//# sourceMappingURL=chunk-OS46ZE46.js.map
|