@kotao/storefront 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-4OQYNUGM.js +29 -0
- package/dist/chunk-4OQYNUGM.js.map +1 -0
- package/dist/{chunk-7XYWHWT4.js → chunk-4TEFGD42.js} +331 -38
- package/dist/chunk-4TEFGD42.js.map +1 -0
- package/dist/chunk-7MTCGXIG.js +144 -0
- package/dist/chunk-7MTCGXIG.js.map +1 -0
- package/dist/chunk-IIOHENCG.js +239 -0
- package/dist/chunk-IIOHENCG.js.map +1 -0
- package/dist/chunk-VV653S52.js +246 -0
- package/dist/chunk-VV653S52.js.map +1 -0
- package/dist/chunk-WG7HYVHJ.js +38 -0
- package/dist/chunk-WG7HYVHJ.js.map +1 -0
- package/dist/{client-DiPdlvPu.d.ts → client-D51WdvYR.d.ts} +55 -8
- package/dist/client-bsiNPHBi.d.ts +159 -0
- package/dist/createCartHandler-C4RrPwSG.d.ts +58 -0
- package/dist/editor.d.ts +1 -1
- package/dist/events-react.d.ts +68 -0
- package/dist/events-react.js +557 -0
- package/dist/events-react.js.map +1 -0
- package/dist/events.d.ts +18 -0
- package/dist/events.js +5 -0
- package/dist/events.js.map +1 -0
- package/dist/{fetch-B6TIc6lI.d.ts → fetch-M3Y-fQrW.d.ts} +1 -1
- package/dist/forms.d.ts +58 -0
- package/dist/forms.js +3 -0
- package/dist/forms.js.map +1 -0
- package/dist/http-types-CGh8WGHB.d.ts +11 -0
- package/dist/index.d.ts +74 -12
- package/dist/index.js +55 -9
- package/dist/index.js.map +1 -1
- package/dist/offer-token-C-nk_nj8.d.ts +16 -0
- package/dist/{pagination-CPgH3fAa.d.ts → pagination-DCrQk02Q.d.ts} +1 -1
- package/dist/product.d.ts +1 -1
- package/dist/react-router.d.ts +11 -7
- package/dist/react-router.js +4 -3
- package/dist/react-router.js.map +1 -1
- package/dist/react.d.ts +30 -7
- package/dist/react.js +4 -2
- package/dist/react.js.map +1 -1
- package/dist/{routing-BxRlep_-.d.ts → routing-sEonP93J.d.ts} +17 -60
- package/dist/seo.d.ts +2 -1
- package/dist/settings.d.ts +5 -4
- package/dist/{shop-DkQmro-Y.d.ts → shop-BJSvtmnV.d.ts} +2 -2
- package/dist/{store-DQK1nhob.d.ts → store-CtCWHI8H.d.ts} +1 -1
- package/dist/types-CSNXbGFW.d.ts +108 -0
- package/dist/{types-Df3bGbKU.d.ts → types-bcbQzx87.d.ts} +1 -1
- package/package.json +13 -1
- package/dist/chunk-7XYWHWT4.js.map +0 -1
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
import { StorefrontFormFields } from './chunk-VV653S52.js';
|
|
2
|
+
import { offerTokenHrefMarker, consumeOfferTokenFragment } from './chunk-WG7HYVHJ.js';
|
|
3
|
+
import { StorefrontEventsRequestError } from './chunk-7MTCGXIG.js';
|
|
4
|
+
import './chunk-IIOHENCG.js';
|
|
5
|
+
import { useState, useRef, useEffect, useCallback, useId, useMemo, useLayoutEffect } from 'react';
|
|
6
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
function useEventRegistration(input) {
|
|
9
|
+
const [state, setState] = useState("idle");
|
|
10
|
+
const generation = useRef(0);
|
|
11
|
+
const logicalPayload = useRef(null);
|
|
12
|
+
const idempotencyKey = useRef(null);
|
|
13
|
+
const activeClient = useRef(input.client);
|
|
14
|
+
const activeCallback = useRef(input.onCheckoutSession);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (activeClient.current !== input.client || activeCallback.current !== input.onCheckoutSession) {
|
|
17
|
+
activeClient.current = input.client;
|
|
18
|
+
activeCallback.current = input.onCheckoutSession;
|
|
19
|
+
generation.current += 1;
|
|
20
|
+
setState("idle");
|
|
21
|
+
}
|
|
22
|
+
}, [input.client, input.onCheckoutSession]);
|
|
23
|
+
useEffect(
|
|
24
|
+
() => () => {
|
|
25
|
+
generation.current += 1;
|
|
26
|
+
},
|
|
27
|
+
[]
|
|
28
|
+
);
|
|
29
|
+
const reset = useCallback(() => {
|
|
30
|
+
generation.current += 1;
|
|
31
|
+
setState("idle");
|
|
32
|
+
}, []);
|
|
33
|
+
async function submit(submission) {
|
|
34
|
+
const attempt = ++generation.current;
|
|
35
|
+
const prepared = registrationSubmission(submission, logicalPayload, idempotencyKey);
|
|
36
|
+
setState("submitting");
|
|
37
|
+
try {
|
|
38
|
+
const result = await input.client.submitRegistration(prepared);
|
|
39
|
+
if (attempt !== generation.current) return;
|
|
40
|
+
if (result.kind === "checkout") {
|
|
41
|
+
input.onCheckoutSession?.(result.checkoutSession);
|
|
42
|
+
setState("checkout_ready");
|
|
43
|
+
} else if (result.kind === "approval") {
|
|
44
|
+
setState("awaiting_approval");
|
|
45
|
+
} else {
|
|
46
|
+
setState("waitlisted");
|
|
47
|
+
}
|
|
48
|
+
} catch {
|
|
49
|
+
if (attempt !== generation.current) return;
|
|
50
|
+
setState("request_error");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { state, submit, reset };
|
|
54
|
+
}
|
|
55
|
+
function registrationKey(mode) {
|
|
56
|
+
const kind = mode === "approval_then_payment" ? "application" : "checkout";
|
|
57
|
+
return `events-${kind}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
58
|
+
}
|
|
59
|
+
function stablePayload(value) {
|
|
60
|
+
return JSON.stringify(value, (_key, item) => {
|
|
61
|
+
if (item === null || typeof item !== "object" || Array.isArray(item)) return item;
|
|
62
|
+
return Object.fromEntries(
|
|
63
|
+
Object.entries(item).sort(
|
|
64
|
+
([left], [right]) => left.localeCompare(right)
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function registrationSubmission(submission, previousPayload, previousKey) {
|
|
70
|
+
if (submission.registrationMode === "waitlist_only") return submission;
|
|
71
|
+
if (submission.idempotencyKey.trim() !== "") return submission;
|
|
72
|
+
const payload = {
|
|
73
|
+
registrationMode: submission.registrationMode,
|
|
74
|
+
handle: submission.handle,
|
|
75
|
+
input: submission.input
|
|
76
|
+
};
|
|
77
|
+
const identity = stablePayload(payload);
|
|
78
|
+
if (identity !== previousPayload.current || previousKey.current === null) {
|
|
79
|
+
previousPayload.current = identity;
|
|
80
|
+
previousKey.current = registrationKey(submission.registrationMode);
|
|
81
|
+
}
|
|
82
|
+
return { ...submission, idempotencyKey: previousKey.current };
|
|
83
|
+
}
|
|
84
|
+
function eventFormForRenderer(form) {
|
|
85
|
+
return {
|
|
86
|
+
definition: {
|
|
87
|
+
id: form.definitionId,
|
|
88
|
+
handle: form.definitionId,
|
|
89
|
+
title: form.title
|
|
90
|
+
},
|
|
91
|
+
version: {
|
|
92
|
+
id: form.versionId,
|
|
93
|
+
definitionId: form.definitionId,
|
|
94
|
+
schema: form.schema
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
var REGISTRATION_COPY = {
|
|
99
|
+
en: {
|
|
100
|
+
submit: "Register",
|
|
101
|
+
submitting: "Submitting\u2026",
|
|
102
|
+
awaiting_approval: "Application received. Awaiting approval.",
|
|
103
|
+
waitlisted: "You joined the waitlist.",
|
|
104
|
+
checkout_ready: "Registration ready for checkout.",
|
|
105
|
+
request_error: "Something went wrong. Please try again.",
|
|
106
|
+
email: "Email",
|
|
107
|
+
quantity: "Quantity",
|
|
108
|
+
ticket: "Ticket"
|
|
109
|
+
},
|
|
110
|
+
de: {
|
|
111
|
+
submit: "Anmelden",
|
|
112
|
+
submitting: "Wird gesendet\u2026",
|
|
113
|
+
awaiting_approval: "Anmeldung erhalten. Sie wartet auf Freigabe.",
|
|
114
|
+
waitlisted: "Du stehst auf der Warteliste.",
|
|
115
|
+
checkout_ready: "Die Anmeldung kann bezahlt werden.",
|
|
116
|
+
request_error: "Etwas ist schiefgelaufen. Bitte versuche es erneut.",
|
|
117
|
+
email: "E-Mail",
|
|
118
|
+
quantity: "Anzahl",
|
|
119
|
+
ticket: "Ticket"
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
function registrationCopy(locale) {
|
|
123
|
+
return locale.toLowerCase().startsWith("de") ? REGISTRATION_COPY.de : REGISTRATION_COPY.en;
|
|
124
|
+
}
|
|
125
|
+
function selectable(ticket) {
|
|
126
|
+
return ticket.salesState === "on_sale" && ticket.maxPerOrder >= ticket.minPerOrder && (ticket.available === null || ticket.available >= ticket.minPerOrder);
|
|
127
|
+
}
|
|
128
|
+
function EventRegistrationForm({
|
|
129
|
+
event,
|
|
130
|
+
locale,
|
|
131
|
+
client,
|
|
132
|
+
cartToken,
|
|
133
|
+
fallbackLocale,
|
|
134
|
+
onCheckoutSession,
|
|
135
|
+
labels,
|
|
136
|
+
className
|
|
137
|
+
}) {
|
|
138
|
+
const tickets = event.occurrences.flatMap((occurrence) => occurrence.ticketTypes);
|
|
139
|
+
const firstTicket = tickets.find(selectable);
|
|
140
|
+
const [ticketTypeId, setTicketTypeId] = useState(firstTicket?.id ?? "");
|
|
141
|
+
const ticket = tickets.find((candidate) => candidate.id === ticketTypeId);
|
|
142
|
+
const initialQuantity = ticket?.minPerOrder ?? 1;
|
|
143
|
+
const [quantity, setQuantity] = useState(initialQuantity);
|
|
144
|
+
const [email, setEmail] = useState("");
|
|
145
|
+
const [preflightError, setPreflightError] = useState(false);
|
|
146
|
+
const [buyerAnswers, setBuyerAnswers] = useState({});
|
|
147
|
+
const [participantAnswers, setParticipantAnswers] = useState(
|
|
148
|
+
() => Array.from({ length: initialQuantity }, () => ({}))
|
|
149
|
+
);
|
|
150
|
+
const generatedId = useId();
|
|
151
|
+
const instanceId = `event-registration-${generatedId.replaceAll(":", "")}`;
|
|
152
|
+
const selectedProjectionIdentity = stablePayload({
|
|
153
|
+
buyerForm: ticket?.buyerForm ?? null,
|
|
154
|
+
participantForm: ticket?.participantForm ?? null
|
|
155
|
+
});
|
|
156
|
+
const previousProjection = useRef(selectedProjectionIdentity);
|
|
157
|
+
const [projectionGeneration, setProjectionGeneration] = useState(0);
|
|
158
|
+
const registration = useEventRegistration({
|
|
159
|
+
client,
|
|
160
|
+
...onCheckoutSession ? { onCheckoutSession } : {}
|
|
161
|
+
});
|
|
162
|
+
const copy = { ...registrationCopy(locale), ...labels };
|
|
163
|
+
const previousEvent = useRef(`${event.id}:${event.handle}:${event.registrationMode}:${locale}`);
|
|
164
|
+
const previousCartToken = useRef(cartToken);
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
const eventIdentity = `${event.id}:${event.handle}:${event.registrationMode}:${locale}`;
|
|
167
|
+
if (previousEvent.current !== eventIdentity) {
|
|
168
|
+
previousEvent.current = eventIdentity;
|
|
169
|
+
const nextTicket = tickets.find(selectable);
|
|
170
|
+
setTicketTypeId(nextTicket?.id ?? "");
|
|
171
|
+
setQuantity(nextTicket?.minPerOrder ?? 1);
|
|
172
|
+
setEmail("");
|
|
173
|
+
setBuyerAnswers({});
|
|
174
|
+
setParticipantAnswers(Array.from({ length: nextTicket?.minPerOrder ?? 1 }, () => ({})));
|
|
175
|
+
previousProjection.current = selectedProjectionIdentity;
|
|
176
|
+
setProjectionGeneration((current) => current + 1);
|
|
177
|
+
setPreflightError(false);
|
|
178
|
+
registration.reset();
|
|
179
|
+
} else if (previousProjection.current !== selectedProjectionIdentity) {
|
|
180
|
+
previousProjection.current = selectedProjectionIdentity;
|
|
181
|
+
setBuyerAnswers({});
|
|
182
|
+
setParticipantAnswers(Array.from({ length: quantity }, () => ({})));
|
|
183
|
+
setProjectionGeneration((current) => current + 1);
|
|
184
|
+
setPreflightError(false);
|
|
185
|
+
registration.reset();
|
|
186
|
+
}
|
|
187
|
+
if (previousCartToken.current !== cartToken) {
|
|
188
|
+
previousCartToken.current = cartToken;
|
|
189
|
+
setPreflightError(false);
|
|
190
|
+
registration.reset();
|
|
191
|
+
}
|
|
192
|
+
}, [
|
|
193
|
+
cartToken,
|
|
194
|
+
event.handle,
|
|
195
|
+
event.id,
|
|
196
|
+
event.registrationMode,
|
|
197
|
+
locale,
|
|
198
|
+
quantity,
|
|
199
|
+
selectedProjectionIdentity
|
|
200
|
+
]);
|
|
201
|
+
function selectTicket(nextId) {
|
|
202
|
+
const next = tickets.find((candidate) => candidate.id === nextId);
|
|
203
|
+
if (!next || !selectable(next)) return;
|
|
204
|
+
setTicketTypeId(nextId);
|
|
205
|
+
setQuantity(next.minPerOrder);
|
|
206
|
+
setBuyerAnswers({});
|
|
207
|
+
setParticipantAnswers(Array.from({ length: next.minPerOrder }, () => ({})));
|
|
208
|
+
registration.reset();
|
|
209
|
+
setPreflightError(false);
|
|
210
|
+
}
|
|
211
|
+
function updateQuantity(next) {
|
|
212
|
+
if (!ticket) return;
|
|
213
|
+
const maximum2 = Math.min(ticket.maxPerOrder, ticket.available ?? ticket.maxPerOrder);
|
|
214
|
+
const normalized = Number.isFinite(next) ? Math.trunc(next) : ticket.minPerOrder;
|
|
215
|
+
const bounded = Math.max(ticket.minPerOrder, Math.min(maximum2, normalized));
|
|
216
|
+
setQuantity(bounded);
|
|
217
|
+
setParticipantAnswers(
|
|
218
|
+
(current) => Array.from({ length: bounded }, (_, index) => current[index] ?? {})
|
|
219
|
+
);
|
|
220
|
+
registration.reset();
|
|
221
|
+
setPreflightError(false);
|
|
222
|
+
}
|
|
223
|
+
async function handleSubmit(submitEvent) {
|
|
224
|
+
submitEvent.preventDefault();
|
|
225
|
+
if (!ticket || !selectable(ticket)) {
|
|
226
|
+
setPreflightError(true);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
setPreflightError(false);
|
|
230
|
+
const buyer = ticket.buyerForm ? { versionId: ticket.buyerForm.versionId, answers: buyerAnswers } : void 0;
|
|
231
|
+
const participants = ticket.participantForm ? participantAnswers.map((answers) => ({
|
|
232
|
+
versionId: ticket.participantForm.versionId,
|
|
233
|
+
answers
|
|
234
|
+
})) : void 0;
|
|
235
|
+
let submission;
|
|
236
|
+
if (event.registrationMode === "instant") {
|
|
237
|
+
if (!cartToken) {
|
|
238
|
+
setPreflightError(true);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
submission = {
|
|
242
|
+
registrationMode: "instant",
|
|
243
|
+
handle: event.handle,
|
|
244
|
+
idempotencyKey: "",
|
|
245
|
+
input: {
|
|
246
|
+
ticketTypeId: ticket.id,
|
|
247
|
+
quantity,
|
|
248
|
+
cartToken,
|
|
249
|
+
locale,
|
|
250
|
+
...buyer ? { buyer } : {},
|
|
251
|
+
...participants ? { participants } : {}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
} else if (event.registrationMode === "approval_then_payment") {
|
|
255
|
+
submission = {
|
|
256
|
+
registrationMode: "approval_then_payment",
|
|
257
|
+
handle: event.handle,
|
|
258
|
+
idempotencyKey: "",
|
|
259
|
+
input: {
|
|
260
|
+
ticketTypeId: ticket.id,
|
|
261
|
+
quantity,
|
|
262
|
+
contactEmail: email,
|
|
263
|
+
locale,
|
|
264
|
+
...buyer ? { buyer } : {},
|
|
265
|
+
...participants ? { participants } : {}
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
} else {
|
|
269
|
+
submission = {
|
|
270
|
+
registrationMode: "waitlist_only",
|
|
271
|
+
handle: event.handle,
|
|
272
|
+
input: { ticketTypeId: ticket.id, quantity, email }
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
await registration.submit(submission);
|
|
276
|
+
}
|
|
277
|
+
const maximum = ticket ? Math.min(ticket.maxPerOrder, ticket.available ?? ticket.maxPerOrder) : void 0;
|
|
278
|
+
const renderedState = preflightError ? "request_error" : registration.state;
|
|
279
|
+
const status = renderedState === "idle" ? "" : copy[renderedState];
|
|
280
|
+
return /* @__PURE__ */ jsxs("form", { className, "data-kotao-event-registration": true, onSubmit: handleSubmit, children: [
|
|
281
|
+
/* @__PURE__ */ jsxs("label", { children: [
|
|
282
|
+
/* @__PURE__ */ jsx("span", { children: copy.ticket }),
|
|
283
|
+
/* @__PURE__ */ jsx(
|
|
284
|
+
"select",
|
|
285
|
+
{
|
|
286
|
+
"data-kotao-event-ticket": true,
|
|
287
|
+
value: ticketTypeId,
|
|
288
|
+
onChange: (changeEvent) => selectTicket(changeEvent.currentTarget.value),
|
|
289
|
+
children: tickets.map((candidate) => /* @__PURE__ */ jsx("option", { value: candidate.id, disabled: !selectable(candidate), children: candidate.title }, candidate.id))
|
|
290
|
+
}
|
|
291
|
+
)
|
|
292
|
+
] }),
|
|
293
|
+
/* @__PURE__ */ jsxs("label", { children: [
|
|
294
|
+
/* @__PURE__ */ jsx("span", { children: copy.quantity }),
|
|
295
|
+
/* @__PURE__ */ jsx(
|
|
296
|
+
"input",
|
|
297
|
+
{
|
|
298
|
+
name: "quantity",
|
|
299
|
+
type: "number",
|
|
300
|
+
value: quantity,
|
|
301
|
+
min: ticket?.minPerOrder,
|
|
302
|
+
max: maximum,
|
|
303
|
+
required: true,
|
|
304
|
+
step: 1,
|
|
305
|
+
onChange: (changeEvent) => updateQuantity(changeEvent.currentTarget.valueAsNumber)
|
|
306
|
+
}
|
|
307
|
+
)
|
|
308
|
+
] }),
|
|
309
|
+
event.registrationMode !== "instant" ? /* @__PURE__ */ jsxs("label", { children: [
|
|
310
|
+
/* @__PURE__ */ jsx("span", { children: copy.email }),
|
|
311
|
+
/* @__PURE__ */ jsx(
|
|
312
|
+
"input",
|
|
313
|
+
{
|
|
314
|
+
type: "email",
|
|
315
|
+
required: true,
|
|
316
|
+
value: email,
|
|
317
|
+
onChange: (changeEvent) => {
|
|
318
|
+
setEmail(changeEvent.currentTarget.value);
|
|
319
|
+
setPreflightError(false);
|
|
320
|
+
registration.reset();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
)
|
|
324
|
+
] }) : null,
|
|
325
|
+
ticket?.buyerForm ? /* @__PURE__ */ jsx("div", { "data-kotao-event-buyer-form": true, children: /* @__PURE__ */ jsx(
|
|
326
|
+
StorefrontFormFields,
|
|
327
|
+
{
|
|
328
|
+
form: eventFormForRenderer(ticket.buyerForm),
|
|
329
|
+
locale,
|
|
330
|
+
...fallbackLocale === void 0 ? {} : { fallbackLocale },
|
|
331
|
+
answers: buyerAnswers,
|
|
332
|
+
idPrefix: `${instanceId}-event-${event.id}-ticket-${ticket.id}-buyer`,
|
|
333
|
+
onAnswersChange: (next) => {
|
|
334
|
+
setBuyerAnswers(next);
|
|
335
|
+
setPreflightError(false);
|
|
336
|
+
registration.reset();
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
`${projectionGeneration}:${ticket.id}:${ticket.buyerForm.versionId}`
|
|
340
|
+
) }) : null,
|
|
341
|
+
ticket?.participantForm ? participantAnswers.map((answers, index) => /* @__PURE__ */ jsx(
|
|
342
|
+
"div",
|
|
343
|
+
{
|
|
344
|
+
"data-kotao-event-participant-form": true,
|
|
345
|
+
children: /* @__PURE__ */ jsx(
|
|
346
|
+
StorefrontFormFields,
|
|
347
|
+
{
|
|
348
|
+
form: eventFormForRenderer(ticket.participantForm),
|
|
349
|
+
locale,
|
|
350
|
+
...fallbackLocale === void 0 ? {} : { fallbackLocale },
|
|
351
|
+
answers,
|
|
352
|
+
idPrefix: `${instanceId}-event-${event.id}-ticket-${ticket.id}-participant-${index}`,
|
|
353
|
+
onAnswersChange: (next) => {
|
|
354
|
+
setParticipantAnswers(
|
|
355
|
+
(current) => current.map(
|
|
356
|
+
(value, participantIndex) => participantIndex === index ? next : value
|
|
357
|
+
)
|
|
358
|
+
);
|
|
359
|
+
setPreflightError(false);
|
|
360
|
+
registration.reset();
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
)
|
|
364
|
+
},
|
|
365
|
+
`${projectionGeneration}:${ticket.id}:${ticket.participantForm.versionId}:${index}`
|
|
366
|
+
)) : null,
|
|
367
|
+
/* @__PURE__ */ jsx("button", { type: "submit", disabled: registration.state === "submitting", children: copy.submit }),
|
|
368
|
+
/* @__PURE__ */ jsx("p", { role: "status", "aria-live": "polite", "aria-atomic": "true", "data-kotao-event-state": renderedState, children: status })
|
|
369
|
+
] });
|
|
370
|
+
}
|
|
371
|
+
var OFFER_LABELS = {
|
|
372
|
+
resolving: "Loading offer\u2026",
|
|
373
|
+
claim: "Claim offer",
|
|
374
|
+
resume: "Continue to checkout",
|
|
375
|
+
claiming: "Starting checkout\u2026",
|
|
376
|
+
claimed: "Offer claimed. Continue to checkout.",
|
|
377
|
+
expired: "This offer has expired.",
|
|
378
|
+
unavailable: "This offer is not available.",
|
|
379
|
+
requestError: "Something went wrong. Please try again.",
|
|
380
|
+
retry: "Try again",
|
|
381
|
+
expires: "Offer expires at"
|
|
382
|
+
};
|
|
383
|
+
function browserLocation() {
|
|
384
|
+
return typeof window === "undefined" ? void 0 : window.location;
|
|
385
|
+
}
|
|
386
|
+
function browserHistory() {
|
|
387
|
+
return typeof window === "undefined" ? void 0 : window.history;
|
|
388
|
+
}
|
|
389
|
+
function EventApprovalOffer({
|
|
390
|
+
client,
|
|
391
|
+
offerId,
|
|
392
|
+
cartToken,
|
|
393
|
+
locale,
|
|
394
|
+
idempotencyKey,
|
|
395
|
+
location,
|
|
396
|
+
history,
|
|
397
|
+
labels,
|
|
398
|
+
onCheckoutSession,
|
|
399
|
+
initialResolution,
|
|
400
|
+
initialState,
|
|
401
|
+
className
|
|
402
|
+
}) {
|
|
403
|
+
const copy = { ...OFFER_LABELS, ...labels };
|
|
404
|
+
const token = useRef(null);
|
|
405
|
+
const consumedHrefMarkers = useRef(/* @__PURE__ */ new Set());
|
|
406
|
+
const offerGeneration = useRef(0);
|
|
407
|
+
const resolvedGeneration = useRef(initialResolution ? 0 : null);
|
|
408
|
+
const mounted = useRef(false);
|
|
409
|
+
const strictCleanupGeneration = useRef(null);
|
|
410
|
+
const activeDependencies = useRef({ client, cartToken, locale, onCheckoutSession });
|
|
411
|
+
const claimIdempotencyKey = useMemo(
|
|
412
|
+
() => idempotencyKey ?? `events-claim-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
413
|
+
[idempotencyKey, offerId]
|
|
414
|
+
);
|
|
415
|
+
const resolveIdempotencyKey = useMemo(
|
|
416
|
+
() => `events-resolve-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
417
|
+
[offerId]
|
|
418
|
+
);
|
|
419
|
+
const [canClaim, setCanClaim] = useState(initialResolution?.state === "active");
|
|
420
|
+
const [resolution, setResolution] = useState(
|
|
421
|
+
initialResolution ?? null
|
|
422
|
+
);
|
|
423
|
+
const [state, setState] = useState(
|
|
424
|
+
initialResolution ? initialResolution.state === "claimed" ? "claimed" : "active" : initialState ?? "resolving"
|
|
425
|
+
);
|
|
426
|
+
async function resolveCapability(generation, claimToken) {
|
|
427
|
+
try {
|
|
428
|
+
const offer = await client.resolveOffer(offerId, claimToken, resolveIdempotencyKey);
|
|
429
|
+
if (!mounted.current || generation !== offerGeneration.current) return;
|
|
430
|
+
resolvedGeneration.current = generation;
|
|
431
|
+
setResolution(offer);
|
|
432
|
+
if (offer.state === "claimed") setState("claimed");
|
|
433
|
+
else if (new Date(offer.expiresAt).getTime() <= Date.now()) setState("expired");
|
|
434
|
+
else setState("active");
|
|
435
|
+
} catch (error) {
|
|
436
|
+
if (!mounted.current || generation !== offerGeneration.current) return;
|
|
437
|
+
setState(
|
|
438
|
+
error instanceof StorefrontEventsRequestError && error.status === 409 ? "unavailable" : "request_error"
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
useLayoutEffect(() => {
|
|
443
|
+
if (strictCleanupGeneration.current !== null && offerGeneration.current === strictCleanupGeneration.current + 1) {
|
|
444
|
+
offerGeneration.current = strictCleanupGeneration.current;
|
|
445
|
+
}
|
|
446
|
+
strictCleanupGeneration.current = null;
|
|
447
|
+
mounted.current = true;
|
|
448
|
+
return () => {
|
|
449
|
+
mounted.current = false;
|
|
450
|
+
strictCleanupGeneration.current = offerGeneration.current;
|
|
451
|
+
offerGeneration.current += 1;
|
|
452
|
+
};
|
|
453
|
+
}, []);
|
|
454
|
+
useLayoutEffect(() => {
|
|
455
|
+
const previous = activeDependencies.current;
|
|
456
|
+
if (previous.client === client && previous.cartToken === cartToken && previous.locale === locale && previous.onCheckoutSession === onCheckoutSession) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
activeDependencies.current = { client, cartToken, locale, onCheckoutSession };
|
|
460
|
+
offerGeneration.current += 1;
|
|
461
|
+
resolvedGeneration.current = null;
|
|
462
|
+
token.current = null;
|
|
463
|
+
setCanClaim(false);
|
|
464
|
+
setResolution(null);
|
|
465
|
+
setState("unavailable");
|
|
466
|
+
}, [cartToken, client, locale, onCheckoutSession]);
|
|
467
|
+
useLayoutEffect(() => {
|
|
468
|
+
if (initialState !== void 0) return;
|
|
469
|
+
const currentLocation = location ?? browserLocation();
|
|
470
|
+
const currentHistory = history ?? browserHistory();
|
|
471
|
+
if (currentLocation === void 0 || currentHistory === void 0) {
|
|
472
|
+
if (initialResolution === void 0) setState("unavailable");
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
const hrefMarker = offerTokenHrefMarker(currentLocation.href);
|
|
476
|
+
if (consumedHrefMarkers.current.has(hrefMarker)) return;
|
|
477
|
+
consumedHrefMarkers.current.add(hrefMarker);
|
|
478
|
+
offerGeneration.current += 1;
|
|
479
|
+
const generation = offerGeneration.current;
|
|
480
|
+
resolvedGeneration.current = null;
|
|
481
|
+
token.current = null;
|
|
482
|
+
setCanClaim(false);
|
|
483
|
+
setResolution(null);
|
|
484
|
+
setState("resolving");
|
|
485
|
+
const claimToken = consumeOfferTokenFragment(currentLocation, currentHistory);
|
|
486
|
+
consumedHrefMarkers.current.add(offerTokenHrefMarker(currentLocation.href));
|
|
487
|
+
token.current = claimToken;
|
|
488
|
+
setCanClaim(claimToken !== null);
|
|
489
|
+
if (claimToken === null) {
|
|
490
|
+
if (initialResolution === void 0) setState("unavailable");
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
void resolveCapability(generation, claimToken);
|
|
494
|
+
});
|
|
495
|
+
function retryResolve() {
|
|
496
|
+
const claimToken = token.current;
|
|
497
|
+
if (claimToken === null) {
|
|
498
|
+
setState("unavailable");
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
const generation = offerGeneration.current;
|
|
502
|
+
setState("resolving");
|
|
503
|
+
void resolveCapability(generation, claimToken);
|
|
504
|
+
}
|
|
505
|
+
async function claim() {
|
|
506
|
+
const claimToken = token.current;
|
|
507
|
+
const generation = offerGeneration.current;
|
|
508
|
+
if (claimToken === null || resolvedGeneration.current !== generation || resolution?.offerId !== offerId) {
|
|
509
|
+
setState("unavailable");
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
setState("claiming");
|
|
513
|
+
try {
|
|
514
|
+
const session = await client.claimOffer(
|
|
515
|
+
offerId,
|
|
516
|
+
{ claimToken, cartToken, locale },
|
|
517
|
+
claimIdempotencyKey
|
|
518
|
+
);
|
|
519
|
+
if (!mounted.current || generation !== offerGeneration.current) return;
|
|
520
|
+
token.current = null;
|
|
521
|
+
setCanClaim(false);
|
|
522
|
+
setState("claimed");
|
|
523
|
+
onCheckoutSession?.(session);
|
|
524
|
+
} catch (error) {
|
|
525
|
+
if (!mounted.current || generation !== offerGeneration.current) return;
|
|
526
|
+
setState(
|
|
527
|
+
error instanceof StorefrontEventsRequestError && error.status === 409 ? "unavailable" : "request_error"
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
const status = state === "resolving" ? copy.resolving : state === "claiming" ? copy.claiming : state === "claimed" ? copy.claimed : state === "expired" ? copy.expired : state === "unavailable" ? copy.unavailable : state === "request_error" ? copy.requestError : null;
|
|
532
|
+
return /* @__PURE__ */ jsxs("section", { className, "data-kotao-event-approval-offer": true, children: [
|
|
533
|
+
resolution ? /* @__PURE__ */ jsxs("header", { children: [
|
|
534
|
+
/* @__PURE__ */ jsx("h1", { children: resolution.eventTitle }),
|
|
535
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
536
|
+
resolution.ticketTypeTitle,
|
|
537
|
+
" \xB7 ",
|
|
538
|
+
resolution.quantity
|
|
539
|
+
] }),
|
|
540
|
+
/* @__PURE__ */ jsx("time", { dateTime: resolution.occurrenceStartsAt, children: resolution.occurrenceStartsAt })
|
|
541
|
+
] }) : null,
|
|
542
|
+
(state === "active" || state === "claimed" && canClaim || state === "request_error" && canClaim) && resolution ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
543
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
544
|
+
copy.expires,
|
|
545
|
+
": ",
|
|
546
|
+
/* @__PURE__ */ jsx("time", { dateTime: resolution.expiresAt, children: resolution.expiresAt })
|
|
547
|
+
] }),
|
|
548
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: claim, children: state === "claimed" ? copy.resume : copy.claim })
|
|
549
|
+
] }) : null,
|
|
550
|
+
state === "request_error" && canClaim && resolution === null ? /* @__PURE__ */ jsx("button", { type: "button", onClick: retryResolve, children: copy.retry }) : null,
|
|
551
|
+
/* @__PURE__ */ jsx("p", { role: "status", "aria-live": "polite", "aria-atomic": "true", children: status })
|
|
552
|
+
] });
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
export { EventApprovalOffer, EventRegistrationForm, useEventRegistration };
|
|
556
|
+
//# sourceMappingURL=events-react.js.map
|
|
557
|
+
//# sourceMappingURL=events-react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/events/react.tsx"],"names":["maximum"],"mappings":"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","file":"events-react.js","sourcesContent":["import {\n type FormEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\n\nimport { StorefrontFormFields } from '../react/form'\nimport type { FormAnswers, PublicForm } from '../forms'\nimport {\n consumeOfferTokenFragment,\n offerTokenHrefMarker,\n type OfferTokenHistory,\n type OfferTokenLocation,\n} from './offer-token'\nimport { StorefrontEventsRequestError, type EventsClient } from './client'\nimport type {\n EventApprovalOfferResolution,\n EventCheckoutSession,\n EventRegistrationSubmission,\n PublicEvent,\n PublicEventForm,\n PublicEventTicketType,\n} from './types'\n\nexport type EventRegistrationState =\n | 'idle'\n | 'submitting'\n | 'awaiting_approval'\n | 'waitlisted'\n | 'checkout_ready'\n | 'request_error'\n\nexport function useEventRegistration(input: {\n readonly client: EventsClient\n readonly onCheckoutSession?: (session: EventCheckoutSession) => void\n}): {\n readonly state: EventRegistrationState\n readonly submit: (submission: EventRegistrationSubmission) => Promise<void>\n readonly reset: () => void\n} {\n const [state, setState] = useState<EventRegistrationState>('idle')\n const generation = useRef(0)\n const logicalPayload = useRef<string | null>(null)\n const idempotencyKey = useRef<string | null>(null)\n const activeClient = useRef(input.client)\n const activeCallback = useRef(input.onCheckoutSession)\n\n useEffect(() => {\n if (\n activeClient.current !== input.client ||\n activeCallback.current !== input.onCheckoutSession\n ) {\n activeClient.current = input.client\n activeCallback.current = input.onCheckoutSession\n generation.current += 1\n setState('idle')\n }\n }, [input.client, input.onCheckoutSession])\n\n useEffect(\n () => () => {\n generation.current += 1\n },\n [],\n )\n\n const reset = useCallback(() => {\n generation.current += 1\n setState('idle')\n }, [])\n\n async function submit(submission: EventRegistrationSubmission): Promise<void> {\n const attempt = ++generation.current\n const prepared = registrationSubmission(submission, logicalPayload, idempotencyKey)\n setState('submitting')\n try {\n const result = await input.client.submitRegistration(prepared)\n if (attempt !== generation.current) return\n if (result.kind === 'checkout') {\n input.onCheckoutSession?.(result.checkoutSession)\n setState('checkout_ready')\n } else if (result.kind === 'approval') {\n setState('awaiting_approval')\n } else {\n setState('waitlisted')\n }\n } catch {\n if (attempt !== generation.current) return\n setState('request_error')\n }\n }\n\n return { state, submit, reset }\n}\n\nfunction registrationKey(mode: PublicEvent['registrationMode']): string {\n const kind = mode === 'approval_then_payment' ? 'application' : 'checkout'\n return `events-${kind}-${Date.now()}-${Math.random().toString(36).slice(2)}`\n}\n\nfunction stablePayload(value: unknown): string {\n return JSON.stringify(value, (_key, item: unknown) => {\n if (item === null || typeof item !== 'object' || Array.isArray(item)) return item\n return Object.fromEntries(\n Object.entries(item as Record<string, unknown>).sort(([left], [right]) =>\n left.localeCompare(right),\n ),\n )\n })\n}\n\nfunction registrationSubmission(\n submission: EventRegistrationSubmission,\n previousPayload: { current: string | null },\n previousKey: { current: string | null },\n): EventRegistrationSubmission {\n if (submission.registrationMode === 'waitlist_only') return submission\n if (submission.idempotencyKey.trim() !== '') return submission\n const payload = {\n registrationMode: submission.registrationMode,\n handle: submission.handle,\n input: submission.input,\n }\n const identity = stablePayload(payload)\n if (identity !== previousPayload.current || previousKey.current === null) {\n previousPayload.current = identity\n previousKey.current = registrationKey(submission.registrationMode)\n }\n return { ...submission, idempotencyKey: previousKey.current }\n}\n\n/** Adapts an event-owned form without claiming that it is a published standalone Forms version. */\nfunction eventFormForRenderer(form: PublicEventForm): PublicForm {\n return {\n definition: {\n id: form.definitionId,\n handle: form.definitionId,\n title: form.title,\n },\n version: {\n id: form.versionId,\n definitionId: form.definitionId,\n schema: form.schema,\n },\n } as PublicForm\n}\n\nconst REGISTRATION_COPY = {\n en: {\n submit: 'Register',\n submitting: 'Submitting…',\n awaiting_approval: 'Application received. Awaiting approval.',\n waitlisted: 'You joined the waitlist.',\n checkout_ready: 'Registration ready for checkout.',\n request_error: 'Something went wrong. Please try again.',\n email: 'Email',\n quantity: 'Quantity',\n ticket: 'Ticket',\n },\n de: {\n submit: 'Anmelden',\n submitting: 'Wird gesendet…',\n awaiting_approval: 'Anmeldung erhalten. Sie wartet auf Freigabe.',\n waitlisted: 'Du stehst auf der Warteliste.',\n checkout_ready: 'Die Anmeldung kann bezahlt werden.',\n request_error: 'Etwas ist schiefgelaufen. Bitte versuche es erneut.',\n email: 'E-Mail',\n quantity: 'Anzahl',\n ticket: 'Ticket',\n },\n} as const\n\nexport interface EventRegistrationLabels {\n readonly submit: string\n readonly submitting: string\n readonly awaiting_approval: string\n readonly waitlisted: string\n readonly checkout_ready: string\n readonly request_error: string\n readonly email: string\n readonly quantity: string\n readonly ticket: string\n}\n\nfunction registrationCopy(locale: string): EventRegistrationLabels {\n return locale.toLowerCase().startsWith('de') ? REGISTRATION_COPY.de : REGISTRATION_COPY.en\n}\n\nfunction selectable(ticket: PublicEventTicketType): boolean {\n return (\n ticket.salesState === 'on_sale' &&\n ticket.maxPerOrder >= ticket.minPerOrder &&\n (ticket.available === null || ticket.available >= ticket.minPerOrder)\n )\n}\n\nexport interface EventRegistrationFormProps {\n readonly event: PublicEvent\n readonly locale: string\n readonly client: EventsClient\n readonly cartToken?: string\n readonly fallbackLocale?: string\n readonly onCheckoutSession?: (session: EventCheckoutSession) => void\n readonly labels?: Partial<EventRegistrationLabels>\n readonly className?: string\n}\n\nexport function EventRegistrationForm({\n event,\n locale,\n client,\n cartToken,\n fallbackLocale,\n onCheckoutSession,\n labels,\n className,\n}: EventRegistrationFormProps) {\n const tickets = event.occurrences.flatMap((occurrence) => occurrence.ticketTypes)\n const firstTicket = tickets.find(selectable)\n const [ticketTypeId, setTicketTypeId] = useState(firstTicket?.id ?? '')\n const ticket = tickets.find((candidate) => candidate.id === ticketTypeId)\n const initialQuantity = ticket?.minPerOrder ?? 1\n const [quantity, setQuantity] = useState(initialQuantity)\n const [email, setEmail] = useState('')\n const [preflightError, setPreflightError] = useState(false)\n const [buyerAnswers, setBuyerAnswers] = useState<FormAnswers>({})\n const [participantAnswers, setParticipantAnswers] = useState<FormAnswers[]>(() =>\n Array.from({ length: initialQuantity }, () => ({})),\n )\n const generatedId = useId()\n const instanceId = `event-registration-${generatedId.replaceAll(':', '')}`\n const selectedProjectionIdentity = stablePayload({\n buyerForm: ticket?.buyerForm ?? null,\n participantForm: ticket?.participantForm ?? null,\n })\n const previousProjection = useRef(selectedProjectionIdentity)\n const [projectionGeneration, setProjectionGeneration] = useState(0)\n const registration = useEventRegistration({\n client,\n ...(onCheckoutSession ? { onCheckoutSession } : {}),\n })\n const copy = { ...registrationCopy(locale), ...labels }\n const previousEvent = useRef(`${event.id}:${event.handle}:${event.registrationMode}:${locale}`)\n const previousCartToken = useRef(cartToken)\n\n useEffect(() => {\n const eventIdentity = `${event.id}:${event.handle}:${event.registrationMode}:${locale}`\n if (previousEvent.current !== eventIdentity) {\n previousEvent.current = eventIdentity\n const nextTicket = tickets.find(selectable)\n setTicketTypeId(nextTicket?.id ?? '')\n setQuantity(nextTicket?.minPerOrder ?? 1)\n setEmail('')\n setBuyerAnswers({})\n setParticipantAnswers(Array.from({ length: nextTicket?.minPerOrder ?? 1 }, () => ({})))\n previousProjection.current = selectedProjectionIdentity\n setProjectionGeneration((current) => current + 1)\n setPreflightError(false)\n registration.reset()\n } else if (previousProjection.current !== selectedProjectionIdentity) {\n previousProjection.current = selectedProjectionIdentity\n setBuyerAnswers({})\n setParticipantAnswers(Array.from({ length: quantity }, () => ({})))\n setProjectionGeneration((current) => current + 1)\n setPreflightError(false)\n registration.reset()\n }\n if (previousCartToken.current !== cartToken) {\n previousCartToken.current = cartToken\n setPreflightError(false)\n registration.reset()\n }\n }, [\n cartToken,\n event.handle,\n event.id,\n event.registrationMode,\n locale,\n quantity,\n selectedProjectionIdentity,\n ])\n\n function selectTicket(nextId: string): void {\n const next = tickets.find((candidate) => candidate.id === nextId)\n if (!next || !selectable(next)) return\n setTicketTypeId(nextId)\n setQuantity(next.minPerOrder)\n setBuyerAnswers({})\n setParticipantAnswers(Array.from({ length: next.minPerOrder }, () => ({})))\n registration.reset()\n setPreflightError(false)\n }\n\n function updateQuantity(next: number): void {\n if (!ticket) return\n const maximum = Math.min(ticket.maxPerOrder, ticket.available ?? ticket.maxPerOrder)\n const normalized = Number.isFinite(next) ? Math.trunc(next) : ticket.minPerOrder\n const bounded = Math.max(ticket.minPerOrder, Math.min(maximum, normalized))\n setQuantity(bounded)\n setParticipantAnswers((current) =>\n Array.from({ length: bounded }, (_, index) => current[index] ?? {}),\n )\n registration.reset()\n setPreflightError(false)\n }\n\n async function handleSubmit(submitEvent: FormEvent<HTMLFormElement>): Promise<void> {\n submitEvent.preventDefault()\n if (!ticket || !selectable(ticket)) {\n setPreflightError(true)\n return\n }\n setPreflightError(false)\n const buyer = ticket.buyerForm\n ? { versionId: ticket.buyerForm.versionId, answers: buyerAnswers }\n : undefined\n const participants = ticket.participantForm\n ? participantAnswers.map((answers) => ({\n versionId: ticket.participantForm!.versionId,\n answers,\n }))\n : undefined\n\n let submission: EventRegistrationSubmission\n if (event.registrationMode === 'instant') {\n if (!cartToken) {\n setPreflightError(true)\n return\n }\n submission = {\n registrationMode: 'instant',\n handle: event.handle,\n idempotencyKey: '',\n input: {\n ticketTypeId: ticket.id,\n quantity,\n cartToken,\n locale,\n ...(buyer ? { buyer } : {}),\n ...(participants ? { participants } : {}),\n },\n }\n } else if (event.registrationMode === 'approval_then_payment') {\n submission = {\n registrationMode: 'approval_then_payment',\n handle: event.handle,\n idempotencyKey: '',\n input: {\n ticketTypeId: ticket.id,\n quantity,\n contactEmail: email,\n locale,\n ...(buyer ? { buyer } : {}),\n ...(participants ? { participants } : {}),\n },\n }\n } else {\n submission = {\n registrationMode: 'waitlist_only',\n handle: event.handle,\n input: { ticketTypeId: ticket.id, quantity, email },\n }\n }\n await registration.submit(submission)\n }\n\n const maximum = ticket\n ? Math.min(ticket.maxPerOrder, ticket.available ?? ticket.maxPerOrder)\n : undefined\n const renderedState = preflightError ? 'request_error' : registration.state\n const status = renderedState === 'idle' ? '' : copy[renderedState]\n\n return (\n <form className={className} data-kotao-event-registration onSubmit={handleSubmit}>\n <label>\n <span>{copy.ticket}</span>\n <select\n data-kotao-event-ticket\n value={ticketTypeId}\n onChange={(changeEvent) => selectTicket(changeEvent.currentTarget.value)}\n >\n {tickets.map((candidate) => (\n <option key={candidate.id} value={candidate.id} disabled={!selectable(candidate)}>\n {candidate.title}\n </option>\n ))}\n </select>\n </label>\n <label>\n <span>{copy.quantity}</span>\n <input\n name=\"quantity\"\n type=\"number\"\n value={quantity}\n min={ticket?.minPerOrder}\n max={maximum}\n required\n step={1}\n onChange={(changeEvent) => updateQuantity(changeEvent.currentTarget.valueAsNumber)}\n />\n </label>\n {event.registrationMode !== 'instant' ? (\n <label>\n <span>{copy.email}</span>\n <input\n type=\"email\"\n required\n value={email}\n onChange={(changeEvent) => {\n setEmail(changeEvent.currentTarget.value)\n setPreflightError(false)\n registration.reset()\n }}\n />\n </label>\n ) : null}\n {ticket?.buyerForm ? (\n <div data-kotao-event-buyer-form>\n <StorefrontFormFields\n key={`${projectionGeneration}:${ticket.id}:${ticket.buyerForm.versionId}`}\n form={eventFormForRenderer(ticket.buyerForm)}\n locale={locale}\n {...(fallbackLocale === undefined ? {} : { fallbackLocale })}\n answers={buyerAnswers}\n idPrefix={`${instanceId}-event-${event.id}-ticket-${ticket.id}-buyer`}\n onAnswersChange={(next) => {\n setBuyerAnswers(next)\n setPreflightError(false)\n registration.reset()\n }}\n />\n </div>\n ) : null}\n {ticket?.participantForm\n ? participantAnswers.map((answers, index) => (\n <div\n key={`${projectionGeneration}:${ticket.id}:${ticket.participantForm!.versionId}:${index}`}\n data-kotao-event-participant-form\n >\n <StorefrontFormFields\n form={eventFormForRenderer(ticket.participantForm!)}\n locale={locale}\n {...(fallbackLocale === undefined ? {} : { fallbackLocale })}\n answers={answers}\n idPrefix={`${instanceId}-event-${event.id}-ticket-${ticket.id}-participant-${index}`}\n onAnswersChange={(next) => {\n setParticipantAnswers((current) =>\n current.map((value, participantIndex) =>\n participantIndex === index ? next : value,\n ),\n )\n setPreflightError(false)\n registration.reset()\n }}\n />\n </div>\n ))\n : null}\n <button type=\"submit\" disabled={registration.state === 'submitting'}>\n {copy.submit}\n </button>\n <p role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" data-kotao-event-state={renderedState}>\n {status}\n </p>\n </form>\n )\n}\n\nexport type EventOfferState =\n | 'resolving'\n | 'active'\n | 'claiming'\n | 'claimed'\n | 'expired'\n | 'unavailable'\n | 'request_error'\n\nexport interface EventApprovalOfferLabels {\n readonly resolving: ReactNode\n readonly claim: ReactNode\n readonly resume: ReactNode\n readonly claiming: ReactNode\n readonly claimed: ReactNode\n readonly expired: ReactNode\n readonly unavailable: ReactNode\n readonly requestError: ReactNode\n readonly retry?: ReactNode\n readonly expires: ReactNode\n}\n\nconst OFFER_LABELS: EventApprovalOfferLabels = {\n resolving: 'Loading offer…',\n claim: 'Claim offer',\n resume: 'Continue to checkout',\n claiming: 'Starting checkout…',\n claimed: 'Offer claimed. Continue to checkout.',\n expired: 'This offer has expired.',\n unavailable: 'This offer is not available.',\n requestError: 'Something went wrong. Please try again.',\n retry: 'Try again',\n expires: 'Offer expires at',\n}\n\nexport interface EventApprovalOfferProps {\n readonly client: EventsClient\n readonly offerId: string\n readonly cartToken: string\n readonly locale: string\n readonly idempotencyKey?: string\n readonly location?: OfferTokenLocation\n readonly history?: OfferTokenHistory\n readonly labels?: Partial<EventApprovalOfferLabels>\n readonly onCheckoutSession?: (session: EventCheckoutSession) => void\n readonly initialResolution?: EventApprovalOfferResolution\n readonly initialState?: Exclude<EventOfferState, 'resolving' | 'active' | 'claiming'>\n readonly className?: string\n}\n\nfunction browserLocation(): OfferTokenLocation | undefined {\n return typeof window === 'undefined' ? undefined : window.location\n}\n\nfunction browserHistory(): OfferTokenHistory | undefined {\n return typeof window === 'undefined' ? undefined : window.history\n}\n\nexport function EventApprovalOffer({\n client,\n offerId,\n cartToken,\n locale,\n idempotencyKey,\n location,\n history,\n labels,\n onCheckoutSession,\n initialResolution,\n initialState,\n className,\n}: EventApprovalOfferProps) {\n const copy = { ...OFFER_LABELS, ...labels }\n const token = useRef<string | null>(null)\n const consumedHrefMarkers = useRef(new Set<string>())\n const offerGeneration = useRef(0)\n const resolvedGeneration = useRef<number | null>(initialResolution ? 0 : null)\n const mounted = useRef(false)\n const strictCleanupGeneration = useRef<number | null>(null)\n const activeDependencies = useRef({ client, cartToken, locale, onCheckoutSession })\n const claimIdempotencyKey = useMemo(\n () => idempotencyKey ?? `events-claim-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n [idempotencyKey, offerId],\n )\n const resolveIdempotencyKey = useMemo(\n () => `events-resolve-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n [offerId],\n )\n const [canClaim, setCanClaim] = useState(initialResolution?.state === 'active')\n const [resolution, setResolution] = useState<EventApprovalOfferResolution | null>(\n initialResolution ?? null,\n )\n const [state, setState] = useState<EventOfferState>(\n initialResolution\n ? initialResolution.state === 'claimed'\n ? 'claimed'\n : 'active'\n : (initialState ?? 'resolving'),\n )\n\n async function resolveCapability(generation: number, claimToken: string): Promise<void> {\n try {\n const offer = await client.resolveOffer(offerId, claimToken, resolveIdempotencyKey)\n if (!mounted.current || generation !== offerGeneration.current) return\n resolvedGeneration.current = generation\n setResolution(offer)\n if (offer.state === 'claimed') setState('claimed')\n else if (new Date(offer.expiresAt).getTime() <= Date.now()) setState('expired')\n else setState('active')\n } catch (error) {\n if (!mounted.current || generation !== offerGeneration.current) return\n setState(\n error instanceof StorefrontEventsRequestError && error.status === 409\n ? 'unavailable'\n : 'request_error',\n )\n }\n }\n\n useLayoutEffect(() => {\n if (\n strictCleanupGeneration.current !== null &&\n offerGeneration.current === strictCleanupGeneration.current + 1\n ) {\n // React Strict Mode immediately remounts effects; restore the still-live attempt without\n // issuing a second capability-bearing request.\n offerGeneration.current = strictCleanupGeneration.current\n }\n strictCleanupGeneration.current = null\n mounted.current = true\n return () => {\n mounted.current = false\n strictCleanupGeneration.current = offerGeneration.current\n offerGeneration.current += 1\n }\n }, [])\n\n useLayoutEffect(() => {\n const previous = activeDependencies.current\n if (\n previous.client === client &&\n previous.cartToken === cartToken &&\n previous.locale === locale &&\n previous.onCheckoutSession === onCheckoutSession\n ) {\n return\n }\n activeDependencies.current = { client, cartToken, locale, onCheckoutSession }\n offerGeneration.current += 1\n resolvedGeneration.current = null\n token.current = null\n setCanClaim(false)\n setResolution(null)\n setState('unavailable')\n }, [cartToken, client, locale, onCheckoutSession])\n\n useLayoutEffect(() => {\n if (initialState !== undefined) return\n const currentLocation = location ?? browserLocation()\n const currentHistory = history ?? browserHistory()\n if (currentLocation === undefined || currentHistory === undefined) {\n if (initialResolution === undefined) setState('unavailable')\n return\n }\n const hrefMarker = offerTokenHrefMarker(currentLocation.href)\n if (consumedHrefMarkers.current.has(hrefMarker)) return\n consumedHrefMarkers.current.add(hrefMarker)\n offerGeneration.current += 1\n const generation = offerGeneration.current\n resolvedGeneration.current = null\n token.current = null\n setCanClaim(false)\n setResolution(null)\n setState('resolving')\n const claimToken = consumeOfferTokenFragment(currentLocation, currentHistory)\n consumedHrefMarkers.current.add(offerTokenHrefMarker(currentLocation.href))\n token.current = claimToken\n setCanClaim(claimToken !== null)\n if (claimToken === null) {\n if (initialResolution === undefined) setState('unavailable')\n return\n }\n void resolveCapability(generation, claimToken)\n })\n\n function retryResolve(): void {\n const claimToken = token.current\n if (claimToken === null) {\n setState('unavailable')\n return\n }\n const generation = offerGeneration.current\n setState('resolving')\n void resolveCapability(generation, claimToken)\n }\n\n async function claim(): Promise<void> {\n const claimToken = token.current\n const generation = offerGeneration.current\n if (\n claimToken === null ||\n resolvedGeneration.current !== generation ||\n resolution?.offerId !== offerId\n ) {\n setState('unavailable')\n return\n }\n setState('claiming')\n try {\n const session = await client.claimOffer(\n offerId,\n { claimToken, cartToken, locale },\n claimIdempotencyKey,\n )\n if (!mounted.current || generation !== offerGeneration.current) return\n token.current = null\n setCanClaim(false)\n setState('claimed')\n onCheckoutSession?.(session)\n } catch (error) {\n if (!mounted.current || generation !== offerGeneration.current) return\n setState(\n error instanceof StorefrontEventsRequestError && error.status === 409\n ? 'unavailable'\n : 'request_error',\n )\n }\n }\n\n const status =\n state === 'resolving'\n ? copy.resolving\n : state === 'claiming'\n ? copy.claiming\n : state === 'claimed'\n ? copy.claimed\n : state === 'expired'\n ? copy.expired\n : state === 'unavailable'\n ? copy.unavailable\n : state === 'request_error'\n ? copy.requestError\n : null\n\n return (\n <section className={className} data-kotao-event-approval-offer>\n {resolution ? (\n <header>\n <h1>{resolution.eventTitle}</h1>\n <p>\n {resolution.ticketTypeTitle} · {resolution.quantity}\n </p>\n <time dateTime={resolution.occurrenceStartsAt}>{resolution.occurrenceStartsAt}</time>\n </header>\n ) : null}\n {(state === 'active' ||\n (state === 'claimed' && canClaim) ||\n (state === 'request_error' && canClaim)) &&\n resolution ? (\n <>\n <p>\n {copy.expires}: <time dateTime={resolution.expiresAt}>{resolution.expiresAt}</time>\n </p>\n <button type=\"button\" onClick={claim}>\n {state === 'claimed' ? copy.resume : copy.claim}\n </button>\n </>\n ) : null}\n {state === 'request_error' && canClaim && resolution === null ? (\n <button type=\"button\" onClick={retryResolve}>\n {copy.retry}\n </button>\n ) : null}\n <p role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n {status}\n </p>\n </section>\n )\n}\n"]}
|