@riverbankcms/sdk 0.142.0 → 0.143.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/{PreviewEditorSidebar-Dk6Dt11f.mjs → PreviewEditorSidebar-DROGfMKi.mjs} +4 -4
  2. package/dist/{PreviewEditorUI-D6EQTsCA.mjs → PreviewEditorUI-BaRjhFu-.mjs} +3 -3
  3. package/dist/{PreviewQueryProvider-CC-EPkyQ.mjs → PreviewQueryProvider-BCYICImX.mjs} +1 -1
  4. package/dist/{SdkPreviewModeRuntime-DH1n4ytY.mjs → SdkPreviewModeRuntime-OIABYLES.mjs} +5 -5
  5. package/dist/{SiteChromeCustomizeContext-DunIzY0K.mjs → SiteChromeCustomizeContext-ohjTvZbc.mjs} +491 -525
  6. package/dist/_dts/api/src/endpoints.d.ts +7 -0
  7. package/dist/_dts/api/src/publicEventEndpointDefinitions.d.ts +7 -0
  8. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +48 -41
  9. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +2 -1
  10. package/dist/_dts/blocks/src/system/runtime/api/endpoints.d.ts +8 -0
  11. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +95 -35
  12. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PaymentStatusStep.d.ts +10 -0
  13. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/TicketSelectionStep.d.ts +0 -2
  14. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +12 -1
  15. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +2 -2
  16. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationCompletion.d.ts +1 -4
  17. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationDerivations.d.ts +12 -0
  18. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.d.ts +1 -1
  19. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/sessionStorage.d.ts +1 -0
  20. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.d.ts +4 -5
  21. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +9 -11
  22. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +56 -2
  23. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +10 -4
  24. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.d.ts +23 -0
  25. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/utils.d.ts +1 -1
  26. package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +4 -4
  27. package/dist/_dts/commerce/src/purchase/eventCheckoutRecoveryWindow.d.ts +8 -0
  28. package/dist/_dts/commerce/src/purchase/index.d.ts +2 -1
  29. package/dist/_dts/commerce/src/purchase/stateTransitions.d.ts +1 -13
  30. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +3113 -3077
  31. package/dist/_dts/sdk/src/version.d.ts +1 -1
  32. package/dist/client/{BookingConsentAgreement-CnJeq3_r.mjs → BookingConsentAgreement-BoCtvzzu.mjs} +2 -2
  33. package/dist/client/{DiscountCodeDisclosure-BINEO6J9.mjs → DiscountCodeDisclosure-B5S30nZk.mjs} +1 -1
  34. package/dist/client/{EventCombined.client-srxNQ6sZ.mjs → EventCombined.client-CeZ2-zSt.mjs} +5 -5
  35. package/dist/client/{EventListing.client-DbyVyGkX.mjs → EventListing.client-DJN3j8B3.mjs} +2 -2
  36. package/dist/client/{LeafletStaticMap-B-wpijzL.mjs → LeafletStaticMap-RjtGzDQT.mjs} +1 -1
  37. package/dist/client/{accordion-B-iUXU7n.mjs → accordion-DOmnDoyg.mjs} +1 -1
  38. package/dist/client/{bookingForm-BXYPke5q.mjs → bookingForm-C0vk7pgS.mjs} +5 -5
  39. package/dist/client/bookings.mjs +449 -525
  40. package/dist/client/{carousel-Cr4aj63H.mjs → carousel-BZJ7pno3.mjs} +1 -1
  41. package/dist/client/{cart-DibP9WWa.mjs → cart-CaeVAHJl.mjs} +3 -3
  42. package/dist/client/{checkout-CrSBVnL8.mjs → checkout-7wmoNDtG.mjs} +3 -3
  43. package/dist/client/client.mjs +518 -540
  44. package/dist/client/{context-Ces-AgdR.mjs → context-BOimxE3U.mjs} +12 -1
  45. package/dist/client/{dates-BXyNeNhB.mjs → dates-BnzVksi4.mjs} +2 -2
  46. package/dist/client/{eventCalendar-HwpPeqrH.mjs → eventCalendar-l-fpaslC.mjs} +7 -7
  47. package/dist/client/{eventCombined-BpFUkuEI.mjs → eventCombined-DGGvssK6.mjs} +3 -3
  48. package/dist/client/{eventDetails-DK_agiWy.mjs → eventDetails-DRiCm_hL.mjs} +4 -4
  49. package/dist/client/{eventListing-DhzHqP1c.mjs → eventListing-dph8loYX.mjs} +3 -3
  50. package/dist/client/{eventRegistration-BdQ_Dn2d.mjs → eventRegistration-ClBohmbY.mjs} +472 -530
  51. package/dist/client/{form-B1frcuzy.mjs → form-BLVVAnd3.mjs} +2 -2
  52. package/dist/client/{headerSection-CT5z460s.mjs → headerSection-DHy4C8Ix.mjs} +2 -2
  53. package/dist/client/hooks.mjs +12 -0
  54. package/dist/client/{locationMap-CIQXB9i2.mjs → locationMap-6HuS28ck.mjs} +2 -2
  55. package/dist/client/{newsletterForm-BYNYZSes.mjs → newsletterForm-xOdcOhZP.mjs} +2 -2
  56. package/dist/client/{pricing-CbTlAsmt.mjs → pricing-ChinRYFt.mjs} +1 -1
  57. package/dist/client/{productDetail-CR7Z3yjS.mjs → productDetail-0chA5gbK.mjs} +3 -3
  58. package/dist/client/{productList-DXj00vzR.mjs → productList-OoINA0h1.mjs} +3 -3
  59. package/dist/client/{propsDecoder-DiLiBdek.mjs → propsDecoder-CIZ-hbIG.mjs} +14 -1
  60. package/dist/client/rendering/client.mjs +506 -539
  61. package/dist/client/rendering/islands.mjs +17 -17
  62. package/dist/client/rendering.mjs +517 -539
  63. package/dist/client/{scrollToBlock-CrcbBf0h.mjs → scrollToBlock-BPZl0gPZ.mjs} +1 -1
  64. package/dist/client/{shop-DgqiB_1b.mjs → shop-CLJFqNIq.mjs} +6 -6
  65. package/dist/client/{shop-commerce-D_J781in.mjs → shop-commerce-PpANg5wB.mjs} +5 -5
  66. package/dist/client/{shop-commerce-store-PGUbDwqe.mjs → shop-commerce-store-TA_Kz2ku.mjs} +1 -1
  67. package/dist/client/{shopShared-C_Bb2zwG.mjs → shopShared-DzcFcA5g.mjs} +3 -3
  68. package/dist/client/{useEventFilters-CM17Xpr1.mjs → useEventFilters-CFU21QZo.mjs} +5 -5
  69. package/dist/preview-next/before-render.mjs +11 -0
  70. package/dist/preview-next/client/runtime.mjs +4 -4
  71. package/dist/preview-next/keepAlive.mjs +11 -0
  72. package/dist/preview-next/middleware.mjs +11 -0
  73. package/dist/{previewAuthStore-oVttoRDO.mjs → previewAuthStore-JA6-I_sL.mjs} +11 -0
  74. package/dist/{sdk-runtime-DhmuRhIX.mjs → sdk-runtime-CDKl0Fr7.mjs} +2 -2
  75. package/dist/{separator-C3hlg9LH.mjs → separator-BTp96X32.mjs} +1 -1
  76. package/dist/server/components.mjs +12 -2
  77. package/dist/server/config-validation.mjs +12 -0
  78. package/dist/server/config.mjs +12 -0
  79. package/dist/server/data.mjs +12 -0
  80. package/dist/server/index.mjs +12 -1
  81. package/dist/server/next.mjs +13 -3
  82. package/dist/server/page-converter.mjs +1 -0
  83. package/dist/server/prebuild.mjs +1 -1
  84. package/dist/server/rendering/server.mjs +12 -0
  85. package/dist/server/rendering.mjs +12 -2
  86. package/dist/server/routing.mjs +12 -0
  87. package/dist/server/server.mjs +13 -1
  88. package/package.json +1 -1
  89. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/checkoutRecovery.d.ts +0 -14
  90. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useCheckoutRecovery.d.ts +0 -8
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { d as unwrapResponse, l as ApiEnvelopeError, s as ApiRequestError, u as extractApiEnvelopeErrorDetails } from "./previewAuthStore-oVttoRDO.mjs";
2
+ import { d as unwrapResponse, l as ApiEnvelopeError, s as ApiRequestError, u as extractApiEnvelopeErrorDetails } from "./previewAuthStore-JA6-I_sL.mjs";
3
3
  import * as React$1 from "react";
4
4
  import React, { Component, Fragment, cloneElement, createContext, createElement, createRef, forwardRef, isValidElement, memo, startTransition, useCallback, useContext, useDebugValue, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
5
5
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -89884,6 +89884,10 @@ const EVENTS = {
89884
89884
  method: "POST",
89885
89885
  authScope: "portal"
89886
89886
  },
89887
+ registrationNextStep: {
89888
+ path: "/public/sites/{siteId}/events/registration-next-step",
89889
+ method: "POST"
89890
+ },
89887
89891
  registrationStatus: {
89888
89892
  path: "/public/sites/{siteId}/events/registration-status",
89889
89893
  method: "GET"
@@ -90488,6 +90492,13 @@ function createBlockApi(config) {
90488
90492
  body: data
90489
90493
  });
90490
90494
  },
90495
+ async checkRegistrationNextStep(data) {
90496
+ const path = buildPath(EVENTS.registrationNextStep.path, { siteId: requireSiteId() });
90497
+ return request(EVENTS.registrationNextStep, {
90498
+ path,
90499
+ body: data
90500
+ });
90501
+ },
90491
90502
  async getEventRegistrationStatus(params) {
90492
90503
  const sid = requireSiteId();
90493
90504
  const path = buildPath(EVENTS.registrationStatus.path, { siteId: sid });
@@ -118917,6 +118928,18 @@ function getStepNumber(step, wizardSteps) {
118917
118928
  }
118918
118929
  //#endregion
118919
118930
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
118931
+ /** Public requests share subject identity without copying the run's display sessions. */
118932
+ function toRegistrationRequestSubject(subject, attendanceMode) {
118933
+ return subject.kind === "occurrence" ? {
118934
+ kind: "occurrence",
118935
+ occurrenceId: subject.occurrenceId,
118936
+ attendanceMode: attendanceMode ?? void 0
118937
+ } : {
118938
+ kind: "wholeSeries",
118939
+ eventSeriesId: subject.eventSeriesId,
118940
+ attendanceMode: attendanceMode ?? void 0
118941
+ };
118942
+ }
118920
118943
  function eventMatchesOccurrenceId(event, occurrenceId) {
118921
118944
  return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
118922
118945
  }
@@ -119212,6 +119235,7 @@ function shellLabelForRegistrationStep(step, events) {
119212
119235
  case "redirecting":
119213
119236
  case "verifying-payment":
119214
119237
  case "verifying-timeout":
119238
+ case "payment-status":
119215
119239
  case "payment-failed": return "Details";
119216
119240
  }
119217
119241
  }
@@ -129184,7 +129208,7 @@ function resolveEventRegistrationDirectPaymentSelection(input) {
129184
129208
  //#endregion
129185
129209
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationStateMachine.ts
129186
129210
  function hasBlockingExistingRegistration(input) {
129187
- return !input.hasWaitlistClaim && input.isAuthenticated && input.registration.kind !== "none";
129211
+ return !input.hasWaitlistClaim && input.isAuthenticated && input.registration.kind === "waitlisted";
129188
129212
  }
129189
129213
  function createInitialRegistrationFlowState(hasPreSelectedContext) {
129190
129214
  return {
@@ -129236,7 +129260,7 @@ function computeAutoSelection(input) {
129236
129260
  return { method: null };
129237
129261
  }
129238
129262
  function computeDirectPaymentSelection(eligibility) {
129239
- if (!eligibility?.canPayDirectly) return { method: null };
129263
+ if (!eligibility?.requiresPayment) return { method: null };
129240
129264
  const approvedKinds = getApprovedDirectPaymentCollectionOptionKinds(eligibility.paymentOptions);
129241
129265
  const collectionOptionKind = approvedKinds.includes("upfront") ? "upfront" : approvedKinds[0];
129242
129266
  return collectionOptionKind ? {
@@ -129250,7 +129274,7 @@ function isSelectionValid(input) {
129250
129274
  if (!eligibility) return selection.method === "stripe" || selection.method === "pass_bundle" || selection.method === "membership_bundle";
129251
129275
  switch (selection.method) {
129252
129276
  case "free": return eligibility.isFree;
129253
- case "stripe": return Boolean(eligibility.canPayDirectly && eligibility.price);
129277
+ case "stripe": return Boolean(eligibility.requiresPayment && eligibility.price);
129254
129278
  case "pass": return isAuthenticated && ticketsCount === 1 && !!selection.passId && eligibility.eligiblePasses.some((pass) => pass.id === selection.passId);
129255
129279
  case "membership": return isAuthenticated && ticketsCount === 1 && !!selection.membershipId && eligibility.eligibleMemberships.some((membership) => membership.id === selection.membershipId);
129256
129280
  case "pass_bundle": return ticketsCount === 1 && !!selection.bundlePassId && eligibility.availablePasses.some((pass) => pass.id === selection.bundlePassId);
@@ -129269,7 +129293,7 @@ function normalizeRegistrationFlowState(state) {
129269
129293
  ticketsCount: state.ticketsCount,
129270
129294
  passOptOut: nextPassOptOut
129271
129295
  });
129272
- const canKeepManualSelection = state.step === "select-payment" && state.selectionSource === "manual" && isSelectionValid({
129296
+ const canKeepManualSelection = state.step !== "select-tickets" && state.selectionSource === "manual" && isSelectionValid({
129273
129297
  selection: state.paymentSelection,
129274
129298
  isAuthenticated: state.isAuthenticated,
129275
129299
  eligibility: state.eligibility,
@@ -129352,7 +129376,7 @@ function resolveEventRegistrationSubmitPlan(input) {
129352
129376
  const selection = input.paymentSelection.method ? input.paymentSelection : void 0;
129353
129377
  if (input.canJoinWaitlist) return {
129354
129378
  ok: true,
129355
- args: withOptionalSelection({ method: "free" }, selection)
129379
+ args: { method: "free" }
129356
129380
  };
129357
129381
  switch (input.paymentSelection.method) {
129358
129382
  case "pass": return input.paymentSelection.passId ? {
@@ -129411,88 +129435,53 @@ function missingPaymentSelection() {
129411
129435
  };
129412
129436
  }
129413
129437
  //#endregion
129414
- //#region ../blocks/src/system/runtime/nodes/event-registration/checkoutRecovery.ts
129415
- /** Recovery may select held places; checkout still owns admission and payment validation. */
129416
- function checkoutRecoveryOptionAvailability(availability) {
129417
- if (availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable") return {
129418
- kind: "available",
129419
- remainingPlaces: null
129420
- };
129421
- return availability;
129438
+ //#region ../blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.ts
129439
+ /** Ticket selection requests a quote; only the server admits a booking. */
129440
+ function canRequestTicketOption(availability) {
129441
+ return availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable";
129422
129442
  }
129423
- /**
129424
- * A form-only projection for the explicit existing-checkout path. It permits
129425
- * collecting the original selection without claiming a new place is available.
129426
- * The public checkout service identifies the customer and remains the admission
129427
- * authority; no reservation/customer data is exposed through this projection.
129428
- */
129429
- function getCheckoutRecoveryFormEligibility(eligibility) {
129430
- if (!eligibility || eligibility.registration.kind !== "none" && eligibility.registration.kind !== "pending_payment" || eligibility.availability.kind === "unavailable" && eligibility.availability.reason !== "full" && eligibility.availability.reason !== "selectionRequired") return eligibility;
129431
- const amountCents = eligibility.price ?? 0;
129432
- if (amountCents <= 0 || !eligibility.currency || eligibility.availability.kind === "unavailable" && eligibility.availability.reason === "selectionRequired") return eligibility.registration.kind === "pending_payment" ? {
129433
- ...eligibility,
129434
- registration: { kind: "none" },
129435
- ticketTypes: eligibility.ticketTypes.map((option) => ({
129436
- ...option,
129437
- availability: checkoutRecoveryOptionAvailability(option.availability)
129438
- }))
129439
- } : eligibility;
129440
- const currency = eligibility.currency;
129441
- const paymentOptions = eligibility.paymentTerms.allowedOptions.map((option) => {
129442
- switch (option.kind) {
129443
- case "upfront": return {
129444
- kind: "payInFull",
129445
- amountCents,
129446
- currency
129447
- };
129448
- case "deferred_manual": return {
129449
- kind: "deferredManual",
129450
- amountCents,
129451
- currency
129452
- };
129453
- case "instalment_plan": return {
129454
- kind: "instalmentPlan",
129455
- amountCents,
129456
- currency
129457
- };
129458
- case "flexible_balance": return {
129459
- kind: "flexibleBalance",
129460
- amountCents,
129461
- currency
129462
- };
129463
- }
129464
- });
129465
- return {
129466
- ...eligibility,
129467
- registration: { kind: "none" },
129468
- availability: {
129469
- kind: "available",
129470
- remainingPlaces: null,
129471
- waitlistEnabled: eligibility.waitlistEnabled
129472
- },
129473
- eligible: paymentOptions.length > 0,
129474
- isFull: false,
129475
- canJoinWaitlist: false,
129476
- isFree: false,
129477
- requiresPayment: true,
129478
- canPayDirectly: paymentOptions.length > 0,
129479
- paymentOptions,
129480
- eligiblePasses: [],
129481
- eligibleMemberships: [],
129482
- ticketTypes: eligibility.ticketTypes.map((option) => ({
129483
- ...option,
129484
- availability: checkoutRecoveryOptionAvailability(option.availability)
129485
- }))
129486
- };
129443
+ function normalizeTicketSelectionLines(lines) {
129444
+ const quantitiesByTicketType = /* @__PURE__ */ new Map();
129445
+ for (const line of lines) {
129446
+ const quantity = Math.floor(line.quantity);
129447
+ if (quantity <= 0) continue;
129448
+ const key = line.pricingOptionId ?? null;
129449
+ quantitiesByTicketType.set(key, (quantitiesByTicketType.get(key) ?? 0) + quantity);
129450
+ }
129451
+ return [...quantitiesByTicketType.entries()].map(([pricingOptionId, quantity]) => ({
129452
+ pricingOptionId,
129453
+ quantity
129454
+ }));
129455
+ }
129456
+ function getTicketSelectionTotal(lines) {
129457
+ return normalizeTicketSelectionLines(lines).reduce((total, line) => total + line.quantity, 0);
129458
+ }
129459
+ function getTicketLineQuantity(lines, pricingOptionId) {
129460
+ return normalizeTicketSelectionLines(lines).find((line) => line.pricingOptionId === pricingOptionId)?.quantity ?? 0;
129487
129461
  }
129488
- function isSoldOutEventSelectable(event, waitlistAvailable) {
129489
- return waitlistAvailable || canRecoverEventCheckout(event);
129462
+ function getSingleSelectedPricingOptionId(lines) {
129463
+ const normalized = normalizeTicketSelectionLines(lines);
129464
+ return normalized.length === 1 ? normalized[0]?.pricingOptionId ?? null : null;
129490
129465
  }
129491
- function canJoinWaitlistOutsideRecovery(event, attendanceMode, checkoutRecovery) {
129492
- return !checkoutRecovery && event !== null && canJoinEventWaitlist(event, { attendanceMode });
129466
+ function hasValidPricingOptionSelection(input) {
129467
+ if (!input.selectionRequired) return true;
129468
+ if (input.lines.length === 0) return false;
129469
+ const availableOptionIds = new Set(input.visibleOptions.filter((option) => canRequestTicketOption(option.availability)).map((option) => option.pricingOptionId));
129470
+ return input.lines.every((line) => line.pricingOptionId !== null && availableOptionIds.has(line.pricingOptionId));
129493
129471
  }
129494
- function canRecoverEventCheckout(event) {
129495
- return event !== null && (event.registrationSubject.kind === "wholeSeries" || event.pricing.kind !== "free" && event.pricing.kind !== "external");
129472
+ function setTicketLineQuantity(input) {
129473
+ const nextQuantity = Math.max(0, Math.floor(input.quantity));
129474
+ const normalized = normalizeTicketSelectionLines(input.lines).filter((line) => line.pricingOptionId !== input.pricingOptionId);
129475
+ if (nextQuantity <= 0) return normalized;
129476
+ return [...normalized, {
129477
+ pricingOptionId: input.pricingOptionId,
129478
+ quantity: nextQuantity
129479
+ }];
129480
+ }
129481
+ function getTicketTypeLineMax(input) {
129482
+ const otherSelectedQuantity = input.totalSelectedQuantity - input.currentQuantity;
129483
+ const maxByBlock = input.maxTickets - otherSelectedQuantity;
129484
+ return Math.max(0, maxByBlock);
129496
129485
  }
129497
129486
  //#endregion
129498
129487
  //#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
@@ -129559,8 +129548,6 @@ function formatPassCreditUsageLabel(creditsRemaining) {
129559
129548
  return `Uses 1 of ${creditsRemaining} credits`;
129560
129549
  }
129561
129550
  function transformRegistrationOptionsResponse(response) {
129562
- const canJoinWaitlist = response.availability.kind === "waitlist";
129563
- const isFull = response.availability.remainingPlaces === 0 || response.availability.kind === "unavailable" && response.availability.reason === "full";
129564
129551
  const eligiblePasses = response.entitlements.passes.map((pass) => ({
129565
129552
  id: pass.customerPassId,
129566
129553
  passName: pass.passName,
@@ -129573,7 +129560,6 @@ function transformRegistrationOptionsResponse(response) {
129573
129560
  const eventAcceptsPasses = response.entitlements.requiresLoginForPasses || eligiblePasses.length > 0 || response.entitlements.availableForPurchase.passes.length > 0;
129574
129561
  const eventAcceptsMemberships = response.entitlements.requiresLoginForMemberships || eligibleMemberships.length > 0 || response.entitlements.availableForPurchase.memberships.length > 0;
129575
129562
  const monetaryPaymentAvailable = hasMonetaryPaymentOption(response);
129576
- const registrationAvailable = response.availability.kind === "available" || response.availability.kind === "waitlist";
129577
129563
  return {
129578
129564
  availability: response.availability,
129579
129565
  registration: response.registration,
@@ -129588,7 +129574,6 @@ function transformRegistrationOptionsResponse(response) {
129588
129574
  },
129589
129575
  transactions: []
129590
129576
  } : null,
129591
- eligible: response.registration.kind === "none" && registrationAvailable,
129592
129577
  requiresPayment: monetaryPaymentAvailable,
129593
129578
  pricingStrategy: response.pricing.strategy,
129594
129579
  paymentTerms: response.pricing.paymentTerms,
@@ -129603,16 +129588,12 @@ function transformRegistrationOptionsResponse(response) {
129603
129588
  currency: response.pricing.currency
129604
129589
  })),
129605
129590
  ticketTypes: response.pricing.options,
129606
- isFull,
129607
- waitlistEnabled: response.availability.waitlistEnabled,
129608
- canJoinWaitlist,
129609
129591
  price: response.pricing.subtotalCents,
129610
129592
  currency: response.pricing.currency,
129611
129593
  requiresAuthForPasses: response.entitlements.requiresLoginForPasses,
129612
129594
  requiresAuthForMemberships: response.entitlements.requiresLoginForMemberships,
129613
129595
  eligiblePasses,
129614
129596
  eligibleMemberships,
129615
- canPayDirectly: monetaryPaymentAvailable,
129616
129597
  eventAcceptsPasses,
129617
129598
  eventAcceptsMemberships,
129618
129599
  availablePasses: [...response.entitlements.availableForPurchase.passes],
@@ -129642,8 +129623,8 @@ function getVisibleTicketTypes(input) {
129642
129623
  })) : [];
129643
129624
  return (input.eligibility?.ticketTypes ?? eventTicketTypes).filter((ticketType) => ticketType.isActive && (!input.selectedAttendanceMode || (ticketType.attendanceScope ?? "both") === "both" || (ticketType.attendanceScope ?? "both") === input.selectedAttendanceMode));
129644
129625
  }
129645
- function getImplicitSingleAvailableTicketType(ticketTypes) {
129646
- return ticketTypes.length === 1 && ticketTypes[0]?.availability.kind === "available" ? ticketTypes[0] : null;
129626
+ function getImplicitSingleTicketType(ticketTypes) {
129627
+ return ticketTypes.length === 1 && ticketTypes[0] && canRequestTicketOption(ticketTypes[0].availability) ? ticketTypes[0] : null;
129647
129628
  }
129648
129629
  function findSelectedTicketType(input) {
129649
129630
  if (!input.selectedPricingOptionId) return null;
@@ -129680,25 +129661,19 @@ const EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCa
129680
129661
  const remaining = getRemainingPlaces(selectMostOpenCapacitySource(event));
129681
129662
  const isSoldOut = isEventFull(event);
129682
129663
  const canJoinWaitlist = canJoinEventWaitlistOnAnyMode(event);
129683
- const isUnavailable = isSoldOut && !isSoldOutEventSelectable(event, canJoinWaitlist);
129684
129664
  const isLowCapacity = remaining.kind === "low";
129685
129665
  const capacityLabel = formatEventRemainingPlaces(event, { full: "Sold out" });
129686
129666
  const timeZone = event.timeZone ?? null;
129687
- const cardClasses = [
129688
- "er-event-card",
129689
- isSelected && "er-event-card--selected",
129690
- isUnavailable && "er-event-card--disabled"
129691
- ].filter(Boolean).join(" ");
129667
+ const cardClasses = ["er-event-card", isSelected && "er-event-card--selected"].filter(Boolean).join(" ");
129692
129668
  const badgeClasses = [
129693
129669
  "er-capacity-badge",
129694
- isUnavailable && "er-capacity-badge--soldout",
129670
+ isSoldOut && "er-capacity-badge--soldout",
129695
129671
  isLowCapacity && "er-capacity-badge--low",
129696
- (canJoinWaitlist || !isUnavailable && !isLowCapacity) && "er-capacity-badge--available"
129672
+ (canJoinWaitlist || !isSoldOut && !isLowCapacity) && "er-capacity-badge--available"
129697
129673
  ].filter(Boolean).join(" ");
129698
129674
  return /* @__PURE__ */ jsx("button", {
129699
129675
  type: "button",
129700
- onClick: () => !isUnavailable && onSelect(event),
129701
- disabled: isUnavailable,
129676
+ onClick: () => onSelect(event),
129702
129677
  className: cardClasses,
129703
129678
  children: /* @__PURE__ */ jsxs("div", {
129704
129679
  className: "er-event-option",
@@ -129725,41 +129700,15 @@ const EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCa
129725
129700
  });
129726
129701
  };
129727
129702
  //#endregion
129728
- //#region ../blocks/src/system/runtime/nodes/event-registration/useCheckoutRecovery.ts
129729
- /** Recovery belongs to the selected booking subject; changing events resets its scope. */
129730
- function useCheckoutRecovery(event, setStep) {
129731
- const [recoveryEventId, setRecoveryEventId] = useState(null);
129732
- return {
129733
- checkoutRecovery: event !== null && recoveryEventId === event.selectionId,
129734
- startCheckoutRecovery: useCallback(() => {
129735
- if (!event) return;
129736
- setRecoveryEventId(event.selectionId);
129737
- setStep("select-tickets");
129738
- }, [event, setStep])
129739
- };
129740
- }
129741
- /** Authenticated pending bookings enter the same form-only recovery path as guests. */
129742
- function useCheckoutRecoveryEligibility(eligibility, step, checkoutRecovery, startCheckoutRecovery) {
129743
- const registrationKind = eligibility?.registration.kind;
129744
- useEffect(() => {
129745
- if ((step === "select-event" || step === "select-tickets" || step === "enter-details" || step === "select-payment") && registrationKind === "pending_payment" && !checkoutRecovery) startCheckoutRecovery();
129746
- }, [
129747
- registrationKind,
129748
- step,
129749
- checkoutRecovery,
129750
- startCheckoutRecovery
129751
- ]);
129752
- return useMemo(() => checkoutRecovery ? getCheckoutRecoveryFormEligibility(eligibility) : eligibility, [checkoutRecovery, eligibility]);
129753
- }
129754
- //#endregion
129755
129703
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.ts
129756
129704
  function resolveRegistrationRecoveryAction(step, action) {
129757
129705
  if (step === "payment-failed") return "payment-options";
129758
- if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "payment-status";
129706
+ if (step === "payment-status") return "none";
129707
+ if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "none";
129759
129708
  return action;
129760
129709
  }
129761
129710
  function canRecoverToWaitlist(eligibility) {
129762
- return Boolean(eligibility?.isFull && eligibility.canJoinWaitlist);
129711
+ return eligibility?.availability.kind === "waitlist" && eligibility.registration.kind !== "pending_payment";
129763
129712
  }
129764
129713
  function shouldRefreshAfterRegistrationError(step, action, enabled) {
129765
129714
  return enabled || step === "error" && action === "places";
@@ -129776,19 +129725,19 @@ function resetRegistrationAfterExpiry(input) {
129776
129725
  input.setErrorMessage("");
129777
129726
  input.setPendingRegistrationReference(null);
129778
129727
  }
129779
- /** Recovery never starts another payment. Unknown payment outcomes go to the portal. */
129728
+ /** Retry the retained submission in place; explicit payment uncertainty stays status-only. */
129780
129729
  function recoverRegistrationError(action, handlers) {
129781
129730
  switch (action) {
129782
129731
  case "none": return;
129783
129732
  case "portal":
129784
- case "payment-status":
129785
129733
  window.location.assign("/portal");
129786
129734
  return;
129787
129735
  case "event":
129788
129736
  window.location.assign(window.location.pathname);
129789
129737
  return;
129790
129738
  case "retry":
129791
- window.location.reload();
129739
+ handlers.clearError();
129740
+ handlers.setStep("select-payment");
129792
129741
  return;
129793
129742
  case "details":
129794
129743
  handlers.clearError();
@@ -129826,53 +129775,6 @@ function validateFormData(formData, requiresConsent = false) {
129826
129775
  return errors;
129827
129776
  }
129828
129777
  //#endregion
129829
- //#region ../blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.ts
129830
- function normalizeTicketSelectionLines(lines) {
129831
- const quantitiesByTicketType = /* @__PURE__ */ new Map();
129832
- for (const line of lines) {
129833
- const quantity = Math.floor(line.quantity);
129834
- if (quantity <= 0) continue;
129835
- const key = line.pricingOptionId ?? null;
129836
- quantitiesByTicketType.set(key, (quantitiesByTicketType.get(key) ?? 0) + quantity);
129837
- }
129838
- return [...quantitiesByTicketType.entries()].map(([pricingOptionId, quantity]) => ({
129839
- pricingOptionId,
129840
- quantity
129841
- }));
129842
- }
129843
- function getTicketSelectionTotal(lines) {
129844
- return normalizeTicketSelectionLines(lines).reduce((total, line) => total + line.quantity, 0);
129845
- }
129846
- function getTicketLineQuantity(lines, pricingOptionId) {
129847
- return normalizeTicketSelectionLines(lines).find((line) => line.pricingOptionId === pricingOptionId)?.quantity ?? 0;
129848
- }
129849
- function getSingleSelectedPricingOptionId(lines) {
129850
- const normalized = normalizeTicketSelectionLines(lines);
129851
- return normalized.length === 1 ? normalized[0]?.pricingOptionId ?? null : null;
129852
- }
129853
- function hasValidPricingOptionSelection(input) {
129854
- if (!input.selectionRequired) return true;
129855
- if (input.lines.length === 0) return false;
129856
- const availableOptionIds = new Set(input.visibleOptions.filter((option) => option.availability.kind === "available").map((option) => option.pricingOptionId));
129857
- return input.lines.every((line) => line.pricingOptionId !== null && availableOptionIds.has(line.pricingOptionId));
129858
- }
129859
- function setTicketLineQuantity(input) {
129860
- const nextQuantity = Math.max(0, Math.floor(input.quantity));
129861
- const normalized = normalizeTicketSelectionLines(input.lines).filter((line) => line.pricingOptionId !== input.pricingOptionId);
129862
- if (nextQuantity <= 0) return normalized;
129863
- return [...normalized, {
129864
- pricingOptionId: input.pricingOptionId,
129865
- quantity: nextQuantity
129866
- }];
129867
- }
129868
- function getTicketTypeLineMax(input) {
129869
- const otherSelectedQuantity = input.totalSelectedQuantity - input.currentQuantity;
129870
- const maxByBlock = input.maxTickets - otherSelectedQuantity;
129871
- const maxByEvent = input.availableSpots == null ? input.maxTickets : input.availableSpots - otherSelectedQuantity;
129872
- const maxByTicketType = input.ticketTypeRemainingCapacity ?? input.maxTickets;
129873
- return Math.max(0, Math.min(maxByBlock, maxByEvent, maxByTicketType));
129874
- }
129875
- //#endregion
129876
129778
  //#region ../blocks/src/system/runtime/nodes/event-registration/hooks.state.ts
129877
129779
  const initialEligibilityLookupState = {
129878
129780
  tag: "idle",
@@ -129990,17 +129892,6 @@ function usePortalAuthWithDeps(deps) {
129990
129892
  logout
129991
129893
  };
129992
129894
  }
129993
- function toRegistrationOptionsSubject(subject, attendanceMode) {
129994
- return subject.kind === "occurrence" ? {
129995
- kind: "occurrence",
129996
- occurrenceId: subject.occurrenceId,
129997
- attendanceMode: attendanceMode ?? void 0
129998
- } : {
129999
- kind: "wholeSeries",
130000
- eventSeriesId: subject.eventSeriesId,
130001
- attendanceMode: attendanceMode ?? void 0
130002
- };
130003
- }
130004
129895
  function useEligibility(params) {
130005
129896
  return useEligibilityWithDeps(params, eventRegistrationHooksDeps);
130006
129897
  }
@@ -130041,7 +129932,7 @@ function useEligibilityWithDeps(params, deps) {
130041
129932
  requestIdRef.current = requestId;
130042
129933
  dispatch({ type: "loading-started" });
130043
129934
  try {
130044
- const subject = toRegistrationOptionsSubject(params.subject, params.attendanceMode);
129935
+ const subject = toRegistrationRequestSubject(params.subject, params.attendanceMode);
130045
129936
  const result = await api.getRegistrationOptions({
130046
129937
  subject,
130047
129938
  selections: ticketSelections.map((selection) => ({
@@ -130408,9 +130299,9 @@ const eventRegistrationErrors = {
130408
130299
  message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
130409
130300
  action: "none"
130410
130301
  },
130411
- paymentUncertain: {
130412
- message: "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.",
130413
- action: "payment-status"
130302
+ paymentInvestigationRequired: {
130303
+ message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
130304
+ action: "none"
130414
130305
  },
130415
130306
  paymentProviderUnavailable: {
130416
130307
  message: "We couldn’t reach the payment provider. Please try again in a minute.",
@@ -130904,7 +130795,30 @@ function checkoutReturnCommand(params) {
130904
130795
  };
130905
130796
  return null;
130906
130797
  }
130907
- async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
130798
+ function handleCheckoutReturnOutcome(options, deps, context, outcome) {
130799
+ const { pending, params } = context;
130800
+ if (outcome.kind === "resolved") {
130801
+ deps.clearReturnParams();
130802
+ options.setPendingRegistrationReference(outcome.reference);
130803
+ options.setStep("verifying-payment");
130804
+ return "settled";
130805
+ }
130806
+ if (outcome.kind === "abandoned") {
130807
+ deps.clearReturnParams();
130808
+ options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
130809
+ options.setStep("select-payment");
130810
+ return "settled";
130811
+ }
130812
+ if (outcome.kind === "notFound" && params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
130813
+ deps.clearReturnParams();
130814
+ options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
130815
+ options.setStep("select-payment");
130816
+ return "settled";
130817
+ }
130818
+ showReturnReconciliation(options, "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.");
130819
+ return outcome.kind === "notFound" ? "settled" : "retryable";
130820
+ }
130821
+ async function handleCheckoutReturn(options, deps, returnContextRef) {
130908
130822
  deps.cleanupStaleRegistrations();
130909
130823
  const params = deps.readReturnParams();
130910
130824
  if (params.registration !== "cancelled" && params.registration !== "success") return "settled";
@@ -130918,34 +130832,15 @@ async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
130918
130832
  }
130919
130833
  const { checkoutAttemptId } = command;
130920
130834
  const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
130921
- checkoutAttemptIdRef.current = checkoutAttemptId;
130835
+ returnContextRef.current = { checkoutAttemptId };
130922
130836
  if (pending) restorePendingPresentation(options, pending);
130923
130837
  options.setStep("verifying-payment");
130924
130838
  try {
130925
130839
  const outcome = await options.api.resolveEventCheckoutReturn(command);
130926
- switch (outcome.kind) {
130927
- case "resolved":
130928
- deps.clearReturnParams();
130929
- options.setPendingRegistrationReference(outcome.reference);
130930
- options.setStep("verifying-payment");
130931
- return "settled";
130932
- case "abandoned":
130933
- deps.clearReturnParams();
130934
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
130935
- options.setStep("select-payment");
130936
- return "settled";
130937
- case "notFound":
130938
- if (params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
130939
- deps.clearReturnParams();
130940
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
130941
- options.setStep("select-payment");
130942
- return "settled";
130943
- }
130944
- showReturnReconciliation(options, "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.");
130945
- return "settled";
130946
- case "reconciliationRequired": break;
130947
- }
130948
- showReturnReconciliation(options, "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.");
130840
+ return handleCheckoutReturnOutcome(options, deps, {
130841
+ pending,
130842
+ params
130843
+ }, outcome);
130949
130844
  } catch {
130950
130845
  showReturnReconciliation(options, "We couldn’t check your payment just now. Please check again in a moment. Don’t make another booking while we’re checking.");
130951
130846
  }
@@ -130954,9 +130849,16 @@ async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
130954
130849
  function useEventRegistrationStripeReturn(options) {
130955
130850
  return useEventRegistrationStripeReturnWithDeps(options, eventRegistrationStripeReturnDeps);
130956
130851
  }
130852
+ function completeVerifiedRegistration(options, deps, returnContext) {
130853
+ const siteId = options.api.config.siteId;
130854
+ const checkoutAttemptId = returnContext?.checkoutAttemptId;
130855
+ if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
130856
+ options.setRegistrationResult({ status: "confirmed" });
130857
+ options.setStep("success");
130858
+ }
130957
130859
  function useEventRegistrationStripeReturnWithDeps(options, deps) {
130958
130860
  const { api, pendingRegistrationReference, setErrorMessage, setRegistrationResult, setStep, step } = options;
130959
- const checkoutAttemptIdRef = useRef(null);
130861
+ const returnContextRef = useRef(null);
130960
130862
  const lookupInFlightRef = useRef(false);
130961
130863
  const [lookupState, setLookupState] = useState("settled");
130962
130864
  const resolveReturn = useCallback(async () => {
@@ -130964,7 +130866,7 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
130964
130866
  lookupInFlightRef.current = true;
130965
130867
  setLookupState("loading");
130966
130868
  try {
130967
- setLookupState(await handleCheckoutReturn(options, deps, checkoutAttemptIdRef));
130869
+ setLookupState(await handleCheckoutReturn(options, deps, returnContextRef));
130968
130870
  } finally {
130969
130871
  lookupInFlightRef.current = false;
130970
130872
  }
@@ -130987,13 +130889,8 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
130987
130889
  resolveReturn();
130988
130890
  }, []);
130989
130891
  useEffect(() => {
130990
- if (verification.status === "completed") {
130991
- const siteId = api.config.siteId;
130992
- const checkoutAttemptId = checkoutAttemptIdRef.current;
130993
- if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
130994
- setRegistrationResult({ status: "confirmed" });
130995
- setStep("success");
130996
- } else if (verification.status === "failed") {
130892
+ if (verification.status === "completed") completeVerifiedRegistration(options, deps, returnContextRef.current);
130893
+ else if (verification.status === "failed") {
130997
130894
  setErrorMessage("Please try again or choose another payment option. If this keeps happening, contact the organiser for help.");
130998
130895
  setStep("payment-failed");
130999
130896
  } else if (verification.status === "timeout") setStep("verifying-timeout");
@@ -131022,7 +130919,10 @@ function registrationErrorPresentation(error) {
131022
130919
  const reason = error instanceof BlockApiError ? parseEventRegistrationErrorReason(error.tag) : null;
131023
130920
  if (reason) return eventRegistrationErrors[reason];
131024
130921
  if (error instanceof BlockApiError && error.status < 500) return eventRegistrationErrors.invalidCommitInput;
131025
- return eventRegistrationErrors.paymentUncertain;
130922
+ return {
130923
+ message: "Something went wrong. Please try again.",
130924
+ action: "retry"
130925
+ };
131026
130926
  }
131027
130927
  //#endregion
131028
130928
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.ts
@@ -131051,26 +130951,6 @@ function useEventRegistrationSubmit(options) {
131051
130951
  * and the balance left, which the block's copy cannot. Every other method keeps
131052
130952
  * whatever success message the site configured.
131053
130953
  */
131054
- function toRegistrationResult(result) {
131055
- if (result.alreadyRegistered) {
131056
- const waitlisted = result.status === "waitlist";
131057
- return {
131058
- status: result.status,
131059
- variant: "info",
131060
- title: waitlisted ? "Already waitlisted" : "Already registered",
131061
- message: result.message ?? (waitlisted ? "You are already on the waitlist for this event." : "You are already registered for this event.")
131062
- };
131063
- }
131064
- if (result.status === "waitlist") return {
131065
- status: "waitlist",
131066
- title: "Added to waitlist",
131067
- message: result.message ?? (typeof result.waitlistPosition === "number" ? `You've been added to the waitlist (position ${result.waitlistPosition}).` : "You've been added to the waitlist.")
131068
- };
131069
- return {
131070
- status: result.status,
131071
- message: result.paymentMethod === "pass" ? result.message : void 0
131072
- };
131073
- }
131074
130954
  function useEventRegistrationSubmitWithDeps(options, deps) {
131075
130955
  /**
131076
130956
  * The command identity for the submission currently in progress.
@@ -131084,7 +130964,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
131084
130964
  * Identical retries retain the command after a lost response. Changed form
131085
130965
  * details get a new command so the server applies the new booking intent.
131086
130966
  */
131087
- const commandRef = useRef(null);
130967
+ const { commandRef } = options;
131088
130968
  const inFlightRef = useRef(null);
131089
130969
  const submit = async (method, passId, membershipId, selection, submitOptions) => {
131090
130970
  const target = options.registrationTarget;
@@ -131097,19 +130977,15 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
131097
130977
  const registrationCommandId = commandRef.current?.id ?? deps.createClientCommandId();
131098
130978
  try {
131099
130979
  let prepared = prepareSubmitContext(options, registrationCommandId, target, method, passId, membershipId, selection);
131100
- if (prepared.subject.kind === "wholeSeries" && method === "stripe") {
131101
- commandRef.current = null;
131102
- return await submitWholeSeriesCheckout(options, deps, {
130980
+ let request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
130981
+ const intentKey = registrationRequestIntentKey(request);
130982
+ if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) {
130983
+ prepared = {
131103
130984
  ...prepared,
131104
- subject: prepared.subject
131105
- }, submitOptions);
130985
+ registrationCommandId: deps.createClientCommandId()
130986
+ };
130987
+ request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
131106
130988
  }
131107
- const request = buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId);
131108
- const intentKey = registrationRequestIntentKey(request);
131109
- if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) prepared = {
131110
- ...prepared,
131111
- registrationCommandId: deps.createClientCommandId()
131112
- };
131113
130989
  commandRef.current = {
131114
130990
  id: prepared.registrationCommandId,
131115
130991
  intentKey
@@ -131118,8 +130994,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
131118
130994
  ...request,
131119
130995
  registrationCommandId: prepared.registrationCommandId
131120
130996
  });
131121
- commandRef.current = null;
131122
- return await completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions);
130997
+ return await completeRegistrationSubmission(options, deps, prepared, result, submitOptions);
131123
130998
  } catch (error) {
131124
130999
  if (error instanceof BlockApiError && error.tag === "registrationPreparationChanged") commandRef.current = null;
131125
131000
  const { message, action } = registrationErrorPresentation(error);
@@ -131143,9 +131018,40 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
131143
131018
  return pending;
131144
131019
  };
131145
131020
  }
131146
- async function completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions) {
131147
- if (needsOccurrenceCheckout(result, method)) return await submitOccurrenceCheckout(options, deps, prepared, result, method, submitOptions);
131148
- options.setRegistrationResult(toRegistrationResult(result));
131021
+ async function completeRegistrationSubmission(options, deps, prepared, result, submitOptions) {
131022
+ switch (result.kind) {
131023
+ case "paymentStatusRequired":
131024
+ options.setPaymentStatusRecovery({
131025
+ kind: "ready",
131026
+ subject: result.subject
131027
+ });
131028
+ options.setStep("payment-status");
131029
+ return {
131030
+ ok: true,
131031
+ outcome: { kind: "payment_status" }
131032
+ };
131033
+ case "checkoutRequired":
131034
+ options.setPendingRegistrationReference(result.reference);
131035
+ savePendingCheckout(options, deps, prepared, result.submissionId, result.reference);
131036
+ options.setStep("redirecting");
131037
+ return redirectToCheckout(result.checkoutUrl, submitOptions);
131038
+ case "waitlisted":
131039
+ options.setRegistrationResult({
131040
+ status: "waitlist",
131041
+ title: "Added to waitlist",
131042
+ message: result.waitlist.message
131043
+ });
131044
+ break;
131045
+ case "bookingComplete":
131046
+ case "paymentDeferred":
131047
+ options.setPendingRegistrationReference(result.reference);
131048
+ options.setRegistrationResult({
131049
+ status: "confirmed",
131050
+ message: result.summary.paymentMethod === "pass" ? result.summary.message : void 0
131051
+ });
131052
+ break;
131053
+ }
131054
+ options.commandRef.current = null;
131149
131055
  options.setStep("success");
131150
131056
  return {
131151
131057
  ok: true,
@@ -131176,15 +131082,7 @@ function prepareSubmitContext(options, registrationCommandId, target, method, pa
131176
131082
  email: guest.email?.trim().toLowerCase() || void 0,
131177
131083
  phone: guest.phone?.trim() || void 0
131178
131084
  })) : void 0,
131179
- subject: target.subject.kind === "occurrence" ? {
131180
- kind: "occurrence",
131181
- occurrenceId: target.subject.occurrenceId,
131182
- attendanceMode: options.selectedAttendanceMode ?? void 0
131183
- } : {
131184
- kind: "wholeSeries",
131185
- eventSeriesId: target.subject.eventSeriesId,
131186
- attendanceMode: options.selectedAttendanceMode ?? void 0
131187
- }
131085
+ subject: toRegistrationRequestSubject(target.subject, options.selectedAttendanceMode)
131188
131086
  };
131189
131087
  }
131190
131088
  function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId, selection) {
@@ -131208,85 +131106,6 @@ function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId,
131208
131106
  if (method === "free") return { method };
131209
131107
  throw new Error("Choose an available payment option.");
131210
131108
  }
131211
- async function submitWholeSeriesCheckout(options, deps, prepared, submitOptions) {
131212
- options.setStep("redirecting");
131213
- if (prepared.selectionSnapshot.method !== "stripe") throw new Error("Choose an available payment option.");
131214
- const checkoutAttemptId = deps.createClientCommandId();
131215
- const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
131216
- const result = await options.api.createEventCheckout({
131217
- subject: prepared.subject,
131218
- ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
131219
- selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
131220
- email: options.formData.email.trim().toLowerCase(),
131221
- name: options.formData.name.trim(),
131222
- phone: options.formData.phone.trim() || void 0,
131223
- formData: options.formData,
131224
- consentAccepted: options.formData.consentAccepted,
131225
- altchaSolution: options.altchaSolution,
131226
- guests: prepared.guestsPayload,
131227
- claimToken: options.claimToken ?? void 0,
131228
- waitlistEntryId: options.waitlistEntryId ?? void 0,
131229
- discountCode: options.discountCode.trim() || void 0,
131230
- collectionOptionKind: prepared.selectionSnapshot.collectionOptionKind,
131231
- checkoutAttemptId,
131232
- ...urls
131233
- });
131234
- if (result.scope !== "wholeSeries") throw new Error("Unexpected registration scope for event checkout.");
131235
- if ("waitlistEntryId" in result) {
131236
- options.setRegistrationResult({
131237
- status: "waitlist",
131238
- variant: result.alreadyRegistered ? "info" : void 0,
131239
- title: result.alreadyRegistered ? "Already waitlisted" : "Added to waitlist",
131240
- message: result.alreadyRegistered ? "You are already on the waitlist for this event." : "You've been added to the waitlist."
131241
- });
131242
- options.setStep("success");
131243
- return {
131244
- ok: true,
131245
- outcome: { kind: "completed" }
131246
- };
131247
- }
131248
- if (result.bypassed) return completeBypassedCheckout(options);
131249
- if (!result.checkoutUrl) throw new Error("Checkout URL missing");
131250
- savePendingCheckout(options, deps, prepared, result.checkoutAttemptId, {
131251
- scope: "wholeSeries",
131252
- registrationId: result.registrationId
131253
- });
131254
- return redirectToCheckout(result.checkoutUrl, submitOptions);
131255
- }
131256
- function needsOccurrenceCheckout(result, method) {
131257
- return result.scope === "occurrence" && result.status === "confirmed" && result.pendingPayment && [
131258
- "stripe",
131259
- "pass_bundle",
131260
- "membership_bundle"
131261
- ].includes(method);
131262
- }
131263
- async function submitOccurrenceCheckout(options, deps, prepared, registration, method, submitOptions) {
131264
- const reference = {
131265
- scope: "occurrence",
131266
- attendeeId: registration.attendeeId
131267
- };
131268
- options.setPendingRegistrationReference(reference);
131269
- options.setStep("redirecting");
131270
- const checkoutAttemptId = deps.createClientCommandId();
131271
- const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
131272
- const result = await options.api.createEventCheckout({
131273
- subject: {
131274
- kind: "occurrence",
131275
- attendeeId: registration.attendeeId
131276
- },
131277
- registrationCommandId: prepared.registrationCommandId,
131278
- checkoutType: method === "pass_bundle" ? "pass_bundle" : method === "membership_bundle" ? "membership_bundle" : "event",
131279
- productId: prepared.bundleProductId,
131280
- discountCode: options.discountCode.trim() || void 0,
131281
- collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0,
131282
- ...urls
131283
- });
131284
- if (result.scope !== "occurrence") throw new Error("Unexpected registration scope for event checkout.");
131285
- if (result.bypassed) return completeBypassedCheckout(options);
131286
- if (!result.checkoutUrl) throw new Error("Checkout URL missing");
131287
- if (prepared.subject.kind === "occurrence") savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference);
131288
- return redirectToCheckout(result.checkoutUrl, submitOptions);
131289
- }
131290
131109
  function savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference) {
131291
131110
  const siteId = options.api.config.siteId;
131292
131111
  if (!siteId) return;
@@ -131299,14 +131118,6 @@ function savePendingCheckout(options, deps, prepared, checkoutAttemptId, referen
131299
131118
  paymentSelection: prepared.selectionSnapshot
131300
131119
  });
131301
131120
  }
131302
- function completeBypassedCheckout(options) {
131303
- options.setRegistrationResult({ status: "confirmed" });
131304
- options.setStep("success");
131305
- return {
131306
- ok: true,
131307
- outcome: { kind: "completed" }
131308
- };
131309
- }
131310
131121
  function redirectToCheckout(checkoutUrl, submitOptions) {
131311
131122
  if (submitOptions?.redirect !== "manual") window.location.href = checkoutUrl;
131312
131123
  return {
@@ -131318,12 +131129,23 @@ function redirectToCheckout(checkoutUrl, submitOptions) {
131318
131129
  };
131319
131130
  }
131320
131131
  function registrationRequestIntentKey(request) {
131321
- const { registrationCommandId: _command, altchaSolution: _proof, ...intent } = request;
131322
- return JSON.stringify(intent);
131132
+ const { registrationCommandId: _command, altchaSolution: _proof, checkout, ...intent } = request;
131133
+ return JSON.stringify({
131134
+ ...intent,
131135
+ checkout: checkout ? {
131136
+ discountCode: checkout.discountCode,
131137
+ collectionOptionKind: checkout.collectionOptionKind
131138
+ } : void 0
131139
+ });
131323
131140
  }
131324
- function buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId) {
131141
+ function buildRegistrationRequest(options, prepared, method, passId, membershipId) {
131325
131142
  return {
131326
131143
  registrationCommandId: prepared.registrationCommandId,
131144
+ checkout: {
131145
+ ...buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: prepared.registrationCommandId }),
131146
+ discountCode: options.discountCode.trim() || void 0,
131147
+ collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0
131148
+ },
131327
131149
  subject: prepared.subject,
131328
131150
  ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
131329
131151
  selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
@@ -131541,20 +131363,124 @@ function useWaitlistClaimRestoration(input) {
131541
131363
  }
131542
131364
  //#endregion
131543
131365
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationCompletion.ts
131366
+ function isSelectionSoldOut(availability) {
131367
+ return availability?.kind === "unavailable" && availability.reason === "full";
131368
+ }
131544
131369
  function resolveRegistrationAvailabilityBlocker(input) {
131545
131370
  if (input.hasWaitlistClaim) return null;
131546
131371
  if (input.eligibilityError) return input.eligibilityError;
131547
131372
  if (!input.eligibility) return "Registration is not available for this event.";
131373
+ if (input.eligibility.registration.kind === "pending_payment") return null;
131374
+ if (isSelectionSoldOut(input.eligibility.availability)) return null;
131548
131375
  if (input.eligibility.availability.kind === "unavailable" && input.eligibility.availability.reason === "paymentUnavailable") return "Payment options are not available for this event.";
131549
- if (input.eligibility.availability.kind === "unavailable" || !input.eligibility.eligible) return "Registration is not available for this event.";
131376
+ if (input.eligibility.availability.kind === "unavailable" || input.eligibility.registration.kind === "waitlisted") return "Registration is not available for this event.";
131550
131377
  return null;
131551
131378
  }
131552
131379
  function resolvePricingSelectionBlocker(input) {
131553
131380
  if (input.selectionRequired && !input.hasValidSelection) return "Choose at least one available ticket to continue.";
131554
131381
  return input.slidingScaleSelectionMessage;
131555
131382
  }
131556
- function isSoldOutWithoutWaitlist(input) {
131557
- return Boolean(!input.hasWaitlistClaim && input.eligibility?.isFull && !input.eligibility.canJoinWaitlist);
131383
+ //#endregion
131384
+ //#region ../blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.ts
131385
+ function isCheckableRecovery(state) {
131386
+ return state.kind === "ready" || state.kind === "processing" || state.kind === "temporarilyUnavailable";
131387
+ }
131388
+ function assistanceRequired(recovery) {
131389
+ return {
131390
+ kind: "assistanceRequired",
131391
+ subject: recovery.subject
131392
+ };
131393
+ }
131394
+ function applyStatusOutcome(outcome, recovery, setters, setRecovery) {
131395
+ if (outcome.kind === "resolved") {
131396
+ setters.setPendingRegistrationReference(outcome.reference);
131397
+ setters.setRegistrationResult({ status: "confirmed" });
131398
+ setRecovery(null);
131399
+ setters.setStep("success");
131400
+ return;
131401
+ }
131402
+ switch (outcome.kind) {
131403
+ case "paymentProcessing":
131404
+ setRecovery({
131405
+ ...recovery,
131406
+ kind: "processing"
131407
+ });
131408
+ return;
131409
+ case "paymentAvailable":
131410
+ setRecovery({
131411
+ ...recovery,
131412
+ kind: "paymentAvailable",
131413
+ checkoutUrl: outcome.checkoutUrl
131414
+ });
131415
+ return;
131416
+ case "paymentCheckUnavailable":
131417
+ setRecovery({
131418
+ ...recovery,
131419
+ kind: "temporarilyUnavailable"
131420
+ });
131421
+ return;
131422
+ case "paymentRetryAvailable":
131423
+ setRecovery({
131424
+ ...recovery,
131425
+ kind: "retryAvailable"
131426
+ });
131427
+ return;
131428
+ case "abandoned":
131429
+ case "notFound":
131430
+ case "reconciliationRequired":
131431
+ case "paymentAssistanceRequired":
131432
+ setRecovery(assistanceRequired(recovery));
131433
+ return;
131434
+ }
131435
+ }
131436
+ function usePaymentStatusRecovery(options) {
131437
+ const [recovery, setRecovery] = useState(null);
131438
+ const checkRef = useRef(null);
131439
+ return {
131440
+ recovery,
131441
+ showRecovery: useCallback((next) => setRecovery(next), []),
131442
+ check: useCallback(() => {
131443
+ if (!recovery || !isCheckableRecovery(recovery) || checkRef.current) return;
131444
+ const pending = (async () => {
131445
+ setRecovery({
131446
+ ...recovery,
131447
+ kind: "checking"
131448
+ });
131449
+ try {
131450
+ applyStatusOutcome(await options.api.resolveEventCheckoutReturn({
131451
+ kind: "checkStatus",
131452
+ subject: recovery.subject
131453
+ }), recovery, options, setRecovery);
131454
+ } catch {
131455
+ setRecovery({
131456
+ ...recovery,
131457
+ kind: "temporarilyUnavailable"
131458
+ });
131459
+ }
131460
+ })();
131461
+ checkRef.current = pending;
131462
+ pending.finally(() => {
131463
+ if (checkRef.current === pending) checkRef.current = null;
131464
+ });
131465
+ }, [options, recovery]),
131466
+ continuePayment: useCallback(() => {
131467
+ if (recovery?.kind === "paymentAvailable") window.location.assign(recovery.checkoutUrl);
131468
+ }, [recovery]),
131469
+ returnToPayment: useCallback(() => {
131470
+ if (recovery?.kind !== "retryAvailable") return;
131471
+ options.beginNewSubmission();
131472
+ setRecovery(null);
131473
+ options.setOptionsRefreshKey((value) => value + 1);
131474
+ options.setStep("select-payment");
131475
+ }, [options, recovery]),
131476
+ returnToBooking: useCallback(() => {
131477
+ if (recovery?.kind !== "assistanceRequired") return;
131478
+ options.beginNewSubmission();
131479
+ setRecovery(null);
131480
+ options.setOptionsRefreshKey((value) => value + 1);
131481
+ options.setStep("select-tickets");
131482
+ }, [options, recovery])
131483
+ };
131558
131484
  }
131559
131485
  //#endregion
131560
131486
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
@@ -131612,6 +131538,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
131612
131538
  const [errorAction, setErrorAction] = useState("retry");
131613
131539
  const [optionsRefreshKey, setOptionsRefreshKey] = useState(0);
131614
131540
  const [altchaSolution, setAltchaSolution] = useState(null);
131541
+ const [checkingNextStep, setCheckingNextStep] = useState(false);
131615
131542
  const { authState: portalAuthState, profile: portalProfile } = deps.usePortalAuth();
131616
131543
  const waitlistClaim = deps.useWaitlistClaim();
131617
131544
  const [showMagicLinkModal, setShowMagicLinkModal] = useState(false);
@@ -131638,28 +131565,29 @@ function useEventRegistrationWizardWithDeps(options, deps) {
131638
131565
  }), [options.occurrenceContext, selectedEvent]);
131639
131566
  const registrationOccurrenceId = getRegistrationOccurrenceId(registrationTarget);
131640
131567
  const currentEvent = selectedEvent ?? preSelectedEvent;
131568
+ const commandRef = useRef(null);
131641
131569
  const setStep = useCallback((nextStep) => {
131642
131570
  dispatchFlow({
131643
131571
  type: "set-step",
131644
131572
  step: nextStep
131645
131573
  });
131646
131574
  }, []);
131647
- const { checkoutRecovery, startCheckoutRecovery } = useCheckoutRecovery(currentEvent, setStep);
131648
- const currentEventUsesTicketTypes = usesTieredPricing(currentEvent);
131649
- const currentCanJoinWaitlist = canJoinWaitlistOutsideRecovery(currentEvent, selectedAttendanceMode, checkoutRecovery);
131650
- const usesTicketTypeSelections = currentEventUsesTicketTypes && !currentCanJoinWaitlist;
131575
+ const { recovery: paymentStatusRecovery, showRecovery: setPaymentStatusRecovery, check: handleCheckPaymentStatus, continuePayment: handleContinueExistingPayment, returnToPayment: handleReturnToPayment, returnToBooking: handleReturnToBooking } = usePaymentStatusRecovery({
131576
+ api,
131577
+ beginNewSubmission: () => {
131578
+ commandRef.current = null;
131579
+ },
131580
+ setPendingRegistrationReference,
131581
+ setRegistrationResult,
131582
+ setOptionsRefreshKey,
131583
+ setStep
131584
+ });
131585
+ const usesTicketTypeSelections = usesTieredPricing(currentEvent);
131651
131586
  const eventTicketTypesForSelection = useMemo(() => getVisibleTicketTypes({
131652
131587
  event: currentEvent,
131653
131588
  eligibility: null,
131654
131589
  selectedAttendanceMode
131655
- }).map((option) => checkoutRecovery ? {
131656
- ...option,
131657
- availability: checkoutRecoveryOptionAvailability(option.availability)
131658
- } : option), [
131659
- currentEvent,
131660
- selectedAttendanceMode,
131661
- checkoutRecovery
131662
- ]);
131590
+ }), [currentEvent, selectedAttendanceMode]);
131663
131591
  const normalizedSelectedTicketLines = useMemo(() => normalizeTicketSelectionLines(selectedTicketLines), [selectedTicketLines]);
131664
131592
  const ticketTypeSelectionTotal = useMemo(() => getTicketSelectionTotal(normalizedSelectedTicketLines), [normalizedSelectedTicketLines]);
131665
131593
  const ticketsCount = usesTicketTypeSelections ? ticketTypeSelectionTotal : flowState.ticketsCount;
@@ -131697,7 +131625,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
131697
131625
  isAuthenticated: portalAuthState === "authenticated",
131698
131626
  occurrenceId: registrationOccurrenceId
131699
131627
  });
131700
- const eligibility = useCheckoutRecoveryEligibility(eligibilityResult.eligibility, step, checkoutRecovery, startCheckoutRecovery);
131628
+ const eligibility = eligibilityResult.eligibility;
131701
131629
  const eligibilityLoading = eligibilityResult.isLoading;
131702
131630
  const eligibilityError = eligibilityResult.error;
131703
131631
  const portalCreditState = eligibilityResult.creditState;
@@ -131809,14 +131737,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
131809
131737
  event: currentEvent,
131810
131738
  eligibility,
131811
131739
  selectedAttendanceMode
131812
- }).map((option) => checkoutRecovery ? {
131813
- ...option,
131814
- availability: checkoutRecoveryOptionAvailability(option.availability)
131815
- } : option), [
131740
+ }), [
131816
131741
  currentEvent,
131817
131742
  selectedAttendanceMode,
131818
- eligibility,
131819
- checkoutRecovery
131743
+ eligibility
131820
131744
  ]);
131821
131745
  const singleSelectedPricingOptionId = getSingleSelectedPricingOptionId(normalizedSelectedTicketLines);
131822
131746
  const selectedTicketType = useMemo(() => findSelectedTicketType({
@@ -131840,12 +131764,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
131840
131764
  const event = currentEvent;
131841
131765
  if (!usesTieredPricing(event)) return false;
131842
131766
  if ((event.deliveryMode ?? "in_person") === "hybrid" && !selectedAttendanceMode) return false;
131843
- return checkoutRecovery || !canJoinEventWaitlist(event, { attendanceMode: selectedAttendanceMode });
131844
- }, [
131845
- currentEvent,
131846
- selectedAttendanceMode,
131847
- checkoutRecovery
131848
- ]);
131767
+ return true;
131768
+ }, [currentEvent, selectedAttendanceMode]);
131849
131769
  const hasValidTicketSelection = hasValidPricingOptionSelection({
131850
131770
  selectionRequired: ticketTypeSelectionRequired,
131851
131771
  lines: normalizedSelectedTicketLines,
@@ -131856,8 +131776,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
131856
131776
  if (selectedTicketLines.length > 0) setSelectedTicketLines([]);
131857
131777
  return;
131858
131778
  }
131859
- const availableTicketTypes = eventTicketTypesForSelection.filter((ticketType) => ticketType.availability.kind === "available");
131860
- const implicitTicketType = getImplicitSingleAvailableTicketType(eventTicketTypesForSelection);
131779
+ const availableTicketTypes = eventTicketTypesForSelection.filter((ticketType) => canRequestTicketOption(ticketType.availability));
131780
+ const implicitTicketType = getImplicitSingleTicketType(eventTicketTypesForSelection);
131861
131781
  if (implicitTicketType && normalizedSelectedTicketLines.length === 0) {
131862
131782
  setSelectedTicketLines([{
131863
131783
  pricingOptionId: implicitTicketType.pricingOptionId,
@@ -131924,6 +131844,26 @@ function useEventRegistrationWizardWithDeps(options, deps) {
131924
131844
  selectedEventSlidingScale,
131925
131845
  selectedSlidingAmount
131926
131846
  ]);
131847
+ const checkDetailsNextStep = async () => {
131848
+ if (portalAuthState === "authenticated" || waitlistClaim.claim || eligibility?.availability.kind === "available" || !registrationTarget) return { kind: canRecoverToWaitlist(eligibility) ? "waitlist" : "continue" };
131849
+ setCheckingNextStep(true);
131850
+ try {
131851
+ return await api.checkRegistrationNextStep({
131852
+ subject: toRegistrationRequestSubject(registrationTarget.subject, selectedAttendanceMode),
131853
+ selections: ticketSelections,
131854
+ selectedSlidingAmount: selectedSlidingAmount ?? void 0,
131855
+ email: formData.email,
131856
+ altchaSolution
131857
+ });
131858
+ } catch {
131859
+ return {
131860
+ kind: "unavailable",
131861
+ message: "We could not check availability. Please try again."
131862
+ };
131863
+ } finally {
131864
+ setCheckingNextStep(false);
131865
+ }
131866
+ };
131927
131867
  const handleDetailsComplete = async () => {
131928
131868
  const blockDetailsCompletion = (message) => {
131929
131869
  setErrorAction("places");
@@ -131955,11 +131895,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
131955
131895
  message: "Check the highlighted fields and try again."
131956
131896
  };
131957
131897
  }
131958
- if (isSoldOutWithoutWaitlist({
131959
- hasWaitlistClaim: waitlistClaim.claim !== null,
131960
- eligibility
131961
- })) return blockDetailsCompletion("Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.");
131962
- if (!eligibility?.canJoinWaitlist && requiresPaymentStep({
131898
+ const next = await checkDetailsNextStep();
131899
+ if (next.kind === "unavailable") return blockDetailsCompletion(next.message);
131900
+ const canJoinWaitlist = next.kind === "waitlist";
131901
+ if (!canJoinWaitlist && requiresPaymentStep({
131963
131902
  eventRequiresPayment,
131964
131903
  paymentSelection
131965
131904
  })) {
@@ -131972,7 +131911,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
131972
131911
  const submitPlan = resolveEventRegistrationSubmitPlan({
131973
131912
  paymentSelection,
131974
131913
  eventRequiresPayment,
131975
- canJoinWaitlist: eligibility?.canJoinWaitlist
131914
+ canJoinWaitlist
131976
131915
  });
131977
131916
  if (!submitPlan.ok) return blockDetailsCompletion(submitPlan.message);
131978
131917
  const submitResult = await handleSubmit(submitPlan.args.method, submitPlan.args.passId, submitPlan.args.membershipId, submitPlan.args.selection);
@@ -131990,7 +131929,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
131990
131929
  const submitPlan = resolveEventRegistrationSubmitPlan({
131991
131930
  paymentSelection,
131992
131931
  eventRequiresPayment,
131993
- canJoinWaitlist: eligibility?.canJoinWaitlist
131932
+ canJoinWaitlist: false
131994
131933
  });
131995
131934
  if (!submitPlan.ok) {
131996
131935
  setErrorMessage(submitPlan.message);
@@ -132022,6 +131961,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
132022
131961
  const selectionMethod = paymentSelection.method;
132023
131962
  const shouldShowDiscountToggle = discountContext !== null && discountUi.manualCodeEntryAllowed && (selectionMethod === "stripe" || selectionMethod === "pass_bundle" || selectionMethod === "membership_bundle");
132024
131963
  const handleSubmit = deps.useEventRegistrationSubmit({
131964
+ commandRef,
132025
131965
  setErrorAction,
132026
131966
  api,
132027
131967
  registrationTarget,
@@ -132038,7 +131978,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
132038
131978
  setPendingRegistrationReference,
132039
131979
  setStep,
132040
131980
  setRegistrationResult: (result) => setRegistrationResult(result),
132041
- setErrorMessage
131981
+ setErrorMessage,
131982
+ setPaymentStatusRecovery
132042
131983
  });
132043
131984
  const handleEventSelect = (event) => {
132044
131985
  setSelectedEvent(event);
@@ -132097,8 +132038,6 @@ function useEventRegistrationWizardWithDeps(options, deps) {
132097
132038
  scopedEvents,
132098
132039
  preSelectedEvent,
132099
132040
  hasPreSelectedContext,
132100
- checkoutRecovery,
132101
- startCheckoutRecovery,
132102
132041
  step,
132103
132042
  setStep,
132104
132043
  selectedEvent,
@@ -132152,7 +132091,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
132152
132091
  waitlistClaim,
132153
132092
  eligibility,
132154
132093
  registrationOptionsState: eligibilityResult.state,
132155
- eligibilityLoading,
132094
+ eligibilityLoading: eligibilityLoading || checkingNextStep,
132156
132095
  eligibilityError,
132157
132096
  existingRegistration: existingRegistrationResult.registration,
132158
132097
  existingRegistrationLoading: existingRegistrationResult.isLoading || portalAuthState === "authenticated" && eligibilityLoading,
@@ -132172,6 +132111,11 @@ function useEventRegistrationWizardWithDeps(options, deps) {
132172
132111
  discountContext,
132173
132112
  shouldShowDiscountToggle,
132174
132113
  verification,
132114
+ paymentStatusRecovery,
132115
+ handleCheckPaymentStatus,
132116
+ handleContinueExistingPayment,
132117
+ handleReturnToPayment,
132118
+ handleReturnToBooking,
132175
132119
  handleDetailsComplete,
132176
132120
  handlePaymentSelect,
132177
132121
  handleUseCardInsteadOfPass,
@@ -132343,7 +132287,6 @@ const labels = {
132343
132287
  start: "Start again",
132344
132288
  details: "Check my details",
132345
132289
  "payment-options": "View payment options",
132346
- "payment-status": "Check payment status",
132347
132290
  portal: "View my bookings",
132348
132291
  event: "View event"
132349
132292
  };
@@ -132362,7 +132305,7 @@ const ErrorStep = ({ message, onRetry, action = "retry", canJoinWaitlist = false
132362
132305
  className: "er-text--muted er-message",
132363
132306
  children: offerWaitlist ? "Sorry, this event is now full. You can join the waiting list, and we’ll email you if a place becomes available." : message
132364
132307
  }),
132365
- actions: action === "none" ? void 0 : action === "portal" || action === "payment-status" ? /* @__PURE__ */ jsx("a", {
132308
+ actions: action === "none" ? void 0 : action === "portal" ? /* @__PURE__ */ jsx("a", {
132366
132309
  href: "/portal",
132367
132310
  className: "er-retry-btn",
132368
132311
  children: labels[action]
@@ -132616,8 +132559,11 @@ function EventRegistrationSummaryBar(props) {
132616
132559
  */
132617
132560
  function resolveDetailsButtonText(input) {
132618
132561
  const { wizard } = input;
132619
- if (wizard.eligibility?.canJoinWaitlist) return "Join waitlist";
132620
- if (!input.hasWaitlistClaim && wizard.eligibility?.isFull) return "Sold out";
132562
+ const availability = wizard.eligibility?.availability;
132563
+ const full = availability?.kind === "waitlist" || isSelectionSoldOut(availability);
132564
+ if (wizard.portalAuthState !== "authenticated" && full) return "Continue";
132565
+ if (canRecoverToWaitlist(wizard.eligibility)) return "Join waitlist";
132566
+ if (!input.hasWaitlistClaim && full && wizard.eligibility?.registration.kind !== "pending_payment") return "Sold out";
132621
132567
  if (wizard.paymentSelection.method === "pass") return "Book using class pass";
132622
132568
  if (wizard.paymentSelection.method === "membership") return input.fallbackText;
132623
132569
  return wizard.eventRequiresPayment ? "Continue to payment" : input.fallbackText;
@@ -132632,44 +132578,28 @@ function isExistingRegistrationBlocking$1(wizard) {
132632
132578
  hasWaitlistClaim: wizard.waitlistClaim.claim !== null
132633
132579
  });
132634
132580
  }
132635
- /**
132636
- * Full for the visitor's selected attendance mode (or the whole event when no
132637
- * mode is chosen) with no waitlist to fall back on. Reads the same capacity
132638
- * source as the steps above the action bar so the button never disagrees
132639
- * with them on a hybrid event.
132640
- */
132641
- function isFullWithNoWaitlist(event, attendanceMode) {
132642
- if (!event) return false;
132643
- const source = selectEventCapacitySource(event, attendanceMode);
132644
- return getEventAvailability(source).isFull && !source.waitlistEnabled;
132645
- }
132646
132581
  function resolveTicketSelectionContinueLabel(input) {
132647
132582
  if (input.isCheckingExistingRegistration) return "Checking registration...";
132648
132583
  if (input.registrationOptionsPending) return "Checking availability...";
132649
132584
  if (input.registrationOptionsFailed) return "Availability unavailable";
132650
132585
  if (input.hasExistingRegistration) return resolveExistingRegistrationLabel(input.wizard);
132651
- if (input.isSoldOutWithoutWaitlist) return "Sold out";
132652
132586
  if (input.ticketTypeSelectionBlocked) return "Choose a ticket";
132653
132587
  return "Continue";
132654
132588
  }
132655
132589
  function SelectTicketsActions(props) {
132656
132590
  const { wizard } = props;
132657
- const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
132658
- const currentEvent = wizard.selectedEvent ?? wizard.preSelectedEvent;
132659
132591
  const registrationOptionsPending = wizard.registrationOptionsState.tag === "idle" || wizard.registrationOptionsState.tag === "loading";
132660
132592
  const registrationOptionsFailed = wizard.registrationOptionsState.tag === "failed";
132661
- const isSoldOutWithoutWaitlist = !wizard.checkoutRecovery && !hasWaitlistClaim && isFullWithNoWaitlist(currentEvent, wizard.selectedAttendanceMode);
132662
132593
  const isCheckingExistingRegistration = wizard.portalAuthState === "authenticated" && wizard.existingRegistrationLoading;
132663
132594
  const hasExistingRegistration = isExistingRegistrationBlocking$1(wizard);
132664
132595
  const ticketTypeSelectionBlocked = wizard.ticketTypeSelectionRequired && !wizard.hasValidTicketSelection;
132665
- const isContinueDisabled = registrationOptionsPending || registrationOptionsFailed || isCheckingExistingRegistration || hasExistingRegistration || isSoldOutWithoutWaitlist || ticketTypeSelectionBlocked;
132596
+ const isContinueDisabled = registrationOptionsPending || registrationOptionsFailed || isCheckingExistingRegistration || hasExistingRegistration || ticketTypeSelectionBlocked;
132666
132597
  const continueLabel = resolveTicketSelectionContinueLabel({
132667
132598
  wizard,
132668
132599
  registrationOptionsPending,
132669
132600
  registrationOptionsFailed,
132670
132601
  isCheckingExistingRegistration,
132671
132602
  hasExistingRegistration,
132672
- isSoldOutWithoutWaitlist,
132673
132603
  ticketTypeSelectionBlocked
132674
132604
  });
132675
132605
  return /* @__PURE__ */ jsxs("div", {
@@ -132700,8 +132630,12 @@ function EnterDetailsActions(props) {
132700
132630
  const { wizard } = props;
132701
132631
  const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
132702
132632
  const isCheckingEligibility = wizard.eligibilityLoading;
132703
- const eligibilityUnavailable = !hasWaitlistClaim && (Boolean(wizard.eligibilityError) || !wizard.eligibility || wizard.eligibility.availability.kind === "unavailable" || !wizard.eligibility.eligible);
132704
- const isSoldOut = !hasWaitlistClaim && wizard.eligibility?.isFull === true && wizard.eligibility.canJoinWaitlist !== true;
132633
+ const eligibilityUnavailable = Boolean(resolveRegistrationAvailabilityBlocker({
132634
+ hasWaitlistClaim,
132635
+ eligibility: wizard.eligibility,
132636
+ eligibilityError: wizard.eligibilityError
132637
+ }));
132638
+ const isSoldOut = !hasWaitlistClaim && wizard.portalAuthState === "authenticated" && wizard.eligibility?.registration.kind !== "pending_payment" && isSelectionSoldOut(wizard.eligibility?.availability);
132705
132639
  const isContinueDisabled = isCheckingEligibility || eligibilityUnavailable || isSoldOut;
132706
132640
  const continueLabel = isCheckingEligibility ? "Checking availability..." : wizard.eligibilityError ? "Availability unavailable" : eligibilityUnavailable ? "Registration unavailable" : resolveDetailsButtonText({
132707
132641
  wizard,
@@ -132752,6 +132686,7 @@ function EventRegistrationWizardActions(props) {
132752
132686
  case "redirecting":
132753
132687
  case "verifying-payment":
132754
132688
  case "verifying-timeout":
132689
+ case "payment-status":
132755
132690
  case "payment-failed": return null;
132756
132691
  case "select-event": return null;
132757
132692
  case "select-tickets": return /* @__PURE__ */ jsx(SelectTicketsActions, { ...props });
@@ -132836,7 +132771,7 @@ function buildSelectedSiteCreditPreview(input) {
132836
132771
  function resolvePaymentStepStatus(input) {
132837
132772
  if (input.loading) return "loading";
132838
132773
  if (input.error || !input.eligibility) return "error";
132839
- if (input.eligibility.registration.kind !== "none" || !input.eligibility.eligible && !input.eligibility.isFree) return "not-eligible";
132774
+ if (input.eligibility.registration.kind === "waitlisted" || input.eligibility.paymentOptions.length === 0) return "not-eligible";
132840
132775
  return "ready";
132841
132776
  }
132842
132777
  function shouldPromptForLogin(status, isAuthenticated, eligibility) {
@@ -132871,7 +132806,7 @@ function UnavailableEntitlementMessage(props) {
132871
132806
  ] });
132872
132807
  }
132873
132808
  function IneligiblePaymentPanel(props) {
132874
- if (props.eligibility.isFull && !props.eligibility.canJoinWaitlist) return /* @__PURE__ */ jsxs("div", {
132809
+ if (isSelectionSoldOut(props.eligibility.availability)) return /* @__PURE__ */ jsxs("div", {
132875
132810
  className: "rb-reg-stack er-stack",
132876
132811
  children: [/* @__PURE__ */ jsx("h3", {
132877
132812
  className: "er-title",
@@ -132940,26 +132875,23 @@ function PaymentBlockingPanel(props) {
132940
132875
  })
132941
132876
  });
132942
132877
  if (!props.eligibility) return /* @__PURE__ */ jsx(MissingEligibilityPanel, {});
132943
- if (props.eligibility.registration.kind !== "none") {
132944
- const isBooked = props.eligibility.registration.kind === "booked";
132945
- return /* @__PURE__ */ jsxs("div", {
132946
- className: "rb-reg-stack er-stack",
132947
- children: [/* @__PURE__ */ jsx("h3", {
132948
- className: "er-title",
132949
- children: isBooked ? "Already booked" : "Already on the waitlist"
132950
- }), /* @__PURE__ */ jsxs("div", {
132951
- className: "er-center",
132952
- children: [/* @__PURE__ */ jsx("p", {
132953
- className: "er-text er-text--muted",
132954
- children: isBooked ? "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser." : "You're already on the waitlist for this event."
132955
- }), /* @__PURE__ */ jsx("a", {
132956
- href: "/portal",
132957
- className: "er-retry-btn",
132958
- children: "View my bookings"
132959
- })]
132878
+ if (props.eligibility.registration.kind === "waitlisted") return /* @__PURE__ */ jsxs("div", {
132879
+ className: "rb-reg-stack er-stack",
132880
+ children: [/* @__PURE__ */ jsx("h3", {
132881
+ className: "er-title",
132882
+ children: "Already on the waitlist"
132883
+ }), /* @__PURE__ */ jsxs("div", {
132884
+ className: "er-center",
132885
+ children: [/* @__PURE__ */ jsx("p", {
132886
+ className: "er-text er-text--muted",
132887
+ children: "You're already on the waitlist for this event."
132888
+ }), /* @__PURE__ */ jsx("a", {
132889
+ href: "/portal",
132890
+ className: "er-retry-btn",
132891
+ children: "View my bookings"
132960
132892
  })]
132961
- });
132962
- }
132893
+ })]
132894
+ });
132963
132895
  if (props.eligibility.isFree) return /* @__PURE__ */ jsxs("div", {
132964
132896
  className: "rb-reg-stack er-stack",
132965
132897
  children: [/* @__PURE__ */ jsx("h3", {
@@ -132980,7 +132912,7 @@ function PaymentBlockingPanel(props) {
132980
132912
  })]
132981
132913
  })]
132982
132914
  });
132983
- return props.eligibility.eligible ? null : /* @__PURE__ */ jsx(IneligiblePaymentPanel, {
132915
+ return props.eligibility.paymentOptions.length > 0 ? null : /* @__PURE__ */ jsx(IneligiblePaymentPanel, {
132984
132916
  eligibility: props.eligibility,
132985
132917
  email: props.email,
132986
132918
  isAuthenticated: props.isAuthenticated,
@@ -133112,7 +133044,7 @@ function SlidingScaleAmountField(props) {
133112
133044
  }
133113
133045
  function TicketTypeQuantityRows(props) {
133114
133046
  const totalSelectedQuantity = getTicketSelectionTotal(props.ticketSelections);
133115
- const effectiveMaxTickets = props.availableSpots == null ? props.maxTickets : Math.min(props.maxTickets, props.availableSpots);
133047
+ const effectiveMaxTickets = props.maxTickets;
133116
133048
  return /* @__PURE__ */ jsxs("div", {
133117
133049
  className: "er-ticket-lines",
133118
133050
  children: [
@@ -133122,16 +133054,14 @@ function TicketTypeQuantityRows(props) {
133122
133054
  "aria-label": props.bookingUnit === "place" ? "Places" : "Tickets",
133123
133055
  children: props.ticketTypes.map((ticketType) => {
133124
133056
  const quantity = getTicketLineQuantity(props.ticketSelections, ticketType.pricingOptionId);
133125
- const disabled = ticketType.availability.kind === "unavailable";
133057
+ const disabled = !canRequestTicketOption(ticketType.availability);
133126
133058
  const availabilityLabel = getTicketTypeAvailabilityLabel(ticketType);
133127
133059
  const ticketTypeRemainingLabel = formatTicketTypeRemaining(ticketType.availability.remainingPlaces);
133128
133060
  const priceLabel = ticketType.priceAmount > 0 ? formatPrice(ticketType.priceAmount, props.currency) : "Free";
133129
133061
  const maxAllowed = disabled ? 0 : getTicketTypeLineMax({
133130
133062
  currentQuantity: quantity,
133131
133063
  totalSelectedQuantity,
133132
- maxTickets: props.maxTickets,
133133
- availableSpots: props.availableSpots,
133134
- ticketTypeRemainingCapacity: ticketType.availability.remainingPlaces
133064
+ maxTickets: props.maxTickets
133135
133065
  });
133136
133066
  return /* @__PURE__ */ jsxs("div", {
133137
133067
  className: `er-ticket-line${disabled ? " er-ticket-line--disabled" : ""}`,
@@ -133236,33 +133166,13 @@ function AttendanceModeTiles(props) {
133236
133166
  })
133237
133167
  });
133238
133168
  }
133239
- function getMaxAllowedTicketCount(input) {
133240
- if (input.canJoinWaitlist) return input.maxTickets;
133241
- if (!input.usesTicketTypes) return Math.min(input.maxTickets, input.availableSpots ?? input.maxTickets);
133242
- if (!input.hasSelectedTicketType) return 1;
133243
- return Math.max(1, Math.min(input.maxTickets, input.selectedTicketTypeRemainingCapacity ?? input.maxTickets, input.availableSpots ?? input.maxTickets));
133244
- }
133245
133169
  function resolveTicketSelectionPricing(event) {
133246
133170
  return {
133247
133171
  mode: event ? publicEventPricingStrategy(event.pricing) : void 0,
133248
133172
  currency: event ? publicEventPricingCurrency(event.pricing) : null
133249
133173
  };
133250
133174
  }
133251
- function CheckoutRecoveryEntry(props) {
133252
- return props.onContinue ? /* @__PURE__ */ jsx("button", {
133253
- type: "button",
133254
- className: "er-back-btn",
133255
- onClick: props.onContinue,
133256
- children: "Continue an existing booking"
133257
- }) : null;
133258
- }
133259
- function getTicketSelectionCapacity(event, attendanceMode, checkoutRecovery) {
133260
- if (checkoutRecovery) return {
133261
- availableSpots: null,
133262
- isSoldOut: false,
133263
- canJoinWaitlist: false,
133264
- eventAvailabilityLabel: null
133265
- };
133175
+ function getTicketSelectionCapacity(event, attendanceMode) {
133266
133176
  const source = event ? selectEventCapacitySource(event, attendanceMode) : null;
133267
133177
  const availability = source ? getEventAvailability(source) : null;
133268
133178
  const canJoinWaitlist = source ? canJoinEventWaitlist(source) : false;
@@ -133281,29 +133191,21 @@ function getTicketSelectionCapacity(event, attendanceMode, checkoutRecovery) {
133281
133191
  *
133282
133192
  * Can use either a full PublicEvent or just occurrence context (when on event page).
133283
133193
  */
133284
- const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, selectedAttendanceMode = null, onAttendanceModeChange, ticketsCount, maxTickets, visibleTicketTypes: visibleTicketTypesOverride, ticketSelections = [], onTicketSelectionsChange, slidingScale = null, selectedSlidingAmountInput = "", slidingScaleSelectionMessage = null, onSlidingAmountChange, onTicketsChange, bookingUnit = { kind: "ticket" }, checkoutRecovery = false, onCheckoutRecovery }) => {
133194
+ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, selectedAttendanceMode = null, onAttendanceModeChange, ticketsCount, maxTickets, visibleTicketTypes: visibleTicketTypesOverride, ticketSelections = [], onTicketSelectionsChange, slidingScale = null, selectedSlidingAmountInput = "", slidingScaleSelectionMessage = null, onSlidingAmountChange, onTicketsChange, bookingUnit = { kind: "ticket" } }) => {
133285
133195
  const unit = bookingUnit.kind;
133286
133196
  const deliveryMode = event?.deliveryMode ?? "in_person";
133287
133197
  const attendanceModes = event?.attendanceModes ?? [];
133288
- const { availableSpots, isSoldOut, canJoinWaitlist, eventAvailabilityLabel } = getTicketSelectionCapacity(event, selectedAttendanceMode, checkoutRecovery);
133198
+ const { availableSpots, isSoldOut, canJoinWaitlist, eventAvailabilityLabel } = getTicketSelectionCapacity(event, selectedAttendanceMode);
133289
133199
  const { mode: eventPricingMode, currency: eventPricingCurrency } = resolveTicketSelectionPricing(event);
133290
- const usesTicketTypes = eventPricingMode === "tiered" && !canJoinWaitlist;
133200
+ const usesTicketTypes = eventPricingMode === "tiered";
133291
133201
  const visibleTicketTypes = usesTicketTypes ? visibleTicketTypesOverride ?? getVisibleTicketTypes({
133292
133202
  event,
133293
133203
  eligibility: null,
133294
133204
  selectedAttendanceMode
133295
133205
  }) : [];
133296
- const implicitTicketType = usesTicketTypes ? getImplicitSingleAvailableTicketType(visibleTicketTypes) : null;
133297
133206
  const noVisibleTicketTypes = usesTicketTypes && visibleTicketTypes.length === 0;
133298
- const hasAvailableTicketTypes = usesTicketTypes && visibleTicketTypes.some((ticketType) => ticketType.availability.kind === "available");
133299
- const maxAllowed = getMaxAllowedTicketCount({
133300
- canJoinWaitlist,
133301
- usesTicketTypes,
133302
- maxTickets,
133303
- availableSpots,
133304
- selectedTicketTypeRemainingCapacity: implicitTicketType?.availability.remainingPlaces ?? null,
133305
- hasSelectedTicketType: implicitTicketType !== null
133306
- });
133207
+ const hasAvailableTicketTypes = usesTicketTypes && visibleTicketTypes.some((ticketType) => canRequestTicketOption(ticketType.availability));
133208
+ const maxAllowed = maxTickets;
133307
133209
  if (deliveryMode === "hybrid" && !selectedAttendanceMode) return /* @__PURE__ */ jsxs("div", {
133308
133210
  className: "rb-reg-stack er-stack",
133309
133211
  children: [
@@ -133322,20 +133224,6 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
133322
133224
  })
133323
133225
  ]
133324
133226
  });
133325
- if (isSoldOut && !canJoinWaitlist) return /* @__PURE__ */ jsxs("div", {
133326
- className: "rb-reg-stack er-stack",
133327
- children: [
133328
- /* @__PURE__ */ jsx("h3", {
133329
- className: "er-title",
133330
- children: "Sold out"
133331
- }),
133332
- /* @__PURE__ */ jsx("p", {
133333
- className: "er-text er-text--muted",
133334
- children: "Sorry you missed out! This event is fully booked."
133335
- }),
133336
- /* @__PURE__ */ jsx(CheckoutRecoveryEntry, { onContinue: onCheckoutRecovery })
133337
- ]
133338
- });
133339
133227
  if (!eventPricingCurrency) return /* @__PURE__ */ jsx("div", {
133340
133228
  className: "rb-reg-stack er-stack",
133341
133229
  children: /* @__PURE__ */ jsx("p", {
@@ -133402,14 +133290,14 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
133402
133290
  })]
133403
133291
  })
133404
133292
  ] }),
133405
- canJoinWaitlist && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("p", {
133293
+ isSoldOut && !canJoinWaitlist && /* @__PURE__ */ jsx("p", {
133406
133294
  className: "er-text er-text--muted",
133407
- children: "This event is currently full. Continue to join the waitlist if a place opens up."
133408
- }), /* @__PURE__ */ jsx(CheckoutRecoveryEntry, { onContinue: onCheckoutRecovery })] }),
133409
- checkoutRecovery && /* @__PURE__ */ jsx("p", {
133295
+ children: "This event is fully booked."
133296
+ }),
133297
+ canJoinWaitlist && /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx("p", {
133410
133298
  className: "er-text er-text--muted",
133411
- children: "Enter the details from your earlier booking. We’ll check your checkout before continuing to payment."
133412
- })
133299
+ children: "This event is currently full. Continue to join the waitlist if a place opens up."
133300
+ }) })
133413
133301
  ]
133414
133302
  });
133415
133303
  };
@@ -134004,7 +133892,7 @@ const PaymentSelectionStep = ({ event, occurrenceContext, ticketsCount, email, i
134004
133892
  const occurrenceId = occurrenceContext?.id ?? (event?.registrationSubject.kind === "occurrence" ? event.registrationSubject.occurrenceId : "");
134005
133893
  const selectedMethod = selectedSelection.method;
134006
133894
  const totalPrice = directPaymentTotalCents;
134007
- const canShowDirectPaymentOptions = Boolean(eligibility?.eligible && eligibility.canPayDirectly && eligibility.price);
133895
+ const canShowDirectPaymentOptions = Boolean(eligibility?.requiresPayment && eligibility.price);
134008
133896
  const directPaymentOptions = eligibility && canShowDirectPaymentOptions ? buildEventRegistrationPaymentOptionsViewModel({
134009
133897
  eventTitle: event?.title ?? "Event",
134010
133898
  approvedPaymentOptions: eligibility.paymentOptions,
@@ -134067,7 +133955,7 @@ const PaymentSelectionStep = ({ event, occurrenceContext, ticketsCount, email, i
134067
133955
  onRequestLogin
134068
133956
  });
134069
133957
  if (eligibilityLoading || eligibilityError || !eligibility) return blockingPanel;
134070
- if (eligibility.isFree || !eligibility.eligible) return blockingPanel;
133958
+ if (eligibility.isFree || paymentStepStatus !== "ready") return blockingPanel;
134071
133959
  const isMultiTicket = areEntitlementsDisabledForTicketCount(ticketsCount);
134072
133960
  return /* @__PURE__ */ jsxs("div", {
134073
133961
  className: "rb-reg-stack er-stack",
@@ -134301,6 +134189,7 @@ function EventRegistrationWizardContent(props) {
134301
134189
  case "redirecting":
134302
134190
  case "verifying-payment":
134303
134191
  case "verifying-timeout":
134192
+ case "payment-status":
134304
134193
  case "payment-failed": return null;
134305
134194
  case "select-event": return /* @__PURE__ */ jsx(EventSelectionStep, {
134306
134195
  events: wizard.scopedEvents,
@@ -134316,8 +134205,6 @@ function EventRegistrationWizardContent(props) {
134316
134205
  onBookForSomeoneElse: wizard.handleBookForSomeoneElse
134317
134206
  }), /* @__PURE__ */ jsx(TicketSelectionStep, {
134318
134207
  event: wizard.selectedEvent,
134319
- checkoutRecovery: wizard.checkoutRecovery,
134320
- onCheckoutRecovery: canRecoverEventCheckout(wizard.selectedEvent) ? wizard.startCheckoutRecovery : void 0,
134321
134208
  occurrenceContext: wizard.occurrenceContext,
134322
134209
  selectedAttendanceMode: wizard.selectedAttendanceMode,
134323
134210
  onAttendanceModeChange: wizard.setSelectedAttendanceMode,
@@ -134372,6 +134259,81 @@ const PaymentFailedStep = ({ onRetry }) => {
134372
134259
  });
134373
134260
  };
134374
134261
  //#endregion
134262
+ //#region ../blocks/src/system/runtime/nodes/event-registration/PaymentStatusStep.tsx
134263
+ function presentation(state) {
134264
+ switch (state.kind) {
134265
+ case "ready": return {
134266
+ title: "We haven’t confirmed your payment yet",
134267
+ message: "We’ve saved your booking details, but we haven’t been able to confirm that your payment was successful. Please don’t make another payment. Select Check payment status to get the latest update.",
134268
+ action: { label: "Check payment status" }
134269
+ };
134270
+ case "checking": return {
134271
+ title: "We haven’t confirmed your payment yet",
134272
+ message: "We’ve saved your booking details, but we haven’t been able to confirm that your payment was successful. Please don’t make another payment.",
134273
+ action: {
134274
+ label: "Checking payment…",
134275
+ disabled: true
134276
+ }
134277
+ };
134278
+ case "processing": return {
134279
+ title: "Your payment is still being processed",
134280
+ message: "Please don’t make another payment. You can check its status again in a moment.",
134281
+ action: { label: "Check payment status" }
134282
+ };
134283
+ case "paymentAvailable": return {
134284
+ title: "Your payment hasn’t been completed",
134285
+ message: "Your booking details are still saved. Continue to payment to finish your booking.",
134286
+ action: { label: "Continue to payment" }
134287
+ };
134288
+ case "retryAvailable": return {
134289
+ title: "Continue your booking",
134290
+ message: "You can return to payment. We’ll check your booking, any existing payment and availability before starting another checkout.",
134291
+ action: { label: "Return to payment" }
134292
+ };
134293
+ case "temporarilyUnavailable": return {
134294
+ title: "We couldn’t check your payment",
134295
+ message: "Please don’t make another payment yet. Try checking again in a moment.",
134296
+ action: { label: "Check payment status" }
134297
+ };
134298
+ case "assistanceRequired": return {
134299
+ title: "We still can’t confirm your payment",
134300
+ message: "Please don’t make another payment. Contact the organiser so they can check your booking.",
134301
+ action: { label: "Return to booking" }
134302
+ };
134303
+ }
134304
+ }
134305
+ function PaymentStatusStep(props) {
134306
+ const view = presentation(props.state);
134307
+ const onClick = props.state.kind === "paymentAvailable" ? props.onContinuePayment : props.state.kind === "retryAvailable" ? props.onReturnToPayment : props.state.kind === "assistanceRequired" ? props.onReturnToBooking : props.onCheck;
134308
+ return /* @__PURE__ */ jsx(TerminalPanel, {
134309
+ tone: "warning",
134310
+ className: "er-center",
134311
+ titleClassName: "er-title--lg er-message",
134312
+ icon: /* @__PURE__ */ jsx(StateIcon, {
134313
+ variant: "warning",
134314
+ children: /* @__PURE__ */ jsx(ClockIcon, {})
134315
+ }),
134316
+ title: view.title,
134317
+ body: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("p", {
134318
+ className: "er-text--muted er-message",
134319
+ children: view.message
134320
+ }), /* @__PURE__ */ jsx("span", {
134321
+ className: "rb-sr-only",
134322
+ "aria-live": "polite",
134323
+ "aria-atomic": "true",
134324
+ children: props.state.kind === "checking" ? "Checking payment…" : view.title
134325
+ })] }),
134326
+ actionsClassName: "er-button-group",
134327
+ actions: view.action ? /* @__PURE__ */ jsx("button", {
134328
+ type: "button",
134329
+ onClick,
134330
+ disabled: view.action.disabled,
134331
+ className: "er-btn er-btn--primary",
134332
+ children: /* @__PURE__ */ jsx("span", { children: view.action.label })
134333
+ }) : void 0
134334
+ });
134335
+ }
134336
+ //#endregion
134375
134337
  //#region ../blocks/src/system/runtime/nodes/event-registration/StepIndicator.tsx
134376
134338
  /**
134377
134339
  * Step indicator component for the event registration wizard.
@@ -134489,7 +134451,7 @@ const VerifyingTimeoutStep = ({ onCheckAgain, supportEmail, title = "We’re che
134489
134451
  title,
134490
134452
  body: /* @__PURE__ */ jsx("p", {
134491
134453
  className: "er-text--muted er-message",
134492
- children: message
134454
+ children: onCheckAgain ? message : "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking."
134493
134455
  }),
134494
134456
  actionsClassName: "er-button-group",
134495
134457
  actions: onCheckAgain ? /* @__PURE__ */ jsx("button", {
@@ -134497,11 +134459,7 @@ const VerifyingTimeoutStep = ({ onCheckAgain, supportEmail, title = "We’re che
134497
134459
  onClick: onCheckAgain,
134498
134460
  className: "er-btn er-btn--primary",
134499
134461
  children: "Check payment status"
134500
- }) : /* @__PURE__ */ jsx("a", {
134501
- href: "/portal",
134502
- className: "er-btn er-btn--primary",
134503
- children: "Check payment status"
134504
- }),
134462
+ }) : void 0,
134505
134463
  secondaryBody: supportEmail ? /* @__PURE__ */ jsxs("p", {
134506
134464
  className: "er-text--sm er-text--muted er-message",
134507
134465
  children: [
@@ -134602,6 +134560,13 @@ function EventRegistrationTerminalState(props) {
134602
134560
  message: wizard.verification.status === "timeout" ? void 0 : wizard.errorMessage,
134603
134561
  supportEmail: props.supportEmail
134604
134562
  });
134563
+ case "payment-status": return wizard.paymentStatusRecovery ? /* @__PURE__ */ jsx(PaymentStatusStep, {
134564
+ state: wizard.paymentStatusRecovery,
134565
+ onCheck: wizard.handleCheckPaymentStatus,
134566
+ onContinuePayment: wizard.handleContinueExistingPayment,
134567
+ onReturnToPayment: wizard.handleReturnToPayment,
134568
+ onReturnToBooking: wizard.handleReturnToBooking
134569
+ }) : null;
134605
134570
  case "success": return wizard.registrationResult ? /* @__PURE__ */ jsx(SuccessStep, {
134606
134571
  title: wizard.registrationResult.title,
134607
134572
  variant: wizard.registrationResult.variant,
@@ -134610,7 +134575,7 @@ function EventRegistrationTerminalState(props) {
134610
134575
  case "error": return /* @__PURE__ */ jsx(ErrorStep, {
134611
134576
  message: wizard.errorMessage,
134612
134577
  action: wizard.errorAction,
134613
- canJoinWaitlist: wizard.eligibility?.isFull && wizard.eligibility.canJoinWaitlist,
134578
+ canJoinWaitlist: wizard.eligibility?.availability.kind === "waitlist" && wizard.eligibility.registration.kind !== "pending_payment",
134614
134579
  onRetry: wizard.handleRetry
134615
134580
  });
134616
134581
  case "select-event":
@@ -134905,6 +134870,7 @@ function getWizardStepLabel(input) {
134905
134870
  case "redirecting":
134906
134871
  case "verifying-payment":
134907
134872
  case "verifying-timeout":
134873
+ case "payment-status":
134908
134874
  case "payment-failed": return "";
134909
134875
  }
134910
134876
  }