@session-services/web-elements 0.1.28 → 0.1.31

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.
Files changed (37) hide show
  1. package/README.md +5 -0
  2. package/dist/cjs/{index-BYBgrATL.js → index-B2ZmNnji.js} +292 -245
  3. package/dist/cjs/loader.cjs.js +2 -2
  4. package/dist/cjs/session-services-elements.cjs.js +3 -3
  5. package/dist/cjs/session-services-formatted-text.cjs.entry.js +8 -20
  6. package/dist/cjs/session-services-ticketing.cjs.entry.js +2188 -23012
  7. package/dist/collection/collection-manifest.json +4 -3
  8. package/dist/collection/components/session-services-ticketing/bot-detection.js +83 -0
  9. package/dist/collection/components/session-services-ticketing/bot-detection.test.js +74 -0
  10. package/dist/collection/components/session-services-ticketing/session-services-ticketing.css +164 -36
  11. package/dist/collection/components/session-services-ticketing/session-services-ticketing.js +811 -262
  12. package/dist/collection/components/session-services-ticketing/session-services-ticketing.logic.js +39 -8
  13. package/dist/collection/components/session-services-ticketing/session-services-ticketing.logic.test.js +47 -3
  14. package/dist/collection/components/session-services-ticketing/session-services-ticketing.test.js +611 -20
  15. package/dist/components/index.d.ts +2 -0
  16. package/dist/components/index.js +1 -1311
  17. package/dist/components/session-services-formatted-text.js +1 -1802
  18. package/dist/components/session-services-ticketing.js +1 -25072
  19. package/dist/esm/{index-CNOpF6tk.js → index-DhbVMqIT.js} +292 -245
  20. package/dist/esm/loader.js +3 -3
  21. package/dist/esm/session-services-elements.js +4 -4
  22. package/dist/esm/session-services-formatted-text.entry.js +8 -20
  23. package/dist/esm/session-services-ticketing.entry.js +2188 -23012
  24. package/dist/session-services-elements/{p-703444ed.entry.js → p-8483ca88.entry.js} +1 -1
  25. package/dist/session-services-elements/p-DhbVMqIT.js +2 -0
  26. package/dist/session-services-elements/p-d7264f6b.entry.js +1 -0
  27. package/dist/session-services-elements/session-services-elements.esm.js +1 -1
  28. package/dist/types/components/session-services-ticketing/bot-detection.d.ts +13 -0
  29. package/dist/types/components/session-services-ticketing/bot-detection.test.d.ts +1 -0
  30. package/dist/types/components/session-services-ticketing/session-services-ticketing.d.ts +67 -9
  31. package/dist/types/components/session-services-ticketing/session-services-ticketing.logic.d.ts +11 -2
  32. package/dist/types/components.d.ts +36 -8
  33. package/dist/types/index.d.ts +1 -1
  34. package/dist/types/stencil-public-runtime.d.ts +67 -5
  35. package/package.json +15 -11
  36. package/dist/session-services-elements/p-1acfcdfd.entry.js +0 -1
  37. package/dist/session-services-elements/p-CNOpF6tk.js +0 -2
@@ -1,15 +1,58 @@
1
1
  import { createClient } from "@session-services/sdk";
2
- import { buildOrderChannel, createAnalytics, formatPrice, } from "@session-services/sdk/analytics";
3
- import { formatNaiveDateTime } from "@session-services/utils/naive-datetime";
2
+ import { buildOrderChannel, createAnalytics, } from "@session-services/sdk/analytics";
3
+ import { fromMinorUnits } from "@session-services/utils/currency";
4
+ import { parseNaiveDateTime } from "@session-services/utils/naive-datetime";
4
5
  import { isSectionSoldOut } from "@session-services/utils/ticket-availability";
5
6
  import { normalizeCouponCode } from "@session-services/utils/ticket-quote";
6
7
  import { Host,
7
8
  // biome-ignore lint/correctness/noUnusedImports: h is required by Stencil JSX transform
8
9
  h, } from "@stencil/core";
9
- import { admissionPriceSavings, discountCouponFromSearch, getAdmissionDisplayState, getAdmissionPriceDisplay, getTicketingState, parseSelectionKey, previewQuoteItems, priceTotal, quoteItemsBySelection, selectionKey, topLevelTicketItems, visibleAdmissions, } from "./session-services-ticketing.logic";
10
+ import { detectBot, isProductionApi } from "./bot-detection";
11
+ import { admissionPriceSavings, discountCouponFromSearch, eventTimeZone, getAdmissionDisplayState, getAdmissionPriceDisplay, getTicketingState, parseSelectionKey, previewQuoteItems, priceTotal, quoteItemsBySelection, selectionKey, topLevelTicketItems, visibleAdmissions, } from "./session-services-ticketing.logic";
10
12
  const quoteTotal = (quote) => quote.price?.total ?? 0;
13
+ function majorUnits(value, currency) {
14
+ return fromMinorUnits(value, currency ?? "");
15
+ }
16
+ function priceAmount(price, currency) {
17
+ return majorUnits(priceTotal(price), price?.currency ?? currency);
18
+ }
19
+ function quoteAmount(quote, currency) {
20
+ return majorUnits(quoteTotal(quote), quote.price?.currency ?? currency);
21
+ }
11
22
  const QUOTE_DEBOUNCE_MS = 150;
23
+ const REQUEST_TIMEOUT_MS = 15_000;
12
24
  const STICKY_CHECKOUT_SCROLL_OFFSET_PX = 100;
25
+ const CHECKOUT_IDEMPOTENCY_PREFIX = "session-services:checkout:";
26
+ function createCheckoutIdempotencyKey() {
27
+ const bytes = globalThis.crypto.getRandomValues(new Uint8Array(16));
28
+ return `elements_${Array.from(bytes, (value) => value.toString(16).padStart(2, "0")).join("")}`;
29
+ }
30
+ async function checkoutStorageName(identity) {
31
+ if (!globalThis.crypto?.subtle)
32
+ return undefined;
33
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(identity));
34
+ return `${CHECKOUT_IDEMPOTENCY_PREFIX}${Array.from(new Uint8Array(digest), (value) => value.toString(16).padStart(2, "0")).join("")}`;
35
+ }
36
+ function storedCheckoutIdempotencyKey(name) {
37
+ if (!name || typeof window === "undefined")
38
+ return undefined;
39
+ try {
40
+ return window.sessionStorage?.getItem(name) || undefined;
41
+ }
42
+ catch {
43
+ return undefined;
44
+ }
45
+ }
46
+ function storeCheckoutIdempotencyKey(name, key) {
47
+ if (!name || typeof window === "undefined")
48
+ return;
49
+ try {
50
+ window.sessionStorage?.setItem(name, key);
51
+ }
52
+ catch {
53
+ // In-memory state still keeps retries idempotent when storage is blocked.
54
+ }
55
+ }
13
56
  function objectValue(value, key) {
14
57
  if (!value || typeof value !== "object")
15
58
  return undefined;
@@ -28,6 +71,29 @@ function isPasscodeAccessError(err) {
28
71
  return true;
29
72
  return errorCode(err) === "UNAUTHORIZED" && /passcode/i.test(message);
30
73
  }
74
+ function classifyLoadError(err) {
75
+ if (isPasscodeAccessError(err))
76
+ return "access";
77
+ if (errorCode(err) === "NOT_FOUND")
78
+ return "not_found";
79
+ return "transient";
80
+ }
81
+ async function withTimeout(controller, request) {
82
+ let timer;
83
+ const timeout = new Promise((_, reject) => {
84
+ timer = setTimeout(() => {
85
+ controller.abort();
86
+ reject(new Error("The request timed out"));
87
+ }, REQUEST_TIMEOUT_MS);
88
+ });
89
+ try {
90
+ return await Promise.race([request(controller.signal), timeout]);
91
+ }
92
+ finally {
93
+ if (timer)
94
+ clearTimeout(timer);
95
+ }
96
+ }
31
97
  function parseJson(value) {
32
98
  try {
33
99
  return JSON.parse(value);
@@ -36,8 +102,12 @@ function parseJson(value) {
36
102
  return null;
37
103
  }
38
104
  }
39
- function hasAnalyticsIds(event) {
40
- return Boolean(event.teamId && event.promoterId);
105
+ function analyticsSkipReason(event) {
106
+ if (!event.teamId)
107
+ return "missing_team_id";
108
+ if (!event.promoterId)
109
+ return "missing_promoter_id";
110
+ return null;
41
111
  }
42
112
  function eventVenueName(event) {
43
113
  return [event.location?.venue?.name, event.location?.name].find(Boolean);
@@ -81,7 +151,7 @@ function quoteProductContext({ event, admission, section, }) {
81
151
  }
82
152
  function quoteProductPrice(item) {
83
153
  return {
84
- price: priceTotal(item.price) / 100,
154
+ price: priceAmount(item.price),
85
155
  price_base: item.price?.base,
86
156
  price_booking_fee: item.price?.booking,
87
157
  };
@@ -110,8 +180,13 @@ export class SessionsTicketing {
110
180
  selectedItems = new Map();
111
181
  quote = null;
112
182
  previewQuote = null;
113
- loading = true;
183
+ initialLoading = true;
184
+ eventLoading = false;
185
+ retryLoading = false;
186
+ passcodeLoading = false;
114
187
  error = null;
188
+ errorKind = null;
189
+ refreshError = null;
115
190
  quoteLoading = false;
116
191
  previewLoading = false;
117
192
  quoteError = null;
@@ -123,44 +198,85 @@ export class SessionsTicketing {
123
198
  passcodeDenied = false;
124
199
  selectionPrompt = false;
125
200
  checkoutLoading = false;
201
+ checkoutError = null;
126
202
  currentTheme = "light";
127
203
  openModalAdmissionId = null;
204
+ verificationRequired = false;
128
205
  checkoutInit;
129
206
  cartUpdate;
130
207
  errorOccurred;
208
+ analyticsEventSkipped;
131
209
  client;
132
210
  analytics;
133
211
  mediaQueryList;
134
212
  requestId = 0;
135
213
  previewRequestId = 0;
214
+ eventRequestId = 0;
215
+ checkoutRequestId = 0;
216
+ couponRequestId = 0;
217
+ initializeId = 0;
218
+ initialSettled = false;
219
+ active = true;
220
+ trackedIdentity;
221
+ quoteRevision;
222
+ checkoutIdempotencyKeys = new Map();
223
+ eventController;
224
+ quoteController;
225
+ previewController;
226
+ checkoutController;
227
+ couponController;
136
228
  quoteTimer;
137
229
  promptTimer;
138
- async componentWillLoad() {
230
+ botBypassed = false;
231
+ modalTrigger;
232
+ modalFocusPending = false;
233
+ modalRestorePending = false;
234
+ connectedCallback() {
235
+ this.active = true;
139
236
  if (typeof window !== "undefined") {
140
237
  window.addEventListener("popstate", this.handleDiscountQueryChange);
141
238
  }
142
- await this.initializeComponent();
143
239
  }
144
- async propsChanged() {
145
- await this.initializeComponent();
240
+ componentWillLoad() {
241
+ this.startInitialization();
146
242
  }
147
- async couponCodeChanged() {
148
- await this.setInitialCoupon();
243
+ componentDidRender() {
244
+ if (this.modalFocusPending) {
245
+ const dialog = this.host.shadowRoot?.querySelector(".modal-content");
246
+ if (!dialog)
247
+ return;
248
+ this.modalFocusPending = false;
249
+ dialog.querySelector("button")?.focus();
250
+ return;
251
+ }
252
+ if (!this.modalRestorePending)
253
+ return;
254
+ this.modalRestorePending = false;
255
+ this.modalTrigger?.focus();
256
+ this.modalTrigger = undefined;
257
+ }
258
+ propsChanged() {
259
+ this.startInitialization();
260
+ }
261
+ couponCodeChanged() {
262
+ this.setInitialCoupon().catch((err) => {
263
+ this.setCouponError(errorMessage(err, "Failed to update coupon"));
264
+ });
149
265
  }
150
266
  themeChanged() {
151
267
  this.setupTheme();
152
268
  }
153
269
  disconnectedCallback() {
154
- if (typeof window !== "undefined") {
270
+ this.active = false;
271
+ this.initializeId++;
272
+ this.invalidateRequests();
273
+ if (typeof window !== "undefined" && window.removeEventListener) {
155
274
  window.removeEventListener("popstate", this.handleDiscountQueryChange);
156
275
  }
157
276
  if (this.mediaQueryList) {
158
277
  this.mediaQueryList.removeEventListener("change", this.handleSystemThemeChange);
159
278
  }
160
- // Clean up modal listener if component unmounts while modal is open
161
- if (this.openModalAdmissionId) {
162
- document.removeEventListener("keydown", this.handleModalKeyDown);
163
- }
279
+ document.removeEventListener("keydown", this.handleModalKeyDown);
164
280
  this.clearQuoteTimer();
165
281
  this.clearPromptTimer();
166
282
  }
@@ -169,56 +285,144 @@ export class SessionsTicketing {
169
285
  return;
170
286
  this.setInitialCoupon().catch(() => undefined);
171
287
  };
288
+ continueAfterVerification = async () => {
289
+ this.botBypassed = true;
290
+ this.verificationRequired = false;
291
+ const pending = this.initializeComponent();
292
+ const id = this.initializeId;
293
+ try {
294
+ await pending;
295
+ }
296
+ catch (err) {
297
+ if (id === this.initializeId)
298
+ this.handleInitializationError(err);
299
+ }
300
+ };
301
+ startInitialization() {
302
+ const pending = this.initializeComponent();
303
+ const id = this.initializeId;
304
+ pending.catch((err) => {
305
+ if (id === this.initializeId)
306
+ this.handleInitializationError(err);
307
+ });
308
+ }
309
+ handleInitializationError = (err) => {
310
+ const error = errorMessage(err, "Failed to load event data");
311
+ this.error = error;
312
+ this.errorKind = "transient";
313
+ this.finishInitialLoad(!this.initialSettled);
314
+ this.errorOccurred.emit({ error });
315
+ };
172
316
  async initializeComponent() {
317
+ const id = ++this.initializeId;
318
+ const initial = !this.initialSettled;
319
+ this.invalidateRequests();
173
320
  this.error = null;
321
+ this.errorKind = null;
322
+ this.refreshError = null;
174
323
  this.event = null;
175
324
  this.selectedItems = new Map();
176
325
  this.quote = null;
177
326
  this.previewQuote = null;
178
327
  this.quoteError = null;
328
+ this.checkoutError = null;
329
+ this.quoteLoading = false;
330
+ this.previewLoading = false;
331
+ this.checkoutLoading = false;
179
332
  this.couponError = null;
180
333
  this.couponInput = this.initialCouponCode();
181
334
  this.appliedCouponCode = this.couponInput;
182
335
  this.activePasscode = this.passcode || "";
183
336
  this.passcodeInput = this.activePasscode;
184
337
  this.passcodeDenied = false;
338
+ this.verificationRequired = false;
339
+ this.initialLoading = initial;
340
+ this.eventLoading = !initial;
341
+ this.retryLoading = false;
342
+ this.passcodeLoading = false;
185
343
  if (!this.tenantId || !this.eventId) {
186
344
  this.error = "Missing required configuration: tenantId and eventId";
187
- this.loading = false;
345
+ this.errorKind = "configuration";
346
+ this.finishInitialLoad(initial);
347
+ return;
348
+ }
349
+ this.setupTheme();
350
+ if (!this.botBypassed && isProductionApi(this.apiUrl) && detectBot().bot) {
351
+ this.verificationRequired = true;
352
+ this.finishInitialLoad(initial);
188
353
  return;
189
354
  }
190
355
  this.client = createClient({
191
356
  environment: this.apiUrl,
192
357
  tenantId: this.tenantId,
193
358
  });
194
- this.setupTheme();
195
- await this.loadEventData();
359
+ this.analytics = undefined;
360
+ const result = await this.loadEventData({
361
+ mode: initial ? "initial" : "refresh",
362
+ });
363
+ if (id !== this.initializeId || result.status !== "success")
364
+ return;
365
+ this.handleLoadedEvent(result.event);
366
+ await this.updatePreviewQuote();
367
+ }
368
+ handleLoadedEvent(event) {
369
+ const identity = `${this.apiUrl}::${this.tenantId}::${this.eventId}`;
370
+ this.setupAnalytics(event);
371
+ if (identity === this.trackedIdentity)
372
+ return;
373
+ this.trackedIdentity = identity;
374
+ this.trackLoadedEvent(event);
375
+ }
376
+ finishInitialLoad(initial) {
377
+ if (initial) {
378
+ this.initialSettled = true;
379
+ this.initialLoading = false;
380
+ }
381
+ this.eventLoading = false;
382
+ }
383
+ invalidateRequests() {
384
+ this.eventRequestId++;
385
+ this.requestId++;
386
+ this.previewRequestId++;
387
+ this.checkoutRequestId++;
388
+ this.couponRequestId++;
389
+ this.eventController?.abort();
390
+ this.quoteController?.abort();
391
+ this.previewController?.abort();
392
+ this.checkoutController?.abort();
393
+ this.couponController?.abort();
394
+ this.eventController = undefined;
395
+ this.quoteController = undefined;
396
+ this.previewController = undefined;
397
+ this.checkoutController = undefined;
398
+ this.couponController = undefined;
399
+ this.clearQuoteTimer();
400
+ this.quoteRevision = undefined;
401
+ this.quoteLoading = false;
402
+ this.previewLoading = false;
403
+ this.checkoutLoading = false;
196
404
  }
197
405
  async setInitialCoupon() {
198
406
  const coupon = this.initialCouponCode();
199
407
  this.couponInput = coupon;
200
- this.quote = null;
201
- this.previewQuote = this.activeInitialPreviewQuote(coupon);
202
408
  this.quoteError = null;
203
409
  this.couponError = null;
204
- if (!coupon) {
205
- this.appliedCouponCode = "";
206
- await this.updateQuote();
410
+ if (!this.event) {
411
+ this.appliedCouponCode = coupon;
412
+ this.previewQuote = this.activeInitialPreviewQuote(coupon);
207
413
  return;
208
414
  }
209
415
  if (this.selectedItems.size > 0) {
210
416
  await this.applyCartCoupon(coupon);
211
417
  return;
212
418
  }
213
- if (this.previewQuote)
214
- return;
215
419
  await this.applyPreviewCoupon(coupon);
216
420
  }
217
421
  initialCouponCode() {
218
422
  const prop = normalizeCouponCode(this.couponCode);
219
423
  if (prop)
220
424
  return prop;
221
- if (typeof window === "undefined")
425
+ if (typeof window === "undefined" || !window.location)
222
426
  return "";
223
427
  return normalizeCouponCode(discountCouponFromSearch(window.location.search));
224
428
  }
@@ -269,36 +473,62 @@ export class SessionsTicketing {
269
473
  }
270
474
  };
271
475
  trackEvent(eventType, properties = {}) {
272
- const context = this.analyticsContext();
476
+ const context = this.analyticsContext(eventType);
273
477
  if (!context)
274
478
  return;
275
479
  context.analytics.track(eventType, {
276
- event_id: this.eventId,
277
- team_id: context.event.teamId,
278
- promoter_id: context.event.promoterId,
279
- event_name: context.event.name,
280
- event_slug: context.event.slug,
281
- currency: context.event.currency,
480
+ ...this.analyticsProperties(context.event),
282
481
  ...properties,
283
482
  });
284
483
  }
285
- analyticsContext() {
286
- const analytics = this.activeAnalytics();
287
- const event = this.analyticsEvent();
288
- if (!analytics || !event)
289
- return undefined;
290
- return { analytics, event };
484
+ analyticsProperties(event, properties = {}) {
485
+ return {
486
+ event_id: this.eventId,
487
+ team_id: event.teamId,
488
+ promoter_id: event.promoterId,
489
+ event_name: event.name,
490
+ event_slug: event.slug,
491
+ currency: event.currency,
492
+ ...properties,
493
+ };
291
494
  }
292
- activeAnalytics() {
495
+ analyticsForEvent(eventType, event) {
293
496
  if (!this.enableAnalytics)
294
497
  return undefined;
498
+ const reason = analyticsSkipReason(event);
499
+ if (reason) {
500
+ this.emitAnalyticsEventSkipped(eventType, reason, event);
501
+ return undefined;
502
+ }
503
+ if (!this.analytics) {
504
+ this.emitAnalyticsEventSkipped(eventType, "analytics_not_initialized", event);
505
+ return undefined;
506
+ }
295
507
  return this.analytics;
296
508
  }
297
- analyticsEvent() {
509
+ analyticsContext(eventType) {
298
510
  const event = this.event;
299
- if (!event)
511
+ if (!event) {
512
+ this.emitAnalyticsEventSkipped(eventType, "missing_event");
300
513
  return undefined;
301
- return hasAnalyticsIds(event) ? event : undefined;
514
+ }
515
+ const analytics = this.analyticsForEvent(eventType, event);
516
+ if (!analytics)
517
+ return undefined;
518
+ return { analytics, event };
519
+ }
520
+ emitAnalyticsEventSkipped(eventType, reason, event, err) {
521
+ const detail = {
522
+ eventType,
523
+ eventId: this.eventId,
524
+ reason,
525
+ promoterId: event?.promoterId || undefined,
526
+ teamId: event?.teamId || undefined,
527
+ };
528
+ this.analyticsEventSkipped.emit(detail);
529
+ if (this.debugAnalytics) {
530
+ console.warn("[SessionServicesTicketing] Analytics event skipped:", detail, err);
531
+ }
302
532
  }
303
533
  getLowestPrice() {
304
534
  const event = this.event;
@@ -312,7 +542,7 @@ export class SessionsTicketing {
312
542
  sku: adm.id,
313
543
  name: adm.name,
314
544
  category: event.name,
315
- price: priceTotal(adm.price) / 100,
545
+ price: priceAmount(adm.price, event.currency),
316
546
  quantity: 1,
317
547
  position: index + 1,
318
548
  admission_id: adm.id,
@@ -323,41 +553,111 @@ export class SessionsTicketing {
323
553
  capacity: adm.capacity,
324
554
  }));
325
555
  }
326
- async loadEventData() {
556
+ async loadEventData(options = {}) {
557
+ const mode = options.mode ?? "refresh";
558
+ const client = this.client;
559
+ const eventId = this.eventId;
560
+ if (!client || !this.tenantId || !eventId) {
561
+ const error = "Missing required configuration: tenantId and eventId";
562
+ this.error = error;
563
+ this.errorKind = "configuration";
564
+ return { status: "error", error, kind: "configuration" };
565
+ }
566
+ const id = ++this.eventRequestId;
567
+ const controller = new AbortController();
568
+ this.eventController?.abort();
569
+ this.eventController = controller;
570
+ if (mode === "coupon")
571
+ this.couponController = controller;
572
+ if (mode === "initial")
573
+ this.initialLoading = true;
574
+ if (mode === "refresh")
575
+ this.eventLoading = true;
576
+ if (mode === "retry")
577
+ this.retryLoading = true;
578
+ if (mode === "passcode")
579
+ this.passcodeLoading = true;
327
580
  try {
328
- this.loading = true;
329
- this.error = null;
581
+ if (mode !== "coupon" && mode !== "passcode") {
582
+ this.error = null;
583
+ this.errorKind = null;
584
+ this.refreshError = null;
585
+ }
586
+ const response = await withTimeout(controller, (signal) => client.event.get({
587
+ key: eventId,
588
+ couponCode: (options.couponCode ?? this.appliedCouponCode) || undefined,
589
+ passcode: (options.passcode ?? this.activePasscode) || undefined,
590
+ }, { signal }));
591
+ if (!this.isEventRequestCurrent(id, eventId, controller)) {
592
+ return { status: "stale" };
593
+ }
594
+ if (options.commit !== false) {
595
+ this.event = response.event;
596
+ this.pruneSelectedItems(response.event);
597
+ }
330
598
  this.passcodeDenied = false;
331
- const response = await this.client.event.get({
332
- key: this.eventId,
333
- couponCode: this.appliedCouponCode || undefined,
334
- passcode: this.activePasscode || undefined,
335
- });
336
- this.event = response.event;
337
- this.pruneSelectedItems(response.event);
338
- this.trackLoadedEvent(response.event);
339
- await this.updatePreviewQuote();
599
+ return { status: "success", event: response.event };
340
600
  }
341
601
  catch (err) {
342
- this.passcodeDenied = isPasscodeAccessError(err);
343
- this.error = errorMessage(err, "Failed to load event data");
344
- this.errorOccurred.emit({ error: this.error });
602
+ if (!this.isEventRequestCurrent(id, eventId, controller)) {
603
+ return { status: "stale" };
604
+ }
605
+ const kind = classifyLoadError(err);
606
+ const error = errorMessage(err, "Failed to load event data");
607
+ this.passcodeDenied = kind === "access";
608
+ if (mode !== "coupon") {
609
+ if (this.event && (mode === "refresh" || mode === "retry")) {
610
+ this.refreshError = error;
611
+ }
612
+ else {
613
+ this.error = error;
614
+ this.errorKind = kind;
615
+ }
616
+ this.errorOccurred.emit({ error });
617
+ }
618
+ return { status: "error", error, kind };
345
619
  }
346
620
  finally {
347
- this.loading = false;
621
+ if (id === this.eventRequestId) {
622
+ if (mode === "initial")
623
+ this.finishInitialLoad(true);
624
+ if (mode === "refresh")
625
+ this.eventLoading = false;
626
+ if (mode === "retry")
627
+ this.retryLoading = false;
628
+ if (mode === "passcode")
629
+ this.passcodeLoading = false;
630
+ if (this.eventController === controller)
631
+ this.eventController = undefined;
632
+ if (this.couponController === controller)
633
+ this.couponController = undefined;
634
+ }
348
635
  }
349
636
  }
637
+ isEventRequestCurrent(id, eventId, controller) {
638
+ return (this.active &&
639
+ id === this.eventRequestId &&
640
+ eventId === this.eventId &&
641
+ this.eventController === controller);
642
+ }
350
643
  pruneSelectedItems(event) {
644
+ if (this.openModalAdmissionId &&
645
+ !event.admissions.some((admission) => admission.id === this.openModalAdmissionId)) {
646
+ this.closeModal();
647
+ }
351
648
  const keys = new Set(event.admissions.map((admission) => selectionKey(admission.id, admission.sectionId ?? null)));
352
649
  const selected = Array.from(this.selectedItems).filter(([key]) => keys.has(key));
353
650
  if (selected.length === this.selectedItems.size)
354
651
  return;
355
652
  this.selectedItems = new Map(selected);
356
- this.quote = null;
357
- this.quoteError = null;
653
+ this.invalidateQuote();
654
+ if (this.selectedItems.size > 0)
655
+ this.scheduleQuoteUpdate();
358
656
  }
359
657
  trackLoadedEvent(event) {
360
- this.setupAnalytics(event);
658
+ if (!this.setupAnalytics(event))
659
+ return;
660
+ this.trackPageViewed(event);
361
661
  this.trackProductViewed(event);
362
662
  this.trackEvent("Product List Viewed", {
363
663
  list_id: this.eventId,
@@ -366,19 +666,32 @@ export class SessionsTicketing {
366
666
  });
367
667
  }
368
668
  setupAnalytics(event) {
369
- if (!this.enableAnalytics || this.analytics || !event.promoterId)
669
+ if (!this.enableAnalytics)
670
+ return false;
671
+ const reason = analyticsSkipReason(event);
672
+ if (reason) {
673
+ this.emitAnalyticsEventSkipped("Page Viewed", reason, event);
674
+ return false;
675
+ }
676
+ if (this.analytics)
677
+ return true;
678
+ try {
679
+ this.analytics = createAnalytics({
680
+ client: this.client,
681
+ debug: this.debugAnalytics,
682
+ });
683
+ }
684
+ catch (err) {
685
+ this.emitAnalyticsEventSkipped("Page Viewed", "analytics_initialization_failed", event, err);
686
+ return false;
687
+ }
688
+ return true;
689
+ }
690
+ trackPageViewed(event) {
691
+ const analytics = this.analyticsForEvent("Page Viewed", event);
692
+ if (!analytics)
370
693
  return;
371
- this.analytics = createAnalytics({
372
- client: this.client,
373
- debug: this.debugAnalytics,
374
- });
375
- this.analytics.page("Ticketing Widget", {
376
- event_id: this.eventId,
377
- team_id: event.teamId,
378
- promoter_id: event.promoterId,
379
- event_name: event.name,
380
- event_slug: event.slug,
381
- });
694
+ analytics.page("Ticketing Widget", this.analyticsProperties(event));
382
695
  }
383
696
  trackProductViewed(event) {
384
697
  const lowestPrice = this.getLowestPrice();
@@ -387,8 +700,8 @@ export class SessionsTicketing {
387
700
  sku: this.eventId,
388
701
  name: event.name,
389
702
  category: "Event",
390
- value: lowestPrice / 100,
391
- price: lowestPrice / 100,
703
+ value: majorUnits(lowestPrice, event.currency),
704
+ price: majorUnits(lowestPrice, event.currency),
392
705
  event_date: event.entryStartsAt,
393
706
  venue_name: eventVenueName(event),
394
707
  venue_city: event.location?.city,
@@ -399,6 +712,8 @@ export class SessionsTicketing {
399
712
  await this.setQuantity(admissionId, sectionId, (this.selectedItems.get(key) || 0) + delta);
400
713
  }
401
714
  async setQuantity(admissionId, sectionId, quantity) {
715
+ if (this.checkoutLoading)
716
+ return;
402
717
  const key = selectionKey(admissionId, sectionId);
403
718
  const admission = this.event?.admissions.find((a) => a.id === admissionId);
404
719
  if (!admission)
@@ -409,6 +724,8 @@ export class SessionsTicketing {
409
724
  return;
410
725
  this.selectionPrompt = false;
411
726
  this.setSelectedQuantity(key, next);
727
+ this.invalidateQuote();
728
+ this.checkoutError = null;
412
729
  const section = sectionId
413
730
  ? this.event?.sections.find((s) => s.id === sectionId)
414
731
  : null;
@@ -454,7 +771,7 @@ export class SessionsTicketing {
454
771
  name: change.admission.name,
455
772
  category: this.event?.name,
456
773
  variant: change.section?.name,
457
- price: priceTotal(change.admission.price) / 100,
774
+ price: priceAmount(change.admission.price, this.event?.currency),
458
775
  quantity: Math.abs(change.delta),
459
776
  admission_id: change.admission.id,
460
777
  section_id: optionalId(change.sectionId),
@@ -464,19 +781,26 @@ export class SessionsTicketing {
464
781
  async updateQuote() {
465
782
  this.clearQuoteTimer();
466
783
  if (this.selectedItems.size === 0) {
784
+ this.invalidateQuote();
467
785
  this.quote = null;
468
786
  this.quoteError = null;
469
787
  this.quoteLoading = false;
470
788
  await this.updatePreviewQuote();
471
789
  return;
472
790
  }
473
- this.requestId++;
474
- const currentId = this.requestId;
791
+ const currentId = ++this.requestId;
792
+ const eventId = this.eventId;
793
+ const coupon = this.appliedCouponCode;
794
+ const items = this.getQuoteRequestItems();
795
+ const revision = this.quoteRevisionFor(eventId, coupon, items);
796
+ const controller = new AbortController();
797
+ this.quoteController?.abort();
798
+ this.quoteController = controller;
475
799
  try {
476
800
  this.quoteLoading = true;
477
801
  this.quoteError = null;
478
- const response = await this.fetchCartQuote(this.appliedCouponCode);
479
- this.applyQuote(response.quote, currentId);
802
+ const response = await this.fetchCartQuote(eventId, items, coupon, controller);
803
+ this.applyQuote(response.quote, currentId, revision);
480
804
  }
481
805
  catch (_err) {
482
806
  this.handleQuoteError(currentId);
@@ -484,6 +808,9 @@ export class SessionsTicketing {
484
808
  finally {
485
809
  if (currentId === this.requestId) {
486
810
  this.quoteLoading = false;
811
+ if (this.quoteController === controller) {
812
+ this.quoteController = undefined;
813
+ }
487
814
  }
488
815
  }
489
816
  }
@@ -505,6 +832,26 @@ export class SessionsTicketing {
505
832
  clearTimeout(this.quoteTimer);
506
833
  this.quoteTimer = undefined;
507
834
  }
835
+ invalidateQuote() {
836
+ this.requestId++;
837
+ this.couponRequestId++;
838
+ this.checkoutRequestId++;
839
+ this.quoteController?.abort();
840
+ this.previewController?.abort();
841
+ this.checkoutController?.abort();
842
+ this.couponController?.abort();
843
+ this.quoteController = undefined;
844
+ this.previewController = undefined;
845
+ this.checkoutController = undefined;
846
+ this.couponController = undefined;
847
+ this.quoteRevision = undefined;
848
+ this.quote = null;
849
+ this.quoteError = null;
850
+ this.quoteLoading = false;
851
+ this.previewLoading = false;
852
+ this.checkoutError = null;
853
+ this.checkoutLoading = false;
854
+ }
508
855
  clearPromptTimer() {
509
856
  if (!this.promptTimer)
510
857
  return;
@@ -529,22 +876,23 @@ export class SessionsTicketing {
529
876
  };
530
877
  });
531
878
  }
532
- fetchCartQuote(couponCode) {
533
- return this.client.order.quote({
534
- eventId: this.eventId,
535
- items: this.getQuoteRequestItems(),
879
+ fetchCartQuote(eventId, items, couponCode, controller) {
880
+ return withTimeout(controller, (signal) => this.client.order.quote({
881
+ eventId,
882
+ items,
536
883
  couponCode: couponCode || undefined,
537
- });
884
+ }, { signal }));
538
885
  }
539
- applyQuote(quote, requestId) {
886
+ applyQuote(quote, requestId, revision = this.currentQuoteRevision()) {
540
887
  if (requestId !== this.requestId)
541
888
  return;
542
889
  this.quote = quote;
890
+ this.quoteRevision = revision;
543
891
  this.quoteError = null;
544
892
  this.cartUpdate.emit(this.quote);
545
893
  this.trackEvent("Cart Viewed", {
546
894
  products: this.getCartProducts(),
547
- value: quoteTotal(this.quote) / 100,
895
+ value: quoteAmount(this.quote, this.event?.currency),
548
896
  currency: this.event?.currency,
549
897
  });
550
898
  }
@@ -552,13 +900,22 @@ export class SessionsTicketing {
552
900
  if (requestId !== this.requestId)
553
901
  return;
554
902
  this.quote = null;
903
+ this.quoteRevision = undefined;
555
904
  this.quoteError = "Failed to update cart. Please try again.";
556
905
  this.errorOccurred.emit({ error: this.quoteError });
557
906
  }
907
+ quoteRevisionFor(eventId, coupon, items) {
908
+ return JSON.stringify({ eventId, coupon, items });
909
+ }
910
+ currentQuoteRevision() {
911
+ return this.quoteRevisionFor(this.eventId, this.appliedCouponCode, this.getQuoteRequestItems());
912
+ }
558
913
  async updatePreviewQuote() {
559
914
  const event = this.event;
560
915
  if (!event || !this.appliedCouponCode) {
561
916
  this.previewRequestId++;
917
+ this.previewController?.abort();
918
+ this.previewController = undefined;
562
919
  this.previewLoading = false;
563
920
  this.previewQuote = null;
564
921
  return;
@@ -579,35 +936,41 @@ export class SessionsTicketing {
579
936
  }
580
937
  this.previewRequestId++;
581
938
  const currentId = this.previewRequestId;
939
+ const coupon = this.appliedCouponCode;
940
+ const eventId = this.eventId;
941
+ const controller = new AbortController();
942
+ this.previewController?.abort();
943
+ this.previewController = controller;
582
944
  try {
583
945
  this.previewLoading = true;
584
- const response = await this.fetchPreviewQuote(this.appliedCouponCode);
585
- if (currentId === this.previewRequestId) {
946
+ const response = await this.fetchPreviewQuote(event, coupon, controller);
947
+ if (currentId === this.previewRequestId &&
948
+ eventId === this.eventId &&
949
+ coupon === this.appliedCouponCode) {
586
950
  this.previewQuote = response.quote;
587
951
  }
588
952
  }
589
953
  catch (_err) {
590
954
  if (currentId === this.previewRequestId) {
591
955
  this.previewQuote = null;
592
- this.appliedCouponCode = "";
593
956
  this.setCouponError();
594
957
  }
595
958
  }
596
959
  finally {
597
960
  if (currentId === this.previewRequestId) {
598
961
  this.previewLoading = false;
962
+ if (this.previewController === controller) {
963
+ this.previewController = undefined;
964
+ }
599
965
  }
600
966
  }
601
967
  }
602
- fetchPreviewQuote(couponCode) {
603
- const event = this.event;
604
- if (!event)
605
- throw new Error("Missing event");
606
- return this.client.order.quote({
968
+ fetchPreviewQuote(event, couponCode, controller) {
969
+ return withTimeout(controller, (signal) => this.client.order.quote({
607
970
  eventId: event.id,
608
971
  items: previewQuoteItems(event),
609
972
  couponCode,
610
- });
973
+ }, { signal }));
611
974
  }
612
975
  handleCouponInput = (e) => {
613
976
  if (!(e.target instanceof HTMLInputElement))
@@ -639,136 +1002,136 @@ export class SessionsTicketing {
639
1002
  await this.removeCartCoupon();
640
1003
  return;
641
1004
  }
642
- this.couponInput = "";
643
- const coupon = this.appliedCouponCode;
644
- this.appliedCouponCode = "";
645
- await this.loadEventData();
646
- this.previewRequestId++;
647
- this.previewLoading = false;
648
- this.previewQuote = null;
649
- this.trackCouponRemoved(coupon, null);
1005
+ await this.applyPreviewCoupon("");
650
1006
  }
651
1007
  async applyCartCoupon(coupon) {
652
- this.requestId++;
653
- const currentId = this.requestId;
1008
+ const operationId = ++this.couponRequestId;
1009
+ const currentId = ++this.requestId;
654
1010
  const previousCoupon = this.appliedCouponCode;
1011
+ const items = this.getQuoteRequestItems();
1012
+ const eventId = this.eventId;
1013
+ const revision = this.quoteRevisionFor(eventId, coupon, items);
1014
+ const controller = new AbortController();
1015
+ this.quoteController?.abort();
1016
+ this.quoteController = controller;
655
1017
  try {
656
1018
  this.quoteLoading = true;
657
- this.appliedCouponCode = coupon;
658
- await this.loadEventData();
659
- if (currentId !== this.requestId)
660
- return;
661
- if (this.selectedItems.size === 0) {
662
- await this.applyPreviewCoupon(coupon);
1019
+ const loaded = await this.loadEventData({
1020
+ commit: false,
1021
+ couponCode: coupon,
1022
+ mode: "coupon",
1023
+ });
1024
+ if (!this.isCouponOperationCurrent(operationId, currentId))
663
1025
  return;
664
- }
665
- const response = await this.fetchCartQuote(coupon);
666
- if (currentId !== this.requestId)
1026
+ if (loaded.status !== "success")
1027
+ throw new Error("Coupon load failed");
1028
+ const response = await this.fetchCartQuote(eventId, items, coupon, controller);
1029
+ if (!this.isCouponOperationCurrent(operationId, currentId))
667
1030
  return;
1031
+ this.event = loaded.event;
668
1032
  this.appliedCouponCode = coupon;
1033
+ this.couponInput = coupon;
669
1034
  this.previewQuote = null;
670
- this.applyQuote(response.quote, currentId);
671
- this.trackCouponApplied(coupon, response.quote);
1035
+ this.pruneSelectedItems(loaded.event);
1036
+ if (revision !== this.currentQuoteRevision()) {
1037
+ this.invalidateQuote();
1038
+ this.scheduleQuoteUpdate();
1039
+ return;
1040
+ }
1041
+ this.applyQuote(response.quote, currentId, revision);
1042
+ if (coupon) {
1043
+ this.trackCouponApplied(coupon, response.quote);
1044
+ }
1045
+ else {
1046
+ this.trackCouponRemoved(previousCoupon, response.quote);
1047
+ }
672
1048
  }
673
1049
  catch (_err) {
674
- if (currentId === this.requestId) {
675
- this.appliedCouponCode = previousCoupon;
676
- }
677
- this.handleCouponError(currentId);
678
- this.trackCouponDenied(coupon);
1050
+ if (!this.isCouponOperationCurrent(operationId, currentId))
1051
+ return;
1052
+ this.couponInput = previousCoupon || coupon;
1053
+ this.setCouponError(coupon
1054
+ ? undefined
1055
+ : "Failed to remove coupon. Your current discount is still applied.");
1056
+ if (coupon)
1057
+ this.trackCouponDenied(coupon);
679
1058
  }
680
1059
  finally {
681
1060
  if (currentId === this.requestId) {
682
1061
  this.quoteLoading = false;
1062
+ if (this.quoteController === controller) {
1063
+ this.quoteController = undefined;
1064
+ }
683
1065
  }
684
1066
  }
685
1067
  }
686
1068
  async applyPreviewCoupon(coupon) {
687
1069
  const previousCoupon = this.appliedCouponCode;
688
- this.appliedCouponCode = coupon;
689
- try {
690
- await this.loadEventData();
691
- }
692
- catch (_err) {
693
- this.appliedCouponCode = previousCoupon;
694
- this.setCouponError();
695
- this.trackCouponDenied(coupon);
696
- return;
697
- }
698
- const event = this.event;
699
- if (!event)
700
- return;
701
- const initialQuote = this.activeInitialPreviewQuote(coupon);
702
- if (initialQuote) {
703
- this.appliedCouponCode = coupon;
704
- this.previewQuote = initialQuote;
705
- this.trackCouponApplied(coupon, initialQuote);
706
- return;
707
- }
708
- if (previewQuoteItems(event).length === 0) {
709
- this.appliedCouponCode = coupon;
710
- this.previewQuote = null;
711
- return;
712
- }
713
- this.previewRequestId++;
714
- const currentId = this.previewRequestId;
1070
+ const operationId = ++this.couponRequestId;
1071
+ const currentId = ++this.previewRequestId;
1072
+ const controller = new AbortController();
1073
+ this.previewController?.abort();
1074
+ this.previewController = controller;
715
1075
  try {
716
1076
  this.previewLoading = true;
717
- const response = await this.fetchPreviewQuote(coupon);
718
- if (currentId !== this.previewRequestId)
1077
+ const loaded = await this.loadEventData({
1078
+ commit: false,
1079
+ couponCode: coupon,
1080
+ mode: "coupon",
1081
+ });
1082
+ if (!this.isPreviewCouponOperationCurrent(operationId, currentId))
1083
+ return;
1084
+ if (loaded.status !== "success")
1085
+ throw new Error("Coupon load failed");
1086
+ const initialQuote = this.activeInitialPreviewQuote(coupon);
1087
+ const response = initialQuote || !coupon || previewQuoteItems(loaded.event).length === 0
1088
+ ? null
1089
+ : await this.fetchPreviewQuote(loaded.event, coupon, controller);
1090
+ if (!this.isPreviewCouponOperationCurrent(operationId, currentId))
719
1091
  return;
1092
+ this.event = loaded.event;
1093
+ this.pruneSelectedItems(loaded.event);
720
1094
  this.appliedCouponCode = coupon;
721
- this.previewQuote = response.quote;
722
- this.trackCouponApplied(coupon, response.quote);
1095
+ this.couponInput = coupon;
1096
+ this.previewQuote = initialQuote ?? response?.quote ?? null;
1097
+ if (coupon) {
1098
+ this.trackCouponApplied(coupon, this.previewQuote);
1099
+ }
1100
+ else {
1101
+ this.trackCouponRemoved(previousCoupon, null);
1102
+ }
723
1103
  }
724
1104
  catch (_err) {
725
- if (currentId === this.previewRequestId) {
726
- this.setCouponError();
1105
+ if (!this.isPreviewCouponOperationCurrent(operationId, currentId))
1106
+ return;
1107
+ this.couponInput = previousCoupon || coupon;
1108
+ this.setCouponError(coupon
1109
+ ? undefined
1110
+ : "Failed to remove coupon. Your current discount is still applied.");
1111
+ if (coupon)
727
1112
  this.trackCouponDenied(coupon);
728
- }
729
1113
  }
730
1114
  finally {
731
1115
  if (currentId === this.previewRequestId) {
732
1116
  this.previewLoading = false;
1117
+ if (this.previewController === controller) {
1118
+ this.previewController = undefined;
1119
+ }
733
1120
  }
734
1121
  }
735
1122
  }
736
1123
  async removeCartCoupon() {
737
- this.requestId++;
738
- const currentId = this.requestId;
739
- const coupon = this.appliedCouponCode;
740
- try {
741
- this.quoteLoading = true;
742
- this.appliedCouponCode = "";
743
- await this.loadEventData();
744
- if (this.selectedItems.size === 0) {
745
- this.couponInput = "";
746
- this.previewQuote = null;
747
- this.trackCouponRemoved(coupon, null);
748
- return;
749
- }
750
- const response = await this.fetchCartQuote("");
751
- if (currentId !== this.requestId)
752
- return;
753
- this.couponInput = "";
754
- this.appliedCouponCode = "";
755
- this.previewQuote = null;
756
- this.applyQuote(response.quote, currentId);
757
- this.trackCouponRemoved(coupon, response.quote);
758
- }
759
- catch (_err) {
760
- this.handleCouponError(currentId, "Failed to remove coupon. Please try again.");
761
- }
762
- finally {
763
- if (currentId === this.requestId) {
764
- this.quoteLoading = false;
765
- }
766
- }
1124
+ await this.applyCartCoupon("");
767
1125
  }
768
- handleCouponError(requestId, message) {
769
- if (requestId !== this.requestId)
770
- return;
771
- this.setCouponError(message);
1126
+ isCouponOperationCurrent(operationId, requestId) {
1127
+ return (this.active &&
1128
+ operationId === this.couponRequestId &&
1129
+ requestId === this.requestId);
1130
+ }
1131
+ isPreviewCouponOperationCurrent(operationId, requestId) {
1132
+ return (this.active &&
1133
+ operationId === this.couponRequestId &&
1134
+ requestId === this.previewRequestId);
772
1135
  }
773
1136
  setCouponError(message = "Failed to apply coupon. Please check the code.") {
774
1137
  this.couponError = message;
@@ -785,8 +1148,8 @@ export class SessionsTicketing {
785
1148
  this.trackEvent("Coupon Applied", {
786
1149
  coupon,
787
1150
  products: this.getProductsForQuote(quote),
788
- total: quote ? quoteTotal(quote) / 100 : 0,
789
- value: quote ? quoteTotal(quote) / 100 : 0,
1151
+ total: quote ? quoteAmount(quote, this.event?.currency) : 0,
1152
+ value: quote ? quoteAmount(quote, this.event?.currency) : 0,
790
1153
  });
791
1154
  }
792
1155
  trackCouponDenied(coupon) {
@@ -803,8 +1166,8 @@ export class SessionsTicketing {
803
1166
  this.trackEvent("Coupon Removed", {
804
1167
  coupon,
805
1168
  products: this.getProductsForQuote(quote),
806
- total: quote ? quoteTotal(quote) / 100 : 0,
807
- value: quote ? quoteTotal(quote) / 100 : 0,
1169
+ total: quote ? quoteAmount(quote, this.event?.currency) : 0,
1170
+ value: quote ? quoteAmount(quote, this.event?.currency) : 0,
808
1171
  });
809
1172
  }
810
1173
  handlePasscodeInput = (e) => {
@@ -814,33 +1177,93 @@ export class SessionsTicketing {
814
1177
  };
815
1178
  async submitPasscode(e) {
816
1179
  e.preventDefault();
817
- this.activePasscode = this.passcodeInput.trim();
818
- await this.loadEventData();
1180
+ const passcode = this.passcodeInput.trim();
1181
+ this.activePasscode = passcode;
1182
+ const result = await this.loadEventData({ mode: "passcode", passcode });
1183
+ if (result.status !== "success")
1184
+ return;
1185
+ this.error = null;
1186
+ this.errorKind = null;
1187
+ this.handleLoadedEvent(result.event);
1188
+ await this.updatePreviewQuote();
1189
+ }
1190
+ async retryEventLoad() {
1191
+ if (!this.tenantId || !this.eventId) {
1192
+ await this.initializeComponent();
1193
+ return;
1194
+ }
1195
+ const result = await this.loadEventData({ mode: "retry" });
1196
+ if (result.status !== "success")
1197
+ return;
1198
+ this.handleLoadedEvent(result.event);
1199
+ await this.updatePreviewQuote();
819
1200
  }
820
1201
  async initiateCheckout() {
821
1202
  if (this.isCheckoutDisabled())
822
1203
  return;
823
- if (!this.quote)
1204
+ const quote = this.quote;
1205
+ if (!quote)
824
1206
  return;
1207
+ const id = ++this.checkoutRequestId;
1208
+ const eventId = this.eventId;
1209
+ const coupon = this.appliedCouponCode;
1210
+ const revision = this.currentQuoteRevision();
1211
+ const controller = new AbortController();
1212
+ this.checkoutController?.abort();
1213
+ this.checkoutController = controller;
825
1214
  try {
826
1215
  this.checkoutLoading = true;
827
- this.quoteError = null;
828
- const result = await this.client.order.create({
829
- eventId: this.eventId,
830
- items: this.getCheckoutItems(this.quote),
831
- couponCode: this.appliedCouponCode || undefined,
1216
+ this.checkoutError = null;
1217
+ const idempotencyKey = await this.getCheckoutIdempotencyKey(revision);
1218
+ if (!this.isCheckoutRequestCurrent(id, eventId, coupon, revision))
1219
+ return;
1220
+ const result = await withTimeout(controller, (signal) => this.client.order.create({
1221
+ eventId,
1222
+ items: this.getCheckoutItems(quote),
1223
+ couponCode: coupon || undefined,
832
1224
  returnUrl: this.returnUrl,
833
1225
  channel: buildOrderChannel("elements"),
834
- });
835
- this.trackCheckoutStarted(this.quote, result.order.id);
836
- this.handleCheckoutOrder(result.order);
1226
+ idempotencyKey,
1227
+ }, { signal }));
1228
+ if (!this.isCheckoutRequestCurrent(id, eventId, coupon, revision))
1229
+ return;
1230
+ this.trackCheckoutStarted(quote, result.order.id);
1231
+ this.handleCheckoutOrder(result.order, id);
837
1232
  }
838
1233
  catch (_err) {
839
- this.handleCheckoutError();
1234
+ if (this.isCheckoutRequestCurrent(id, eventId, coupon, revision)) {
1235
+ this.handleCheckoutError();
1236
+ }
840
1237
  }
1238
+ finally {
1239
+ if (id === this.checkoutRequestId &&
1240
+ this.checkoutController === controller) {
1241
+ this.checkoutController = undefined;
1242
+ }
1243
+ }
1244
+ }
1245
+ async getCheckoutIdempotencyKey(revision) {
1246
+ const current = this.checkoutIdempotencyKeys.get(revision);
1247
+ if (current)
1248
+ return current;
1249
+ const name = await checkoutStorageName(`${this.apiUrl}\u0000${this.tenantId}\u0000${revision}`);
1250
+ const stored = storedCheckoutIdempotencyKey(name);
1251
+ const key = stored ?? createCheckoutIdempotencyKey();
1252
+ this.checkoutIdempotencyKeys.set(revision, key);
1253
+ if (!stored)
1254
+ storeCheckoutIdempotencyKey(name, key);
1255
+ return key;
1256
+ }
1257
+ isCheckoutRequestCurrent(id, eventId, coupon, revision) {
1258
+ return (this.active &&
1259
+ id === this.checkoutRequestId &&
1260
+ eventId === this.eventId &&
1261
+ coupon === this.appliedCouponCode &&
1262
+ revision === this.currentQuoteRevision() &&
1263
+ revision === this.quoteRevision);
841
1264
  }
842
1265
  trackCheckoutStarted(quote, orderId) {
843
- const total = quoteTotal(quote) / 100;
1266
+ const total = quoteAmount(quote, this.event?.currency);
844
1267
  this.trackEvent("Checkout Started", {
845
1268
  order_id: orderId,
846
1269
  value: total,
@@ -864,7 +1287,9 @@ export class SessionsTicketing {
864
1287
  sectionId: item.sectionId,
865
1288
  }));
866
1289
  }
867
- handleCheckoutOrder(order) {
1290
+ handleCheckoutOrder(order, requestId) {
1291
+ if (!this.active || requestId !== this.checkoutRequestId)
1292
+ return;
868
1293
  this.checkoutInit.emit({
869
1294
  orderId: order.id,
870
1295
  checkoutUrl: order.checkoutUrl,
@@ -876,8 +1301,9 @@ export class SessionsTicketing {
876
1301
  this.checkoutLoading = false;
877
1302
  }
878
1303
  handleCheckoutError() {
879
- this.quoteError = "Failed to initiate checkout. Please try again.";
880
- this.errorOccurred.emit({ error: this.quoteError });
1304
+ this.checkoutError =
1305
+ "We couldn’t open checkout. Your tickets are still selected, so you can try again.";
1306
+ this.errorOccurred.emit({ error: this.checkoutError });
881
1307
  this.checkoutLoading = false;
882
1308
  }
883
1309
  handleStickyCheckoutClick(state) {
@@ -892,7 +1318,9 @@ export class SessionsTicketing {
892
1318
  const target = this.host.shadowRoot?.querySelector(".tickets-wrapper") ??
893
1319
  this.host;
894
1320
  window.scrollTo({
895
- behavior: "smooth",
1321
+ behavior: window.matchMedia?.("(prefers-reduced-motion: reduce)").matches === true
1322
+ ? "auto"
1323
+ : "smooth",
896
1324
  top: Math.max(target.getBoundingClientRect().top +
897
1325
  window.scrollY -
898
1326
  STICKY_CHECKOUT_SCROLL_OFFSET_PX, 0),
@@ -939,31 +1367,55 @@ export class SessionsTicketing {
939
1367
  return this.event?.sections.find((section) => section.id === item.sectionId);
940
1368
  }
941
1369
  formatDateTimeRange(startDate, endDate) {
942
- return `${formatNaiveDateTime(startDate, "EEE, MMM d · h:mm a")} - ${formatNaiveDateTime(endDate, "h:mm a")}`;
1370
+ const zone = this.event ? eventTimeZone(this.event) : "UTC";
1371
+ try {
1372
+ const start = parseNaiveDateTime(startDate, zone);
1373
+ const end = parseNaiveDateTime(endDate, zone);
1374
+ const day = this.dateFormatter({
1375
+ day: "numeric",
1376
+ month: "short",
1377
+ timeZone: zone,
1378
+ weekday: "short",
1379
+ }).format(start);
1380
+ const time = this.dateFormatter({
1381
+ hour: "numeric",
1382
+ minute: "2-digit",
1383
+ timeZone: zone,
1384
+ });
1385
+ return `${day} · ${time.format(start)} – ${time.format(end)}`;
1386
+ }
1387
+ catch {
1388
+ return `${startDate} – ${endDate}`;
1389
+ }
1390
+ }
1391
+ dateFormatter(options) {
1392
+ try {
1393
+ return new Intl.DateTimeFormat(this.locale, options);
1394
+ }
1395
+ catch {
1396
+ return new Intl.DateTimeFormat("en-US", options);
1397
+ }
943
1398
  }
944
- formatPriceValue(priceInCents) {
1399
+ formatPriceValue(priceInMinorUnits) {
945
1400
  const currency = this.event?.currency;
946
1401
  if (!currency) {
947
1402
  return new Intl.NumberFormat(this.locale, {
948
1403
  style: "decimal",
949
1404
  minimumFractionDigits: 2,
950
1405
  maximumFractionDigits: 2,
951
- }).format(priceInCents / 100);
1406
+ }).format(majorUnits(priceInMinorUnits));
952
1407
  }
953
1408
  try {
954
- return formatPrice(priceInCents, currency);
955
- }
956
- catch (error) {
957
- console.error("formatPrice failed, using fallback", {
958
- error,
959
- currency,
960
- priceInCents,
961
- locale: this.locale,
962
- });
963
1409
  return new Intl.NumberFormat(this.locale, {
964
1410
  style: "currency",
965
1411
  currency,
966
- }).format(priceInCents / 100);
1412
+ }).format(majorUnits(priceInMinorUnits, currency));
1413
+ }
1414
+ catch {
1415
+ return new Intl.NumberFormat("en-US", {
1416
+ style: "currency",
1417
+ currency,
1418
+ }).format(majorUnits(priceInMinorUnits, currency));
967
1419
  }
968
1420
  }
969
1421
  handleQuantityDecrease = async (admissionId, sectionId) => {
@@ -979,16 +1431,47 @@ export class SessionsTicketing {
979
1431
  };
980
1432
  openModal = (admissionId, e) => {
981
1433
  e.stopPropagation();
1434
+ this.modalTrigger = e.currentTarget;
1435
+ this.modalFocusPending = true;
982
1436
  this.openModalAdmissionId = admissionId;
983
1437
  document.addEventListener("keydown", this.handleModalKeyDown);
984
1438
  };
985
1439
  closeModal = () => {
986
1440
  this.openModalAdmissionId = null;
987
- document.removeEventListener("keydown", this.handleModalKeyDown);
1441
+ this.modalFocusPending = false;
1442
+ this.modalRestorePending = true;
1443
+ if (typeof document !== "undefined") {
1444
+ document.removeEventListener("keydown", this.handleModalKeyDown);
1445
+ }
988
1446
  };
989
1447
  handleModalKeyDown = (e) => {
990
1448
  if (e.key === "Escape") {
1449
+ e.preventDefault();
991
1450
  this.closeModal();
1451
+ return;
1452
+ }
1453
+ if (e.key !== "Tab")
1454
+ return;
1455
+ const dialog = this.host.shadowRoot?.querySelector(".modal-content");
1456
+ if (!dialog)
1457
+ return;
1458
+ const focusable = Array.from(dialog.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), [tabindex]:not([tabindex="-1"])'));
1459
+ if (focusable.length === 0) {
1460
+ e.preventDefault();
1461
+ dialog.focus();
1462
+ return;
1463
+ }
1464
+ const first = focusable[0];
1465
+ const last = focusable.at(-1);
1466
+ const active = this.host.shadowRoot?.activeElement;
1467
+ if (e.shiftKey && active === first) {
1468
+ e.preventDefault();
1469
+ last?.focus();
1470
+ return;
1471
+ }
1472
+ if (!e.shiftKey && active === last) {
1473
+ e.preventDefault();
1474
+ first?.focus();
992
1475
  }
993
1476
  };
994
1477
  handleBackdropClick = (e) => {
@@ -1008,6 +1491,7 @@ export class SessionsTicketing {
1008
1491
  return getAdmissionDisplayState({
1009
1492
  admission,
1010
1493
  event: this.event,
1494
+ locale: this.locale,
1011
1495
  section: this.getSection(sectionId),
1012
1496
  }).maxQuantity;
1013
1497
  }
@@ -1066,17 +1550,18 @@ export class SessionsTicketing {
1066
1550
  }
1067
1551
  if (mode === "door")
1068
1552
  return null;
1069
- return this.renderQuantityControls(admission, sectionId, state.disabled, state.maxQuantity);
1553
+ return this.renderQuantityControls(admission, sectionId, state.disabled || this.checkoutLoading, state.maxQuantity);
1070
1554
  }
1071
1555
  renderAdmission(admission, event, section, isSectionSoldOut = false, mode = "default") {
1072
1556
  const state = getAdmissionDisplayState({
1073
1557
  admission,
1074
1558
  event,
1559
+ locale: this.locale,
1075
1560
  section,
1076
1561
  sectionSoldOut: isSectionSoldOut,
1077
1562
  });
1078
1563
  const sectionId = section?.id || null;
1079
- return (h("section", { class: this.getAdmissionClassName(state, section), key: selectionKey(admission.id, sectionId), tabindex: state.disabled ? -1 : 0, "aria-label": this.getAdmissionAriaLabel(admission, section, state), "data-testid": "event-admission-card", "data-admission-id": admission.id, "data-admission-name": admission.name, "data-section-id": section?.id ?? "" }, h("div", { class: "admission-content" }, h("div", { class: "admission-details" }, this.renderAdmissionHeader(admission), this.renderAdmissionBody(admission, event, sectionId, state, mode)))));
1564
+ return (h("section", { class: this.getAdmissionClassName(state, section), key: selectionKey(admission.id, sectionId), "aria-label": this.getAdmissionAriaLabel(admission, section, state), "data-testid": "event-admission-card", "data-admission-id": admission.id, "data-admission-name": admission.name, "data-section-id": section?.id ?? "" }, h("div", { class: "admission-content" }, h("div", { class: "admission-details" }, this.renderAdmissionHeader(admission), this.renderAdmissionBody(admission, event, sectionId, state, mode)))));
1080
1565
  }
1081
1566
  getAdmissionClassName(state, section) {
1082
1567
  return `admission-card ${state.soldOut ? "sold-out" : ""} ${state.disabled && !state.soldOut ? "unavailable" : ""} ${section ? "" : "solo-admission"}`;
@@ -1118,34 +1603,49 @@ export class SessionsTicketing {
1118
1603
  return (h("div", { class: `ticket-section ${soldOut ? "section-sold-out" : ""}`, key: section.id }, this.renderSectionHeader(section, admissions), h("div", { class: "admissions-list" }, admissions.map((admission) => this.renderAdmission(admission, event, section, soldOut, mode)))));
1119
1604
  }
1120
1605
  renderLoadingState() {
1121
- return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("div", { class: "tickets-wrapper" }, h("h2", { class: "tickets-heading" }, "Get Tickets"), h("div", { class: "ticket-section loading-ticket-section" }, h("div", { class: "admissions-list" }, [0, 1, 2].map((item) => (h("div", { "aria-hidden": "true", class: "admission-card loading-admission", key: item })))))))));
1606
+ return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container", role: "status", "aria-live": "polite", "aria-label": "Loading ticket options" }, h("span", { class: "sr-only" }, "Loading ticket options"), h("div", { class: "tickets-wrapper" }, h("h2", { class: "tickets-heading" }, "Get Tickets"), h("div", { class: "ticket-section loading-ticket-section" }, h("div", { class: "admissions-list" }, [0, 1, 2].map((item) => (h("div", { "aria-hidden": "true", class: "admission-card loading-admission", key: item })))))))));
1122
1607
  }
1123
1608
  renderErrorState() {
1124
- if (this.passcodeDenied)
1609
+ if (this.errorKind === "access")
1125
1610
  return this.renderPasscodeState();
1126
- return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("div", { class: "message-state" }, h("strong", null, "Tickets Couldn\u2019t Load"), h("span", null, "We couldn\u2019t load ticket details. Try again in a moment."), h("button", { type: "button", class: "retry-button", onClick: () => this.loadEventData() }, "Try Again")))));
1611
+ if (this.errorKind === "not_found")
1612
+ return this.renderNotFoundState();
1613
+ const configuration = this.errorKind === "configuration";
1614
+ return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("div", { class: "message-state", role: "alert", "aria-live": "assertive" }, h("strong", null, configuration
1615
+ ? "Ticket widget needs setup"
1616
+ : "Tickets didn’t load"), h("span", null, configuration
1617
+ ? "This ticket widget is missing its event or tenant details."
1618
+ : "Something got in the way. Try again to load the ticket options."), !configuration && (h("button", { type: "button", class: "checkout-btn", onClick: () => this.retryEventLoad(), disabled: this.retryLoading }, this.retryLoading ? "Loading tickets…" : "Try again"))))));
1619
+ }
1620
+ renderUpdatingState() {
1621
+ return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container", role: "status", "aria-live": "polite" }, h("div", { class: "message-state" }, h("strong", null, "Loading ticket options\u2026"), h("span", null, "This should only take a moment.")))));
1622
+ }
1623
+ renderVerificationState() {
1624
+ return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("section", { class: "message-state", "aria-labelledby": "ticket-verification-title", "aria-describedby": "ticket-verification-description" }, h("h2", { id: "ticket-verification-title" }, "Let\u2019s get your tickets"), h("p", { id: "ticket-verification-description" }, "We just need you to confirm before we load the ticket options."), h("button", { type: "button", class: "checkout-btn", onClick: this.continueAfterVerification }, "Load tickets")))));
1127
1625
  }
1128
1626
  renderPasscodeState() {
1129
- return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("form", { class: "passcode-form", onSubmit: (e) => this.submitPasscode(e) }, h("h2", null, "Enter passcode"), h("p", null, "Enter the event passcode to view tickets and event details."), h("input", { type: "text", name: "passcode", value: this.passcodeInput, onInput: this.handlePasscodeInput, autocomplete: "one-time-code", placeholder: "Passcode", "aria-label": "Passcode" }), this.passcodeDenied && this.activePasscode && (h("span", { class: "error-message" }, "Incorrect passcode")), h("button", { type: "submit", class: "checkout-btn", disabled: !this.passcodeInput.trim() }, "Unlock event")))));
1627
+ return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("form", { class: "passcode-form", onSubmit: (e) => this.submitPasscode(e) }, h("h2", null, "Enter passcode"), h("p", null, "Enter the event passcode to view tickets and event details."), h("input", { type: "text", name: "passcode", value: this.passcodeInput, onInput: this.handlePasscodeInput, autocomplete: "one-time-code", placeholder: "Passcode", "aria-label": "Passcode", "aria-invalid": this.passcodeDenied, "aria-describedby": this.passcodeDenied ? "ticket-passcode-error" : undefined, disabled: this.passcodeLoading }), this.passcodeDenied && this.activePasscode && (h("span", { id: "ticket-passcode-error", class: "error-message", role: "alert", "aria-live": "assertive" }, "That passcode didn\u2019t work. Check it and try again.")), h("button", { type: "submit", class: "checkout-btn", disabled: !this.passcodeInput.trim() || this.passcodeLoading }, this.passcodeLoading ? "Unlocking…" : "Unlock event")))));
1130
1628
  }
1131
1629
  renderNotFoundState() {
1132
- return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("div", { class: "message-state" }, h("strong", null, "Event not found"), h("span", null, "We couldn\u2019t find this event. The link may be incorrect or expired.")))));
1630
+ return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("div", { class: "message-state", role: "alert" }, h("strong", null, "Event not found"), h("span", null, "We couldn\u2019t find this event. The link may be incorrect or expired.")))));
1133
1631
  }
1134
1632
  renderCouponPanel() {
1135
1633
  const hasInput = this.couponInput.trim().length > 0;
1136
1634
  const busy = this.quoteLoading || this.previewLoading || this.checkoutLoading;
1137
1635
  const canApply = hasInput && !busy;
1138
- return (h("div", { class: "coupon-panel" }, h("div", { class: "coupon-row" }, h("input", { id: "coupon-code", name: "coupon-code", placeholder: "Coupon Code", value: this.couponInput, onInput: this.handleCouponInput, onKeyDown: this.handleCouponKeyDown, autocomplete: "off", disabled: busy, "aria-label": "Coupon code", "aria-invalid": Boolean(this.couponError) }), this.appliedCouponCode ? (h("button", { type: "button", class: "coupon-remove", onClick: () => this.removeCoupon(), disabled: busy, "aria-label": "Remove coupon" }, "Remove")) : (h("button", { type: "button", class: "coupon-apply", onClick: () => this.applyCoupon(), disabled: !canApply }, "Apply"))), this.couponError && (h("span", { class: "error-message" }, this.couponError))));
1636
+ return (h("div", { class: "coupon-panel" }, h("div", { class: "coupon-row" }, h("input", { id: "coupon-code", name: "coupon-code", placeholder: "Coupon Code", value: this.appliedCouponCode || this.couponInput, onInput: this.handleCouponInput, onKeyDown: this.handleCouponKeyDown, autocomplete: "off", disabled: busy || Boolean(this.appliedCouponCode), "aria-label": "Coupon code", "aria-invalid": Boolean(this.couponError), "aria-describedby": this.couponError ? "coupon-error" : undefined }), this.appliedCouponCode ? (h("button", { type: "button", class: "coupon-remove", onClick: () => this.removeCoupon(), disabled: busy, "aria-label": "Remove coupon" }, "Remove")) : (h("button", { type: "button", class: "inline-retry-btn", onClick: () => this.applyCoupon(), disabled: !canApply }, "Apply"))), this.couponError && (h("span", { id: "coupon-error", class: "error-message", role: "alert", "aria-live": "assertive" }, this.couponError))));
1139
1637
  }
1140
1638
  isCheckoutDisabled() {
1141
1639
  return (this.quoteLoading ||
1142
1640
  this.checkoutLoading ||
1143
- Boolean(this.quoteError) ||
1144
- !hasQuoteItems(this.quote));
1641
+ !hasQuoteItems(this.quote) ||
1642
+ this.quoteRevision !== this.currentQuoteRevision());
1145
1643
  }
1146
1644
  getCheckoutButtonText() {
1147
1645
  if (this.checkoutLoading)
1148
1646
  return "Processing...";
1647
+ if (this.checkoutError)
1648
+ return "Try checkout again";
1149
1649
  if (this.quote)
1150
1650
  return this.getQuoteCheckoutText();
1151
1651
  return "Pay";
@@ -1202,22 +1702,26 @@ export class SessionsTicketing {
1202
1702
  return this.formatPriceValue(total);
1203
1703
  }
1204
1704
  renderCheckoutActions() {
1205
- return (h("div", { class: "checkout-actions" }, this.renderCouponPanel(), this.quoteError && h("div", { class: "error-message" }, this.quoteError), h("button", { type: "button", class: "checkout-btn", onClick: () => this.initiateCheckout(), disabled: this.isCheckoutDisabled(), "aria-label": this.quoteLoading ? "Updating" : undefined, "data-testid": "event-checkout-cta-desktop" }, this.renderCheckoutButtonContent())));
1705
+ return (h("div", { class: "checkout-actions" }, this.renderCouponPanel(), this.quoteError && (h("div", { class: "error-message", role: "alert", "aria-live": "assertive" }, this.quoteError, h("button", { type: "button", class: "coupon-apply", onClick: () => this.updateQuote(), disabled: this.quoteLoading }, "Try again"))), this.checkoutError && (h("div", { class: "error-message", role: "alert", "aria-live": "assertive" }, this.checkoutError)), h("button", { type: "button", class: "checkout-btn", onClick: () => this.initiateCheckout(), disabled: this.isCheckoutDisabled(), "aria-label": this.quoteLoading ? "Updating" : undefined, "data-testid": "event-checkout-cta-desktop" }, this.renderCheckoutButtonContent())));
1206
1706
  }
1207
1707
  renderStickyCheckout(state) {
1208
1708
  if (!this.stickyCheckout)
1209
1709
  return null;
1210
1710
  if (!state.showTicketing)
1211
1711
  return null;
1712
+ if (state.isDoorOnly) {
1713
+ return (h("div", { class: "sticky-checkout-bar" }, h("div", { class: "sticky-door-info" }, h("strong", null, "Tickets available at the door"), h("span", null, "Buy yours at the venue when you arrive."))));
1714
+ }
1212
1715
  return (h("div", { class: "sticky-checkout-bar" }, h("button", { type: "button", class: `checkout-btn sticky-checkout-btn ${this.selectionPrompt ? "selection-prompt" : ""}`, onClick: () => this.handleStickyCheckoutClick(state), disabled: this.isStickyCheckoutDisabled(state), "aria-label": this.quoteLoading ? "Updating" : undefined }, this.renderStickyCheckoutButtonContent(state))));
1213
1716
  }
1214
1717
  renderStickyExternalTicketing(state) {
1215
1718
  if (!this.stickyCheckout)
1216
1719
  return null;
1217
- if (!state.externalTicketUrl)
1720
+ const url = state.externalTicketUrl;
1721
+ if (!url)
1218
1722
  return null;
1219
- const domain = urlDomain(state.externalTicketUrl);
1220
- return (h("div", { class: "sticky-checkout-bar" }, h("a", { class: "external-ticket-button sticky-checkout-btn", href: state.externalTicketUrl, target: "_blank", rel: "noreferrer", onClick: () => this.trackExternalTicketClick(state.externalTicketUrl, "sticky") }, h("span", { class: "external-ticket-label" }, "Get tickets"), h("span", { class: "external-ticket-domain" }, "via ", domain))));
1723
+ const domain = urlDomain(url);
1724
+ return (h("div", { class: "sticky-checkout-bar" }, h("a", { class: "external-ticket-button sticky-checkout-btn", href: url, target: "_blank", rel: "noreferrer", onClick: () => this.trackExternalTicketClick(url, "sticky") }, h("span", { class: "external-ticket-label" }, "Get tickets"), h("span", { class: "external-ticket-domain" }, "via ", domain))));
1221
1725
  }
1222
1726
  renderModal() {
1223
1727
  if (!this.openModalAdmissionId)
@@ -1227,7 +1731,7 @@ export class SessionsTicketing {
1227
1731
  return null;
1228
1732
  return (
1229
1733
  // biome-ignore lint/a11y/noStaticElementInteractions lint/a11y/useKeyWithClickEvents: backdrop click-to-close is a common modal pattern, keyboard handled via Escape key
1230
- h("div", { class: "modal-backdrop", onClick: this.handleBackdropClick }, h("div", { class: "modal-content", role: "dialog", "aria-modal": "true", "aria-labelledby": "modal-title" }, h("button", { type: "button", class: "modal-close-btn", onClick: () => this.closeModal(), "aria-label": "Close" }, CloseIcon()), h("div", { class: "modal-header" }, h("h2", { id: "modal-title", class: "modal-title" }, admission.name), admission.subtitle && (h("p", { class: "modal-subtitle" }, admission.subtitle))), h("p", { class: "modal-description" }, admission.description))));
1734
+ h("div", { class: "modal-backdrop", onClick: this.handleBackdropClick }, h("div", { class: "modal-content", role: "dialog", "aria-modal": "true", "aria-labelledby": "modal-title", "aria-describedby": "modal-description", tabindex: "-1" }, h("button", { type: "button", class: "modal-close-btn", onClick: () => this.closeModal(), "aria-label": "Close" }, CloseIcon()), h("div", { class: "modal-header" }, h("h2", { id: "modal-title", class: "modal-title" }, admission.name), admission.subtitle && (h("p", { class: "modal-subtitle" }, admission.subtitle))), h("p", { id: "modal-description", class: "modal-description" }, admission.description))));
1231
1735
  }
1232
1736
  renderTicketSections(event) {
1233
1737
  const state = getTicketingState(event);
@@ -1254,16 +1758,28 @@ export class SessionsTicketing {
1254
1758
  return (h("div", { class: "door-alert" }, h("strong", null, "Tickets are available at ", location), h("span", null, "Online sales are closed. Tickets are available at the venue when you arrive.")));
1255
1759
  }
1256
1760
  loadingView() {
1257
- return this.loading ? this.renderLoadingState() : undefined;
1761
+ return this.initialLoading ? this.renderLoadingState() : undefined;
1258
1762
  }
1259
1763
  errorView() {
1260
1764
  return this.error && !this.event ? this.renderErrorState() : undefined;
1261
1765
  }
1766
+ verificationView() {
1767
+ return this.verificationRequired
1768
+ ? this.renderVerificationState()
1769
+ : undefined;
1770
+ }
1262
1771
  missingEventView() {
1263
- return this.event ? undefined : this.renderNotFoundState();
1772
+ if (this.event)
1773
+ return undefined;
1774
+ if (this.eventLoading || this.retryLoading)
1775
+ return this.renderUpdatingState();
1776
+ return this.renderNotFoundState();
1264
1777
  }
1265
1778
  pendingView() {
1266
- return this.loadingView() ?? this.errorView() ?? this.missingEventView();
1779
+ return (this.loadingView() ??
1780
+ this.verificationView() ??
1781
+ this.errorView() ??
1782
+ this.missingEventView());
1267
1783
  }
1268
1784
  renderReadyState() {
1269
1785
  const event = this.event;
@@ -1271,19 +1787,22 @@ export class SessionsTicketing {
1271
1787
  return this.renderNotFoundState();
1272
1788
  const state = getTicketingState(event);
1273
1789
  if (state.showExternalTicketing) {
1274
- return (h(Host, { "data-theme": this.currentTheme, "data-sticky-checkout": this.stickyCheckout ? "true" : undefined }, h("div", { class: "session-services-ticketing-container" }, this.renderExternalTicketing(state)), this.renderStickyExternalTicketing(state)));
1790
+ return (h(Host, { "data-theme": this.currentTheme, "data-sticky-checkout": this.stickyCheckout ? "true" : undefined }, h("div", { class: "session-services-ticketing-container", "aria-busy": this.eventLoading ? "true" : "false" }, this.renderExternalTicketing(state)), this.renderStickyExternalTicketing(state)));
1275
1791
  }
1276
- return (h(Host, { "data-theme": this.currentTheme, "data-sticky-checkout": this.stickyCheckout ? "true" : undefined }, h("div", { class: "session-services-ticketing-container" }, state.showTicketing
1792
+ return (h(Host, { "data-theme": this.currentTheme, "data-sticky-checkout": this.stickyCheckout ? "true" : undefined }, h("div", { class: "session-services-ticketing-container", "aria-busy": this.eventLoading || this.retryLoading || this.passcodeLoading
1793
+ ? "true"
1794
+ : "false", "aria-hidden": this.openModalAdmissionId ? "true" : undefined, inert: this.openModalAdmissionId ? true : undefined }, this.eventLoading && (h("div", { class: "inline-status", role: "status", "aria-live": "polite" }, "Updating ticket options\u2026")), this.refreshError && (h("div", { class: "error-message", role: "alert", "aria-live": "assertive" }, h("span", null, "We couldn\u2019t refresh the latest ticket details."), h("button", { type: "button", class: "inline-retry-btn", onClick: () => this.retryEventLoad(), disabled: this.retryLoading }, this.retryLoading ? "Refreshing…" : "Try again"))), state.showTicketing
1277
1795
  ? this.renderTicketSections(event)
1278
1796
  : this.renderUnavailableState(state), !state.isDoorOnly &&
1279
1797
  state.showTicketing &&
1280
1798
  this.renderCheckoutActions()), this.renderStickyCheckout(state), this.renderModal()));
1281
1799
  }
1282
1800
  renderExternalTicketing(state) {
1283
- const domain = urlDomain(state.externalTicketUrl);
1284
- if (!state.externalTicketUrl)
1801
+ const url = state.externalTicketUrl;
1802
+ if (!url)
1285
1803
  return null;
1286
- return (h("div", { class: "tickets-wrapper" }, h("h2", { class: "tickets-heading" }, state.ticketHeading), h("div", { class: "external-ticket-panel" }, h("p", { class: "external-ticket-warning" }, "This event sells through an external ticketing site. Checkout, tickets, and support are handled there."), h("a", { class: "external-ticket-button inline-external-ticket-button", href: state.externalTicketUrl, target: "_blank", rel: "noreferrer", onClick: () => this.trackExternalTicketClick(state.externalTicketUrl, "inline") }, h("span", { class: "external-ticket-label" }, "Get tickets"), h("span", { class: "external-ticket-domain" }, "via ", domain)))));
1804
+ const domain = urlDomain(url);
1805
+ return (h("div", { class: "tickets-wrapper" }, h("h2", { class: "tickets-heading" }, state.ticketHeading), h("div", { class: "external-ticket-panel" }, h("p", { class: "external-ticket-warning" }, "This event sells through an external ticketing site. Checkout, tickets, and support are handled there."), h("a", { class: "external-ticket-button inline-external-ticket-button", href: url, target: "_blank", rel: "noreferrer", onClick: () => this.trackExternalTicketClick(url, "inline") }, h("span", { class: "external-ticket-label" }, "Get tickets"), h("span", { class: "external-ticket-domain" }, "via ", domain)))));
1287
1806
  }
1288
1807
  renderUnavailableState(state) {
1289
1808
  return (h("div", { class: "empty-ticketing-state" }, h("strong", null, "Tickets Unavailable"), h("span", null, state.isEnded
@@ -1428,7 +1947,7 @@ export class SessionsTicketing {
1428
1947
  "mutable": false,
1429
1948
  "complexType": {
1430
1949
  "original": "| Record<string, { discount: number; gross: number; total: number }>\n | string",
1431
- "resolved": "string | { [x: string]: { discount: number; gross: number; total: number; }; }",
1950
+ "resolved": "string | { discount: number; gross: number; total: number; }",
1432
1951
  "references": {
1433
1952
  "Record": {
1434
1953
  "location": "global",
@@ -1452,12 +1971,13 @@ export class SessionsTicketing {
1452
1971
  "mutable": false,
1453
1972
  "complexType": {
1454
1973
  "original": "OrderQuote | string",
1455
- "resolved": "string | { items: { id: string; kind: \"ADMISSION\" | \"ADDON\"; quantity: number; price: { net: number; total: number; gross: number; base: number; booking: number; refunded: number; discount: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; admissionId?: string; sectionId?: string; admission?: { name: string; capacity: number; limit: number; order: number; entryStartsAt: string; entryEndsAt: string; saleStartsAt: string; saleEndsAt: string; saleEndsBehavior: \"SALE_ENDED\" | \"SOLD_OUT\" | \"DOOR\"; price: { base: number; booking: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; visibility: \"ALWAYS\" | \"HIDDEN\"; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; subtitle?: string; description?: string; available?: number; sold?: number; reserved?: number; createdAt?: string; updatedAt?: string; sectionId?: string; }; section?: { name: string; capacity: number; limit: number; order: number; visibility: \"ALWAYS\" | \"HIDDEN\" | \"STACKED\"; location: { createdAt: string; updatedAt: string; name: string; address: string; country: string; latitude: number; longitude: number; timeZone: string; id?: string; googlePlaceId?: string; city?: string; state?: string; postcode?: string; types?: string[]; description?: string; image?: { src: string; alt: string; width: number; height: number; }; venueId?: string; }; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; createdAt?: string; updatedAt?: string; available?: number; sold?: number; reserved?: number; }; }[]; price: { net: number; total: number; gross: number; base: number; booking: number; shipping: number; sms: number; refunded: number; discount: number; gateway: number; dispute: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; couponCode?: { name: string; active: boolean; couponId: string; teamId: string; id?: string; createdAt?: string; updatedAt?: string; uses?: number; }; }",
1974
+ "resolved": "string | { items: { id: string; kind: \"ADMISSION\" | \"ADDON\"; quantity: number; price: { net: number; total: number; gross: number; base: number; booking: number; refunded: number; discount: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; admissionId?: string; sectionId?: string; admission?: { name: string; capacity: number; limit: number; order: number; entryStartsAt: string; entryEndsAt: string; saleStartsAt: string; saleEndsAt: string; saleEndsBehavior: \"SALE_ENDED\" | \"SOLD_OUT\" | \"DOOR\"; price: { base: number; booking: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; override?: { booking: number; }; }; visibility: \"ALWAYS\" | \"HIDDEN\" | \"AFTER_ADMISSION\"; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; subtitle?: string; description?: string; available?: number; sold?: number; reserved?: number; createdAt?: string; updatedAt?: string; visibleAfterAdmissionId?: string; sectionId?: string; }; section?: { name: string; capacity: number; limit: number; order: number; visibility: \"ALWAYS\" | \"HIDDEN\" | \"STACKED\"; location: { createdAt: string; updatedAt: string; name: string; address: string; country: string; latitude: number; longitude: number; timeZone: string; id?: string; googlePlaceId?: string; city?: string; state?: string; postcode?: string; types?: string[]; description?: string; image?: { src: string; alt: string; width: number; height: number; }; venueId?: string; }; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; createdAt?: string; updatedAt?: string; available?: number; sold?: number; reserved?: number; }; }[]; price: { net: number; total: number; gross: number; base: number; booking: number; shipping: number; sms: number; refunded: number; discount: number; gateway: number; dispute: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; couponCode?: { name: string; active: boolean; couponId: string; teamId: string; id?: string; createdAt?: string; updatedAt?: string; uses?: number; }; stripeConnectAvailability?: { available: boolean; reasons: (\"FEATURE_DISABLED\" | \"UNSUPPORTED_CURRENCY\" | \"NOT_ROUTED\" | \"NO_CONNECTED_GATEWAY\" | \"CHARGES_DISABLED\" | \"INCOMPATIBLE_FEE_STRUCTURE\")[]; supportedCurrencies: (\"AUD\" | \"NZD\" | \"USD\")[]; }; }",
1456
1975
  "references": {
1457
1976
  "OrderQuote": {
1458
1977
  "location": "import",
1459
1978
  "path": "@session-services/sdk/schemas",
1460
- "id": "../../sdk/src/schemas.ts::OrderQuote"
1979
+ "id": "../../sdk/src/schemas.ts::OrderQuote",
1980
+ "referenceLocation": "OrderQuote"
1461
1981
  }
1462
1982
  }
1463
1983
  },
@@ -1579,8 +2099,13 @@ export class SessionsTicketing {
1579
2099
  "selectedItems": {},
1580
2100
  "quote": {},
1581
2101
  "previewQuote": {},
1582
- "loading": {},
2102
+ "initialLoading": {},
2103
+ "eventLoading": {},
2104
+ "retryLoading": {},
2105
+ "passcodeLoading": {},
1583
2106
  "error": {},
2107
+ "errorKind": {},
2108
+ "refreshError": {},
1584
2109
  "quoteLoading": {},
1585
2110
  "previewLoading": {},
1586
2111
  "quoteError": {},
@@ -1592,8 +2117,10 @@ export class SessionsTicketing {
1592
2117
  "passcodeDenied": {},
1593
2118
  "selectionPrompt": {},
1594
2119
  "checkoutLoading": {},
2120
+ "checkoutError": {},
1595
2121
  "currentTheme": {},
1596
- "openModalAdmissionId": {}
2122
+ "openModalAdmissionId": {},
2123
+ "verificationRequired": {}
1597
2124
  };
1598
2125
  }
1599
2126
  static get events() {
@@ -1608,8 +2135,8 @@ export class SessionsTicketing {
1608
2135
  "text": ""
1609
2136
  },
1610
2137
  "complexType": {
1611
- "original": "{\n orderId: string;\n checkoutUrl: string;\n }",
1612
- "resolved": "{ orderId: string; checkoutUrl: string; }",
2138
+ "original": "{\n orderId?: string;\n checkoutUrl?: string;\n }",
2139
+ "resolved": "{ orderId?: string; checkoutUrl?: string; }",
1613
2140
  "references": {}
1614
2141
  }
1615
2142
  }, {
@@ -1624,12 +2151,13 @@ export class SessionsTicketing {
1624
2151
  },
1625
2152
  "complexType": {
1626
2153
  "original": "OrderQuote",
1627
- "resolved": "{ items: { id: string; kind: \"ADMISSION\" | \"ADDON\"; quantity: number; price: { net: number; total: number; gross: number; base: number; booking: number; refunded: number; discount: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; admissionId?: string; sectionId?: string; admission?: { name: string; capacity: number; limit: number; order: number; entryStartsAt: string; entryEndsAt: string; saleStartsAt: string; saleEndsAt: string; saleEndsBehavior: \"SALE_ENDED\" | \"SOLD_OUT\" | \"DOOR\"; price: { base: number; booking: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; visibility: \"ALWAYS\" | \"HIDDEN\"; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; subtitle?: string; description?: string; available?: number; sold?: number; reserved?: number; createdAt?: string; updatedAt?: string; sectionId?: string; }; section?: { name: string; capacity: number; limit: number; order: number; visibility: \"ALWAYS\" | \"HIDDEN\" | \"STACKED\"; location: { createdAt: string; updatedAt: string; name: string; address: string; country: string; latitude: number; longitude: number; timeZone: string; id?: string; googlePlaceId?: string; city?: string; state?: string; postcode?: string; types?: string[]; description?: string; image?: { src: string; alt: string; width: number; height: number; }; venueId?: string; }; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; createdAt?: string; updatedAt?: string; available?: number; sold?: number; reserved?: number; }; }[]; price: { net: number; total: number; gross: number; base: number; booking: number; shipping: number; sms: number; refunded: number; discount: number; gateway: number; dispute: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; couponCode?: { name: string; active: boolean; couponId: string; teamId: string; id?: string; createdAt?: string; updatedAt?: string; uses?: number; }; }",
2154
+ "resolved": "{ items: { id: string; kind: \"ADMISSION\" | \"ADDON\"; quantity: number; price: { net: number; total: number; gross: number; base: number; booking: number; refunded: number; discount: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; admissionId?: string; sectionId?: string; admission?: { name: string; capacity: number; limit: number; order: number; entryStartsAt: string; entryEndsAt: string; saleStartsAt: string; saleEndsAt: string; saleEndsBehavior: \"SALE_ENDED\" | \"SOLD_OUT\" | \"DOOR\"; price: { base: number; booking: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; override?: { booking: number; }; }; visibility: \"ALWAYS\" | \"HIDDEN\" | \"AFTER_ADMISSION\"; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; subtitle?: string; description?: string; available?: number; sold?: number; reserved?: number; createdAt?: string; updatedAt?: string; visibleAfterAdmissionId?: string; sectionId?: string; }; section?: { name: string; capacity: number; limit: number; order: number; visibility: \"ALWAYS\" | \"HIDDEN\" | \"STACKED\"; location: { createdAt: string; updatedAt: string; name: string; address: string; country: string; latitude: number; longitude: number; timeZone: string; id?: string; googlePlaceId?: string; city?: string; state?: string; postcode?: string; types?: string[]; description?: string; image?: { src: string; alt: string; width: number; height: number; }; venueId?: string; }; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; createdAt?: string; updatedAt?: string; available?: number; sold?: number; reserved?: number; }; }[]; price: { net: number; total: number; gross: number; base: number; booking: number; shipping: number; sms: number; refunded: number; discount: number; gateway: number; dispute: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; couponCode?: { name: string; active: boolean; couponId: string; teamId: string; id?: string; createdAt?: string; updatedAt?: string; uses?: number; }; stripeConnectAvailability?: { available: boolean; reasons: (\"FEATURE_DISABLED\" | \"UNSUPPORTED_CURRENCY\" | \"NOT_ROUTED\" | \"NO_CONNECTED_GATEWAY\" | \"CHARGES_DISABLED\" | \"INCOMPATIBLE_FEE_STRUCTURE\")[]; supportedCurrencies: (\"AUD\" | \"NZD\" | \"USD\")[]; }; }",
1628
2155
  "references": {
1629
2156
  "OrderQuote": {
1630
2157
  "location": "import",
1631
2158
  "path": "@session-services/sdk/schemas",
1632
- "id": "../../sdk/src/schemas.ts::OrderQuote"
2159
+ "id": "../../sdk/src/schemas.ts::OrderQuote",
2160
+ "referenceLocation": "OrderQuote"
1633
2161
  }
1634
2162
  }
1635
2163
  }
@@ -1648,6 +2176,27 @@ export class SessionsTicketing {
1648
2176
  "resolved": "{ error: string; }",
1649
2177
  "references": {}
1650
2178
  }
2179
+ }, {
2180
+ "method": "analyticsEventSkipped",
2181
+ "name": "analyticsEventSkipped",
2182
+ "bubbles": true,
2183
+ "cancelable": true,
2184
+ "composed": true,
2185
+ "docs": {
2186
+ "tags": [],
2187
+ "text": ""
2188
+ },
2189
+ "complexType": {
2190
+ "original": "AnalyticsEventSkipped",
2191
+ "resolved": "{ eventType: string; eventId: string; reason: AnalyticsSkipReason; promoterId?: string; teamId?: string; }",
2192
+ "references": {
2193
+ "AnalyticsEventSkipped": {
2194
+ "location": "local",
2195
+ "path": "/Users/j/Dev/sessions-repo/packages/elements/web/src/components/session-services-ticketing/session-services-ticketing.tsx",
2196
+ "id": "src/components/session-services-ticketing/session-services-ticketing.tsx::AnalyticsEventSkipped"
2197
+ }
2198
+ }
2199
+ }
1651
2200
  }];
1652
2201
  }
1653
2202
  static get elementRef() { return "host"; }