@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
@@ -9612,6 +9612,10 @@ var init_endpoints = __esmMin((() => {
9612
9612
  method: "POST",
9613
9613
  authScope: "portal"
9614
9614
  },
9615
+ registrationNextStep: {
9616
+ path: "/public/sites/{siteId}/events/registration-next-step",
9617
+ method: "POST"
9618
+ },
9615
9619
  registrationStatus: {
9616
9620
  path: "/public/sites/{siteId}/events/registration-status",
9617
9621
  method: "GET"
@@ -10194,6 +10198,13 @@ function createBlockApi(config) {
10194
10198
  body: data
10195
10199
  });
10196
10200
  },
10201
+ async checkRegistrationNextStep(data) {
10202
+ const path = buildPath(EVENTS.registrationNextStep.path, { siteId: requireSiteId() });
10203
+ return request(EVENTS.registrationNextStep, {
10204
+ path,
10205
+ body: data
10206
+ });
10207
+ },
10197
10208
  async getEventRegistrationStatus(params) {
10198
10209
  const sid = requireSiteId();
10199
10210
  const path = buildPath(EVENTS.registrationStatus.path, { siteId: sid });
@@ -33622,6 +33633,18 @@ var init_wizardSteps$1 = __esmMin((() => {
33622
33633
  }));
33623
33634
  //#endregion
33624
33635
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
33636
+ /** Public requests share subject identity without copying the run's display sessions. */
33637
+ function toRegistrationRequestSubject(subject, attendanceMode) {
33638
+ return subject.kind === "occurrence" ? {
33639
+ kind: "occurrence",
33640
+ occurrenceId: subject.occurrenceId,
33641
+ attendanceMode: attendanceMode ?? void 0
33642
+ } : {
33643
+ kind: "wholeSeries",
33644
+ eventSeriesId: subject.eventSeriesId,
33645
+ attendanceMode: attendanceMode ?? void 0
33646
+ };
33647
+ }
33625
33648
  function eventMatchesOccurrenceId(event, occurrenceId) {
33626
33649
  return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
33627
33650
  }
@@ -33851,6 +33874,7 @@ function shellLabelForRegistrationStep(step, events) {
33851
33874
  case "redirecting":
33852
33875
  case "verifying-payment":
33853
33876
  case "verifying-timeout":
33877
+ case "payment-status":
33854
33878
  case "payment-failed": return "Details";
33855
33879
  }
33856
33880
  }
@@ -46823,7 +46847,7 @@ var init_eventPaymentOptions = __esmMin((() => {
46823
46847
  //#endregion
46824
46848
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationStateMachine.ts
46825
46849
  function hasBlockingExistingRegistration(input) {
46826
- return !input.hasWaitlistClaim && input.isAuthenticated && input.registration.kind !== "none";
46850
+ return !input.hasWaitlistClaim && input.isAuthenticated && input.registration.kind === "waitlisted";
46827
46851
  }
46828
46852
  function createInitialRegistrationFlowState(hasPreSelectedContext) {
46829
46853
  return {
@@ -46875,7 +46899,7 @@ function computeAutoSelection(input) {
46875
46899
  return { method: null };
46876
46900
  }
46877
46901
  function computeDirectPaymentSelection(eligibility) {
46878
- if (!eligibility?.canPayDirectly) return { method: null };
46902
+ if (!eligibility?.requiresPayment) return { method: null };
46879
46903
  const approvedKinds = getApprovedDirectPaymentCollectionOptionKinds(eligibility.paymentOptions);
46880
46904
  const collectionOptionKind = approvedKinds.includes("upfront") ? "upfront" : approvedKinds[0];
46881
46905
  return collectionOptionKind ? {
@@ -46889,7 +46913,7 @@ function isSelectionValid(input) {
46889
46913
  if (!eligibility) return selection.method === "stripe" || selection.method === "pass_bundle" || selection.method === "membership_bundle";
46890
46914
  switch (selection.method) {
46891
46915
  case "free": return eligibility.isFree;
46892
- case "stripe": return Boolean(eligibility.canPayDirectly && eligibility.price);
46916
+ case "stripe": return Boolean(eligibility.requiresPayment && eligibility.price);
46893
46917
  case "pass": return isAuthenticated && ticketsCount === 1 && !!selection.passId && eligibility.eligiblePasses.some((pass) => pass.id === selection.passId);
46894
46918
  case "membership": return isAuthenticated && ticketsCount === 1 && !!selection.membershipId && eligibility.eligibleMemberships.some((membership) => membership.id === selection.membershipId);
46895
46919
  case "pass_bundle": return ticketsCount === 1 && !!selection.bundlePassId && eligibility.availablePasses.some((pass) => pass.id === selection.bundlePassId);
@@ -46908,7 +46932,7 @@ function normalizeRegistrationFlowState(state) {
46908
46932
  ticketsCount: state.ticketsCount,
46909
46933
  passOptOut: nextPassOptOut
46910
46934
  });
46911
- const canKeepManualSelection = state.step === "select-payment" && state.selectionSource === "manual" && isSelectionValid({
46935
+ const canKeepManualSelection = state.step !== "select-tickets" && state.selectionSource === "manual" && isSelectionValid({
46912
46936
  selection: state.paymentSelection,
46913
46937
  isAuthenticated: state.isAuthenticated,
46914
46938
  eligibility: state.eligibility,
@@ -47000,7 +47024,7 @@ function resolveEventRegistrationSubmitPlan(input) {
47000
47024
  const selection = input.paymentSelection.method ? input.paymentSelection : void 0;
47001
47025
  if (input.canJoinWaitlist) return {
47002
47026
  ok: true,
47003
- args: withOptionalSelection({ method: "free" }, selection)
47027
+ args: { method: "free" }
47004
47028
  };
47005
47029
  switch (input.paymentSelection.method) {
47006
47030
  case "pass": return input.paymentSelection.passId ? {
@@ -47069,92 +47093,55 @@ var init_event_registration_headless_state = __esmMin((() => {
47069
47093
  init_event_registration_headless_planning();
47070
47094
  }));
47071
47095
  //#endregion
47072
- //#region ../blocks/src/system/runtime/nodes/event-registration/checkoutRecovery.ts
47073
- /** Recovery may select held places; checkout still owns admission and payment validation. */
47074
- function checkoutRecoveryOptionAvailability(availability) {
47075
- if (availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable") return {
47076
- kind: "available",
47077
- remainingPlaces: null
47078
- };
47079
- return availability;
47096
+ //#region ../blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.ts
47097
+ /** Ticket selection requests a quote; only the server admits a booking. */
47098
+ function canRequestTicketOption(availability) {
47099
+ return availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable";
47080
47100
  }
47081
- /**
47082
- * A form-only projection for the explicit existing-checkout path. It permits
47083
- * collecting the original selection without claiming a new place is available.
47084
- * The public checkout service identifies the customer and remains the admission
47085
- * authority; no reservation/customer data is exposed through this projection.
47086
- */
47087
- function getCheckoutRecoveryFormEligibility(eligibility) {
47088
- 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;
47089
- const amountCents = eligibility.price ?? 0;
47090
- if (amountCents <= 0 || !eligibility.currency || eligibility.availability.kind === "unavailable" && eligibility.availability.reason === "selectionRequired") return eligibility.registration.kind === "pending_payment" ? {
47091
- ...eligibility,
47092
- registration: { kind: "none" },
47093
- ticketTypes: eligibility.ticketTypes.map((option) => ({
47094
- ...option,
47095
- availability: checkoutRecoveryOptionAvailability(option.availability)
47096
- }))
47097
- } : eligibility;
47098
- const currency = eligibility.currency;
47099
- const paymentOptions = eligibility.paymentTerms.allowedOptions.map((option) => {
47100
- switch (option.kind) {
47101
- case "upfront": return {
47102
- kind: "payInFull",
47103
- amountCents,
47104
- currency
47105
- };
47106
- case "deferred_manual": return {
47107
- kind: "deferredManual",
47108
- amountCents,
47109
- currency
47110
- };
47111
- case "instalment_plan": return {
47112
- kind: "instalmentPlan",
47113
- amountCents,
47114
- currency
47115
- };
47116
- case "flexible_balance": return {
47117
- kind: "flexibleBalance",
47118
- amountCents,
47119
- currency
47120
- };
47121
- }
47122
- });
47123
- return {
47124
- ...eligibility,
47125
- registration: { kind: "none" },
47126
- availability: {
47127
- kind: "available",
47128
- remainingPlaces: null,
47129
- waitlistEnabled: eligibility.waitlistEnabled
47130
- },
47131
- eligible: paymentOptions.length > 0,
47132
- isFull: false,
47133
- canJoinWaitlist: false,
47134
- isFree: false,
47135
- requiresPayment: true,
47136
- canPayDirectly: paymentOptions.length > 0,
47137
- paymentOptions,
47138
- eligiblePasses: [],
47139
- eligibleMemberships: [],
47140
- ticketTypes: eligibility.ticketTypes.map((option) => ({
47141
- ...option,
47142
- availability: checkoutRecoveryOptionAvailability(option.availability)
47143
- }))
47144
- };
47101
+ function normalizeTicketSelectionLines(lines) {
47102
+ const quantitiesByTicketType = /* @__PURE__ */ new Map();
47103
+ for (const line of lines) {
47104
+ const quantity = Math.floor(line.quantity);
47105
+ if (quantity <= 0) continue;
47106
+ const key = line.pricingOptionId ?? null;
47107
+ quantitiesByTicketType.set(key, (quantitiesByTicketType.get(key) ?? 0) + quantity);
47108
+ }
47109
+ return [...quantitiesByTicketType.entries()].map(([pricingOptionId, quantity]) => ({
47110
+ pricingOptionId,
47111
+ quantity
47112
+ }));
47145
47113
  }
47146
- function isSoldOutEventSelectable(event, waitlistAvailable) {
47147
- return waitlistAvailable || canRecoverEventCheckout(event);
47114
+ function getTicketSelectionTotal(lines) {
47115
+ return normalizeTicketSelectionLines(lines).reduce((total, line) => total + line.quantity, 0);
47148
47116
  }
47149
- function canJoinWaitlistOutsideRecovery(event, attendanceMode, checkoutRecovery) {
47150
- return !checkoutRecovery && event !== null && canJoinEventWaitlist(event, { attendanceMode });
47117
+ function getTicketLineQuantity(lines, pricingOptionId) {
47118
+ return normalizeTicketSelectionLines(lines).find((line) => line.pricingOptionId === pricingOptionId)?.quantity ?? 0;
47151
47119
  }
47152
- function canRecoverEventCheckout(event) {
47153
- return event !== null && (event.registrationSubject.kind === "wholeSeries" || event.pricing.kind !== "free" && event.pricing.kind !== "external");
47120
+ function getSingleSelectedPricingOptionId(lines) {
47121
+ const normalized = normalizeTicketSelectionLines(lines);
47122
+ return normalized.length === 1 ? normalized[0]?.pricingOptionId ?? null : null;
47154
47123
  }
47155
- var init_checkoutRecovery = __esmMin((() => {
47156
- init_domain();
47157
- }));
47124
+ function hasValidPricingOptionSelection(input) {
47125
+ if (!input.selectionRequired) return true;
47126
+ if (input.lines.length === 0) return false;
47127
+ const availableOptionIds = new Set(input.visibleOptions.filter((option) => canRequestTicketOption(option.availability)).map((option) => option.pricingOptionId));
47128
+ return input.lines.every((line) => line.pricingOptionId !== null && availableOptionIds.has(line.pricingOptionId));
47129
+ }
47130
+ function setTicketLineQuantity(input) {
47131
+ const nextQuantity = Math.max(0, Math.floor(input.quantity));
47132
+ const normalized = normalizeTicketSelectionLines(input.lines).filter((line) => line.pricingOptionId !== input.pricingOptionId);
47133
+ if (nextQuantity <= 0) return normalized;
47134
+ return [...normalized, {
47135
+ pricingOptionId: input.pricingOptionId,
47136
+ quantity: nextQuantity
47137
+ }];
47138
+ }
47139
+ function getTicketTypeLineMax(input) {
47140
+ const otherSelectedQuantity = input.totalSelectedQuantity - input.currentQuantity;
47141
+ const maxByBlock = input.maxTickets - otherSelectedQuantity;
47142
+ return Math.max(0, maxByBlock);
47143
+ }
47144
+ var init_ticketSelectionLines = __esmMin((() => {}));
47158
47145
  //#endregion
47159
47146
  //#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
47160
47147
  function getPortalSubjectEmail(profile) {
@@ -47218,8 +47205,6 @@ function formatPassCreditUsageLabel(creditsRemaining) {
47218
47205
  return `Uses 1 of ${creditsRemaining} credits`;
47219
47206
  }
47220
47207
  function transformRegistrationOptionsResponse(response) {
47221
- const canJoinWaitlist = response.availability.kind === "waitlist";
47222
- const isFull = response.availability.remainingPlaces === 0 || response.availability.kind === "unavailable" && response.availability.reason === "full";
47223
47208
  const eligiblePasses = response.entitlements.passes.map((pass) => ({
47224
47209
  id: pass.customerPassId,
47225
47210
  passName: pass.passName,
@@ -47232,7 +47217,6 @@ function transformRegistrationOptionsResponse(response) {
47232
47217
  const eventAcceptsPasses = response.entitlements.requiresLoginForPasses || eligiblePasses.length > 0 || response.entitlements.availableForPurchase.passes.length > 0;
47233
47218
  const eventAcceptsMemberships = response.entitlements.requiresLoginForMemberships || eligibleMemberships.length > 0 || response.entitlements.availableForPurchase.memberships.length > 0;
47234
47219
  const monetaryPaymentAvailable = hasMonetaryPaymentOption(response);
47235
- const registrationAvailable = response.availability.kind === "available" || response.availability.kind === "waitlist";
47236
47220
  return {
47237
47221
  availability: response.availability,
47238
47222
  registration: response.registration,
@@ -47247,7 +47231,6 @@ function transformRegistrationOptionsResponse(response) {
47247
47231
  },
47248
47232
  transactions: []
47249
47233
  } : null,
47250
- eligible: response.registration.kind === "none" && registrationAvailable,
47251
47234
  requiresPayment: monetaryPaymentAvailable,
47252
47235
  pricingStrategy: response.pricing.strategy,
47253
47236
  paymentTerms: response.pricing.paymentTerms,
@@ -47262,16 +47245,12 @@ function transformRegistrationOptionsResponse(response) {
47262
47245
  currency: response.pricing.currency
47263
47246
  })),
47264
47247
  ticketTypes: response.pricing.options,
47265
- isFull,
47266
- waitlistEnabled: response.availability.waitlistEnabled,
47267
- canJoinWaitlist,
47268
47248
  price: response.pricing.subtotalCents,
47269
47249
  currency: response.pricing.currency,
47270
47250
  requiresAuthForPasses: response.entitlements.requiresLoginForPasses,
47271
47251
  requiresAuthForMemberships: response.entitlements.requiresLoginForMemberships,
47272
47252
  eligiblePasses,
47273
47253
  eligibleMemberships,
47274
- canPayDirectly: monetaryPaymentAvailable,
47275
47254
  eventAcceptsPasses,
47276
47255
  eventAcceptsMemberships,
47277
47256
  availablePasses: [...response.entitlements.availableForPurchase.passes],
@@ -47301,8 +47280,8 @@ function getVisibleTicketTypes(input) {
47301
47280
  })) : [];
47302
47281
  return (input.eligibility?.ticketTypes ?? eventTicketTypes).filter((ticketType) => ticketType.isActive && (!input.selectedAttendanceMode || (ticketType.attendanceScope ?? "both") === "both" || (ticketType.attendanceScope ?? "both") === input.selectedAttendanceMode));
47303
47282
  }
47304
- function getImplicitSingleAvailableTicketType(ticketTypes) {
47305
- return ticketTypes.length === 1 && ticketTypes[0]?.availability.kind === "available" ? ticketTypes[0] : null;
47283
+ function getImplicitSingleTicketType(ticketTypes) {
47284
+ return ticketTypes.length === 1 && ticketTypes[0] && canRequestTicketOption(ticketTypes[0].availability) ? ticketTypes[0] : null;
47306
47285
  }
47307
47286
  function findSelectedTicketType(input) {
47308
47287
  if (!input.selectedPricingOptionId) return null;
@@ -47315,6 +47294,7 @@ function findSelectedTicketType(input) {
47315
47294
  var ENTITLEMENT_SINGLE_TICKET_TOOLTIP;
47316
47295
  var init_utils = __esmMin((() => {
47317
47296
  init_src$2();
47297
+ init_ticketSelectionLines();
47318
47298
  init_shared();
47319
47299
  ENTITLEMENT_SINGLE_TICKET_TOOLTIP = "Only available for single-ticket bookings";
47320
47300
  }));
@@ -47327,7 +47307,6 @@ function getEventSelectionMode(events) {
47327
47307
  }
47328
47308
  var EventSelectionStep;
47329
47309
  var init_EventSelectionStep = __esmMin((() => {
47330
- init_checkoutRecovery();
47331
47310
  init_utils();
47332
47311
  init_domain();
47333
47312
  EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCapacity }) => {
@@ -47344,25 +47323,19 @@ var init_EventSelectionStep = __esmMin((() => {
47344
47323
  const remaining = getRemainingPlaces(selectMostOpenCapacitySource(event));
47345
47324
  const isSoldOut = isEventFull(event);
47346
47325
  const canJoinWaitlist = canJoinEventWaitlistOnAnyMode(event);
47347
- const isUnavailable = isSoldOut && !isSoldOutEventSelectable(event, canJoinWaitlist);
47348
47326
  const isLowCapacity = remaining.kind === "low";
47349
47327
  const capacityLabel = formatEventRemainingPlaces(event, { full: "Sold out" });
47350
47328
  const timeZone = event.timeZone ?? null;
47351
- const cardClasses = [
47352
- "er-event-card",
47353
- isSelected && "er-event-card--selected",
47354
- isUnavailable && "er-event-card--disabled"
47355
- ].filter(Boolean).join(" ");
47329
+ const cardClasses = ["er-event-card", isSelected && "er-event-card--selected"].filter(Boolean).join(" ");
47356
47330
  const badgeClasses = [
47357
47331
  "er-capacity-badge",
47358
- isUnavailable && "er-capacity-badge--soldout",
47332
+ isSoldOut && "er-capacity-badge--soldout",
47359
47333
  isLowCapacity && "er-capacity-badge--low",
47360
- (canJoinWaitlist || !isUnavailable && !isLowCapacity) && "er-capacity-badge--available"
47334
+ (canJoinWaitlist || !isSoldOut && !isLowCapacity) && "er-capacity-badge--available"
47361
47335
  ].filter(Boolean).join(" ");
47362
47336
  return /* @__PURE__ */ jsx("button", {
47363
47337
  type: "button",
47364
- onClick: () => !isUnavailable && onSelect(event),
47365
- disabled: isUnavailable,
47338
+ onClick: () => onSelect(event),
47366
47339
  className: cardClasses,
47367
47340
  children: /* @__PURE__ */ jsxs("div", {
47368
47341
  className: "er-event-option",
@@ -47390,44 +47363,15 @@ var init_EventSelectionStep = __esmMin((() => {
47390
47363
  };
47391
47364
  }));
47392
47365
  //#endregion
47393
- //#region ../blocks/src/system/runtime/nodes/event-registration/useCheckoutRecovery.ts
47394
- /** Recovery belongs to the selected booking subject; changing events resets its scope. */
47395
- function useCheckoutRecovery(event, setStep) {
47396
- const [recoveryEventId, setRecoveryEventId] = useState(null);
47397
- return {
47398
- checkoutRecovery: event !== null && recoveryEventId === event.selectionId,
47399
- startCheckoutRecovery: useCallback(() => {
47400
- if (!event) return;
47401
- setRecoveryEventId(event.selectionId);
47402
- setStep("select-tickets");
47403
- }, [event, setStep])
47404
- };
47405
- }
47406
- /** Authenticated pending bookings enter the same form-only recovery path as guests. */
47407
- function useCheckoutRecoveryEligibility(eligibility, step, checkoutRecovery, startCheckoutRecovery) {
47408
- const registrationKind = eligibility?.registration.kind;
47409
- useEffect(() => {
47410
- if ((step === "select-event" || step === "select-tickets" || step === "enter-details" || step === "select-payment") && registrationKind === "pending_payment" && !checkoutRecovery) startCheckoutRecovery();
47411
- }, [
47412
- registrationKind,
47413
- step,
47414
- checkoutRecovery,
47415
- startCheckoutRecovery
47416
- ]);
47417
- return useMemo(() => checkoutRecovery ? getCheckoutRecoveryFormEligibility(eligibility) : eligibility, [checkoutRecovery, eligibility]);
47418
- }
47419
- var init_useCheckoutRecovery = __esmMin((() => {
47420
- init_checkoutRecovery();
47421
- }));
47422
- //#endregion
47423
47366
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.ts
47424
47367
  function resolveRegistrationRecoveryAction(step, action) {
47425
47368
  if (step === "payment-failed") return "payment-options";
47426
- if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "payment-status";
47369
+ if (step === "payment-status") return "none";
47370
+ if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "none";
47427
47371
  return action;
47428
47372
  }
47429
47373
  function canRecoverToWaitlist(eligibility) {
47430
- return Boolean(eligibility?.isFull && eligibility.canJoinWaitlist);
47374
+ return eligibility?.availability.kind === "waitlist" && eligibility.registration.kind !== "pending_payment";
47431
47375
  }
47432
47376
  function shouldRefreshAfterRegistrationError(step, action, enabled) {
47433
47377
  return enabled || step === "error" && action === "places";
@@ -47444,19 +47388,19 @@ function resetRegistrationAfterExpiry(input) {
47444
47388
  input.setErrorMessage("");
47445
47389
  input.setPendingRegistrationReference(null);
47446
47390
  }
47447
- /** Recovery never starts another payment. Unknown payment outcomes go to the portal. */
47391
+ /** Retry the retained submission in place; explicit payment uncertainty stays status-only. */
47448
47392
  function recoverRegistrationError(action, handlers) {
47449
47393
  switch (action) {
47450
47394
  case "none": return;
47451
47395
  case "portal":
47452
- case "payment-status":
47453
47396
  window.location.assign("/portal");
47454
47397
  return;
47455
47398
  case "event":
47456
47399
  window.location.assign(window.location.pathname);
47457
47400
  return;
47458
47401
  case "retry":
47459
- window.location.reload();
47402
+ handlers.clearError();
47403
+ handlers.setStep("select-payment");
47460
47404
  return;
47461
47405
  case "details":
47462
47406
  handlers.clearError();
@@ -47496,54 +47440,6 @@ function validateFormData(formData, requiresConsent = false) {
47496
47440
  }
47497
47441
  var init_validation = __esmMin((() => {}));
47498
47442
  //#endregion
47499
- //#region ../blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.ts
47500
- function normalizeTicketSelectionLines(lines) {
47501
- const quantitiesByTicketType = /* @__PURE__ */ new Map();
47502
- for (const line of lines) {
47503
- const quantity = Math.floor(line.quantity);
47504
- if (quantity <= 0) continue;
47505
- const key = line.pricingOptionId ?? null;
47506
- quantitiesByTicketType.set(key, (quantitiesByTicketType.get(key) ?? 0) + quantity);
47507
- }
47508
- return [...quantitiesByTicketType.entries()].map(([pricingOptionId, quantity]) => ({
47509
- pricingOptionId,
47510
- quantity
47511
- }));
47512
- }
47513
- function getTicketSelectionTotal(lines) {
47514
- return normalizeTicketSelectionLines(lines).reduce((total, line) => total + line.quantity, 0);
47515
- }
47516
- function getTicketLineQuantity(lines, pricingOptionId) {
47517
- return normalizeTicketSelectionLines(lines).find((line) => line.pricingOptionId === pricingOptionId)?.quantity ?? 0;
47518
- }
47519
- function getSingleSelectedPricingOptionId(lines) {
47520
- const normalized = normalizeTicketSelectionLines(lines);
47521
- return normalized.length === 1 ? normalized[0]?.pricingOptionId ?? null : null;
47522
- }
47523
- function hasValidPricingOptionSelection(input) {
47524
- if (!input.selectionRequired) return true;
47525
- if (input.lines.length === 0) return false;
47526
- const availableOptionIds = new Set(input.visibleOptions.filter((option) => option.availability.kind === "available").map((option) => option.pricingOptionId));
47527
- return input.lines.every((line) => line.pricingOptionId !== null && availableOptionIds.has(line.pricingOptionId));
47528
- }
47529
- function setTicketLineQuantity(input) {
47530
- const nextQuantity = Math.max(0, Math.floor(input.quantity));
47531
- const normalized = normalizeTicketSelectionLines(input.lines).filter((line) => line.pricingOptionId !== input.pricingOptionId);
47532
- if (nextQuantity <= 0) return normalized;
47533
- return [...normalized, {
47534
- pricingOptionId: input.pricingOptionId,
47535
- quantity: nextQuantity
47536
- }];
47537
- }
47538
- function getTicketTypeLineMax(input) {
47539
- const otherSelectedQuantity = input.totalSelectedQuantity - input.currentQuantity;
47540
- const maxByBlock = input.maxTickets - otherSelectedQuantity;
47541
- const maxByEvent = input.availableSpots == null ? input.maxTickets : input.availableSpots - otherSelectedQuantity;
47542
- const maxByTicketType = input.ticketTypeRemainingCapacity ?? input.maxTickets;
47543
- return Math.max(0, Math.min(maxByBlock, maxByEvent, maxByTicketType));
47544
- }
47545
- var init_ticketSelectionLines = __esmMin((() => {}));
47546
- //#endregion
47547
47443
  //#region ../blocks/src/system/runtime/nodes/event-registration/hooks.state.ts
47548
47444
  function eligibilityLookupReducer(state, action) {
47549
47445
  switch (action.type) {
@@ -47655,17 +47551,6 @@ function usePortalAuthWithDeps(deps) {
47655
47551
  logout
47656
47552
  };
47657
47553
  }
47658
- function toRegistrationOptionsSubject(subject, attendanceMode) {
47659
- return subject.kind === "occurrence" ? {
47660
- kind: "occurrence",
47661
- occurrenceId: subject.occurrenceId,
47662
- attendanceMode: attendanceMode ?? void 0
47663
- } : {
47664
- kind: "wholeSeries",
47665
- eventSeriesId: subject.eventSeriesId,
47666
- attendanceMode: attendanceMode ?? void 0
47667
- };
47668
- }
47669
47554
  function useEligibility(params) {
47670
47555
  return useEligibilityWithDeps(params, eventRegistrationHooksDeps);
47671
47556
  }
@@ -47706,7 +47591,7 @@ function useEligibilityWithDeps(params, deps) {
47706
47591
  requestIdRef.current = requestId;
47707
47592
  dispatch({ type: "loading-started" });
47708
47593
  try {
47709
- const subject = toRegistrationOptionsSubject(params.subject, params.attendanceMode);
47594
+ const subject = toRegistrationRequestSubject(params.subject, params.attendanceMode);
47710
47595
  const result = await api.getRegistrationOptions({
47711
47596
  subject,
47712
47597
  selections: ticketSelections.map((selection) => ({
@@ -47828,6 +47713,7 @@ var init_hooks = __esmMin((() => {
47828
47713
  init_api();
47829
47714
  init_utils();
47830
47715
  init_ticketSelectionLines();
47716
+ init_registrationDerivations();
47831
47717
  init_hooks_state();
47832
47718
  eventRegistrationHooksDeps = { useBlockApi };
47833
47719
  REGISTRATION_OPTIONS_DEBOUNCE_MS = 150;
@@ -48294,7 +48180,6 @@ var init_stripeMinimumCharge = __esmMin((() => {
48294
48180
  var init_stripeCheckoutReturnUrl = __esmMin((() => {}));
48295
48181
  var init_stateTransitions = __esmMin((() => {
48296
48182
  init_src$2();
48297
- init_assertNever();
48298
48183
  }));
48299
48184
  //#endregion
48300
48185
  //#region ../commerce/src/purchase/event-registration-errors.ts
@@ -48308,9 +48193,9 @@ var init_event_registration_errors = __esmMin((() => {
48308
48193
  message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
48309
48194
  action: "none"
48310
48195
  },
48311
- paymentUncertain: {
48312
- 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.",
48313
- action: "payment-status"
48196
+ paymentInvestigationRequired: {
48197
+ message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
48198
+ action: "none"
48314
48199
  },
48315
48200
  paymentProviderUnavailable: {
48316
48201
  message: "We couldn’t reach the payment provider. Please try again in a minute.",
@@ -48362,6 +48247,7 @@ var init_event_registration_errors = __esmMin((() => {
48362
48247
  }
48363
48248
  };
48364
48249
  }));
48250
+ var init_eventCheckoutRecoveryWindow = __esmMin((() => {}));
48365
48251
  //#endregion
48366
48252
  //#region ../commerce/src/purchase/index.ts
48367
48253
  var init_purchase = __esmMin((() => {
@@ -48423,6 +48309,7 @@ var init_purchase = __esmMin((() => {
48423
48309
  init_stripeCheckoutReturnUrl();
48424
48310
  init_stateTransitions();
48425
48311
  init_event_registration_errors();
48312
+ init_eventCheckoutRecoveryWindow();
48426
48313
  init_stripeCommissionMetadata();
48427
48314
  }));
48428
48315
  //#endregion
@@ -48861,7 +48748,30 @@ function checkoutReturnCommand(params) {
48861
48748
  };
48862
48749
  return null;
48863
48750
  }
48864
- async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
48751
+ function handleCheckoutReturnOutcome(options, deps, context, outcome) {
48752
+ const { pending, params } = context;
48753
+ if (outcome.kind === "resolved") {
48754
+ deps.clearReturnParams();
48755
+ options.setPendingRegistrationReference(outcome.reference);
48756
+ options.setStep("verifying-payment");
48757
+ return "settled";
48758
+ }
48759
+ if (outcome.kind === "abandoned") {
48760
+ deps.clearReturnParams();
48761
+ options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
48762
+ options.setStep("select-payment");
48763
+ return "settled";
48764
+ }
48765
+ if (outcome.kind === "notFound" && params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
48766
+ deps.clearReturnParams();
48767
+ options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
48768
+ options.setStep("select-payment");
48769
+ return "settled";
48770
+ }
48771
+ 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.");
48772
+ return outcome.kind === "notFound" ? "settled" : "retryable";
48773
+ }
48774
+ async function handleCheckoutReturn(options, deps, returnContextRef) {
48865
48775
  deps.cleanupStaleRegistrations();
48866
48776
  const params = deps.readReturnParams();
48867
48777
  if (params.registration !== "cancelled" && params.registration !== "success") return "settled";
@@ -48875,34 +48785,15 @@ async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
48875
48785
  }
48876
48786
  const { checkoutAttemptId } = command;
48877
48787
  const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
48878
- checkoutAttemptIdRef.current = checkoutAttemptId;
48788
+ returnContextRef.current = { checkoutAttemptId };
48879
48789
  if (pending) restorePendingPresentation(options, pending);
48880
48790
  options.setStep("verifying-payment");
48881
48791
  try {
48882
48792
  const outcome = await options.api.resolveEventCheckoutReturn(command);
48883
- switch (outcome.kind) {
48884
- case "resolved":
48885
- deps.clearReturnParams();
48886
- options.setPendingRegistrationReference(outcome.reference);
48887
- options.setStep("verifying-payment");
48888
- return "settled";
48889
- case "abandoned":
48890
- deps.clearReturnParams();
48891
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
48892
- options.setStep("select-payment");
48893
- return "settled";
48894
- case "notFound":
48895
- if (params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
48896
- deps.clearReturnParams();
48897
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
48898
- options.setStep("select-payment");
48899
- return "settled";
48900
- }
48901
- 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.");
48902
- return "settled";
48903
- case "reconciliationRequired": break;
48904
- }
48905
- 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.");
48793
+ return handleCheckoutReturnOutcome(options, deps, {
48794
+ pending,
48795
+ params
48796
+ }, outcome);
48906
48797
  } catch {
48907
48798
  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.");
48908
48799
  }
@@ -48911,9 +48802,16 @@ async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
48911
48802
  function useEventRegistrationStripeReturn(options) {
48912
48803
  return useEventRegistrationStripeReturnWithDeps(options, eventRegistrationStripeReturnDeps);
48913
48804
  }
48805
+ function completeVerifiedRegistration(options, deps, returnContext) {
48806
+ const siteId = options.api.config.siteId;
48807
+ const checkoutAttemptId = returnContext?.checkoutAttemptId;
48808
+ if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
48809
+ options.setRegistrationResult({ status: "confirmed" });
48810
+ options.setStep("success");
48811
+ }
48914
48812
  function useEventRegistrationStripeReturnWithDeps(options, deps) {
48915
48813
  const { api, pendingRegistrationReference, setErrorMessage, setRegistrationResult, setStep, step } = options;
48916
- const checkoutAttemptIdRef = useRef(null);
48814
+ const returnContextRef = useRef(null);
48917
48815
  const lookupInFlightRef = useRef(false);
48918
48816
  const [lookupState, setLookupState] = useState("settled");
48919
48817
  const resolveReturn = useCallback(async () => {
@@ -48921,7 +48819,7 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
48921
48819
  lookupInFlightRef.current = true;
48922
48820
  setLookupState("loading");
48923
48821
  try {
48924
- setLookupState(await handleCheckoutReturn(options, deps, checkoutAttemptIdRef));
48822
+ setLookupState(await handleCheckoutReturn(options, deps, returnContextRef));
48925
48823
  } finally {
48926
48824
  lookupInFlightRef.current = false;
48927
48825
  }
@@ -48944,13 +48842,8 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
48944
48842
  resolveReturn();
48945
48843
  }, []);
48946
48844
  useEffect(() => {
48947
- if (verification.status === "completed") {
48948
- const siteId = api.config.siteId;
48949
- const checkoutAttemptId = checkoutAttemptIdRef.current;
48950
- if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
48951
- setRegistrationResult({ status: "confirmed" });
48952
- setStep("success");
48953
- } else if (verification.status === "failed") {
48845
+ if (verification.status === "completed") completeVerifiedRegistration(options, deps, returnContextRef.current);
48846
+ else if (verification.status === "failed") {
48954
48847
  setErrorMessage("Please try again or choose another payment option. If this keeps happening, contact the organiser for help.");
48955
48848
  setStep("payment-failed");
48956
48849
  } else if (verification.status === "timeout") setStep("verifying-timeout");
@@ -49009,7 +48902,10 @@ function registrationErrorPresentation(error) {
49009
48902
  const reason = error instanceof BlockApiError ? parseEventRegistrationErrorReason(error.tag) : null;
49010
48903
  if (reason) return eventRegistrationErrors[reason];
49011
48904
  if (error instanceof BlockApiError && error.status < 500) return eventRegistrationErrors.invalidCommitInput;
49012
- return eventRegistrationErrors.paymentUncertain;
48905
+ return {
48906
+ message: "Something went wrong. Please try again.",
48907
+ action: "retry"
48908
+ };
49013
48909
  }
49014
48910
  var init_registrationErrorPresentation = __esmMin((() => {
49015
48911
  init_purchase();
@@ -49038,26 +48934,6 @@ function useEventRegistrationSubmit(options) {
49038
48934
  * and the balance left, which the block's copy cannot. Every other method keeps
49039
48935
  * whatever success message the site configured.
49040
48936
  */
49041
- function toRegistrationResult(result) {
49042
- if (result.alreadyRegistered) {
49043
- const waitlisted = result.status === "waitlist";
49044
- return {
49045
- status: result.status,
49046
- variant: "info",
49047
- title: waitlisted ? "Already waitlisted" : "Already registered",
49048
- message: result.message ?? (waitlisted ? "You are already on the waitlist for this event." : "You are already registered for this event.")
49049
- };
49050
- }
49051
- if (result.status === "waitlist") return {
49052
- status: "waitlist",
49053
- title: "Added to waitlist",
49054
- message: result.message ?? (typeof result.waitlistPosition === "number" ? `You've been added to the waitlist (position ${result.waitlistPosition}).` : "You've been added to the waitlist.")
49055
- };
49056
- return {
49057
- status: result.status,
49058
- message: result.paymentMethod === "pass" ? result.message : void 0
49059
- };
49060
- }
49061
48937
  function useEventRegistrationSubmitWithDeps(options, deps) {
49062
48938
  /**
49063
48939
  * The command identity for the submission currently in progress.
@@ -49071,7 +48947,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
49071
48947
  * Identical retries retain the command after a lost response. Changed form
49072
48948
  * details get a new command so the server applies the new booking intent.
49073
48949
  */
49074
- const commandRef = useRef(null);
48950
+ const { commandRef } = options;
49075
48951
  const inFlightRef = useRef(null);
49076
48952
  const submit = async (method, passId, membershipId, selection, submitOptions) => {
49077
48953
  const target = options.registrationTarget;
@@ -49084,19 +48960,15 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
49084
48960
  const registrationCommandId = commandRef.current?.id ?? deps.createClientCommandId();
49085
48961
  try {
49086
48962
  let prepared = prepareSubmitContext(options, registrationCommandId, target, method, passId, membershipId, selection);
49087
- if (prepared.subject.kind === "wholeSeries" && method === "stripe") {
49088
- commandRef.current = null;
49089
- return await submitWholeSeriesCheckout(options, deps, {
48963
+ let request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
48964
+ const intentKey = registrationRequestIntentKey(request);
48965
+ if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) {
48966
+ prepared = {
49090
48967
  ...prepared,
49091
- subject: prepared.subject
49092
- }, submitOptions);
48968
+ registrationCommandId: deps.createClientCommandId()
48969
+ };
48970
+ request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
49093
48971
  }
49094
- const request = buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId);
49095
- const intentKey = registrationRequestIntentKey(request);
49096
- if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) prepared = {
49097
- ...prepared,
49098
- registrationCommandId: deps.createClientCommandId()
49099
- };
49100
48972
  commandRef.current = {
49101
48973
  id: prepared.registrationCommandId,
49102
48974
  intentKey
@@ -49105,8 +48977,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
49105
48977
  ...request,
49106
48978
  registrationCommandId: prepared.registrationCommandId
49107
48979
  });
49108
- commandRef.current = null;
49109
- return await completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions);
48980
+ return await completeRegistrationSubmission(options, deps, prepared, result, submitOptions);
49110
48981
  } catch (error) {
49111
48982
  if (error instanceof BlockApiError && error.tag === "registrationPreparationChanged") commandRef.current = null;
49112
48983
  const { message, action } = registrationErrorPresentation(error);
@@ -49130,9 +49001,40 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
49130
49001
  return pending;
49131
49002
  };
49132
49003
  }
49133
- async function completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions) {
49134
- if (needsOccurrenceCheckout(result, method)) return await submitOccurrenceCheckout(options, deps, prepared, result, method, submitOptions);
49135
- options.setRegistrationResult(toRegistrationResult(result));
49004
+ async function completeRegistrationSubmission(options, deps, prepared, result, submitOptions) {
49005
+ switch (result.kind) {
49006
+ case "paymentStatusRequired":
49007
+ options.setPaymentStatusRecovery({
49008
+ kind: "ready",
49009
+ subject: result.subject
49010
+ });
49011
+ options.setStep("payment-status");
49012
+ return {
49013
+ ok: true,
49014
+ outcome: { kind: "payment_status" }
49015
+ };
49016
+ case "checkoutRequired":
49017
+ options.setPendingRegistrationReference(result.reference);
49018
+ savePendingCheckout(options, deps, prepared, result.submissionId, result.reference);
49019
+ options.setStep("redirecting");
49020
+ return redirectToCheckout(result.checkoutUrl, submitOptions);
49021
+ case "waitlisted":
49022
+ options.setRegistrationResult({
49023
+ status: "waitlist",
49024
+ title: "Added to waitlist",
49025
+ message: result.waitlist.message
49026
+ });
49027
+ break;
49028
+ case "bookingComplete":
49029
+ case "paymentDeferred":
49030
+ options.setPendingRegistrationReference(result.reference);
49031
+ options.setRegistrationResult({
49032
+ status: "confirmed",
49033
+ message: result.summary.paymentMethod === "pass" ? result.summary.message : void 0
49034
+ });
49035
+ break;
49036
+ }
49037
+ options.commandRef.current = null;
49136
49038
  options.setStep("success");
49137
49039
  return {
49138
49040
  ok: true,
@@ -49163,15 +49065,7 @@ function prepareSubmitContext(options, registrationCommandId, target, method, pa
49163
49065
  email: guest.email?.trim().toLowerCase() || void 0,
49164
49066
  phone: guest.phone?.trim() || void 0
49165
49067
  })) : void 0,
49166
- subject: target.subject.kind === "occurrence" ? {
49167
- kind: "occurrence",
49168
- occurrenceId: target.subject.occurrenceId,
49169
- attendanceMode: options.selectedAttendanceMode ?? void 0
49170
- } : {
49171
- kind: "wholeSeries",
49172
- eventSeriesId: target.subject.eventSeriesId,
49173
- attendanceMode: options.selectedAttendanceMode ?? void 0
49174
- }
49068
+ subject: toRegistrationRequestSubject(target.subject, options.selectedAttendanceMode)
49175
49069
  };
49176
49070
  }
49177
49071
  function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId, selection) {
@@ -49195,85 +49089,6 @@ function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId,
49195
49089
  if (method === "free") return { method };
49196
49090
  throw new Error("Choose an available payment option.");
49197
49091
  }
49198
- async function submitWholeSeriesCheckout(options, deps, prepared, submitOptions) {
49199
- options.setStep("redirecting");
49200
- if (prepared.selectionSnapshot.method !== "stripe") throw new Error("Choose an available payment option.");
49201
- const checkoutAttemptId = deps.createClientCommandId();
49202
- const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
49203
- const result = await options.api.createEventCheckout({
49204
- subject: prepared.subject,
49205
- ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
49206
- selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
49207
- email: options.formData.email.trim().toLowerCase(),
49208
- name: options.formData.name.trim(),
49209
- phone: options.formData.phone.trim() || void 0,
49210
- formData: options.formData,
49211
- consentAccepted: options.formData.consentAccepted,
49212
- altchaSolution: options.altchaSolution,
49213
- guests: prepared.guestsPayload,
49214
- claimToken: options.claimToken ?? void 0,
49215
- waitlistEntryId: options.waitlistEntryId ?? void 0,
49216
- discountCode: options.discountCode.trim() || void 0,
49217
- collectionOptionKind: prepared.selectionSnapshot.collectionOptionKind,
49218
- checkoutAttemptId,
49219
- ...urls
49220
- });
49221
- if (result.scope !== "wholeSeries") throw new Error("Unexpected registration scope for event checkout.");
49222
- if ("waitlistEntryId" in result) {
49223
- options.setRegistrationResult({
49224
- status: "waitlist",
49225
- variant: result.alreadyRegistered ? "info" : void 0,
49226
- title: result.alreadyRegistered ? "Already waitlisted" : "Added to waitlist",
49227
- message: result.alreadyRegistered ? "You are already on the waitlist for this event." : "You've been added to the waitlist."
49228
- });
49229
- options.setStep("success");
49230
- return {
49231
- ok: true,
49232
- outcome: { kind: "completed" }
49233
- };
49234
- }
49235
- if (result.bypassed) return completeBypassedCheckout(options);
49236
- if (!result.checkoutUrl) throw new Error("Checkout URL missing");
49237
- savePendingCheckout(options, deps, prepared, result.checkoutAttemptId, {
49238
- scope: "wholeSeries",
49239
- registrationId: result.registrationId
49240
- });
49241
- return redirectToCheckout(result.checkoutUrl, submitOptions);
49242
- }
49243
- function needsOccurrenceCheckout(result, method) {
49244
- return result.scope === "occurrence" && result.status === "confirmed" && result.pendingPayment && [
49245
- "stripe",
49246
- "pass_bundle",
49247
- "membership_bundle"
49248
- ].includes(method);
49249
- }
49250
- async function submitOccurrenceCheckout(options, deps, prepared, registration, method, submitOptions) {
49251
- const reference = {
49252
- scope: "occurrence",
49253
- attendeeId: registration.attendeeId
49254
- };
49255
- options.setPendingRegistrationReference(reference);
49256
- options.setStep("redirecting");
49257
- const checkoutAttemptId = deps.createClientCommandId();
49258
- const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
49259
- const result = await options.api.createEventCheckout({
49260
- subject: {
49261
- kind: "occurrence",
49262
- attendeeId: registration.attendeeId
49263
- },
49264
- registrationCommandId: prepared.registrationCommandId,
49265
- checkoutType: method === "pass_bundle" ? "pass_bundle" : method === "membership_bundle" ? "membership_bundle" : "event",
49266
- productId: prepared.bundleProductId,
49267
- discountCode: options.discountCode.trim() || void 0,
49268
- collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0,
49269
- ...urls
49270
- });
49271
- if (result.scope !== "occurrence") throw new Error("Unexpected registration scope for event checkout.");
49272
- if (result.bypassed) return completeBypassedCheckout(options);
49273
- if (!result.checkoutUrl) throw new Error("Checkout URL missing");
49274
- if (prepared.subject.kind === "occurrence") savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference);
49275
- return redirectToCheckout(result.checkoutUrl, submitOptions);
49276
- }
49277
49092
  function savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference) {
49278
49093
  const siteId = options.api.config.siteId;
49279
49094
  if (!siteId) return;
@@ -49286,14 +49101,6 @@ function savePendingCheckout(options, deps, prepared, checkoutAttemptId, referen
49286
49101
  paymentSelection: prepared.selectionSnapshot
49287
49102
  });
49288
49103
  }
49289
- function completeBypassedCheckout(options) {
49290
- options.setRegistrationResult({ status: "confirmed" });
49291
- options.setStep("success");
49292
- return {
49293
- ok: true,
49294
- outcome: { kind: "completed" }
49295
- };
49296
- }
49297
49104
  function redirectToCheckout(checkoutUrl, submitOptions) {
49298
49105
  if (submitOptions?.redirect !== "manual") window.location.href = checkoutUrl;
49299
49106
  return {
@@ -49305,12 +49112,23 @@ function redirectToCheckout(checkoutUrl, submitOptions) {
49305
49112
  };
49306
49113
  }
49307
49114
  function registrationRequestIntentKey(request) {
49308
- const { registrationCommandId: _command, altchaSolution: _proof, ...intent } = request;
49309
- return JSON.stringify(intent);
49115
+ const { registrationCommandId: _command, altchaSolution: _proof, checkout, ...intent } = request;
49116
+ return JSON.stringify({
49117
+ ...intent,
49118
+ checkout: checkout ? {
49119
+ discountCode: checkout.discountCode,
49120
+ collectionOptionKind: checkout.collectionOptionKind
49121
+ } : void 0
49122
+ });
49310
49123
  }
49311
- function buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId) {
49124
+ function buildRegistrationRequest(options, prepared, method, passId, membershipId) {
49312
49125
  return {
49313
49126
  registrationCommandId: prepared.registrationCommandId,
49127
+ checkout: {
49128
+ ...buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: prepared.registrationCommandId }),
49129
+ discountCode: options.discountCode.trim() || void 0,
49130
+ collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0
49131
+ },
49314
49132
  subject: prepared.subject,
49315
49133
  ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
49316
49134
  selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
@@ -49335,6 +49153,7 @@ var init_useEventRegistrationSubmit = __esmMin((() => {
49335
49153
  init_shared();
49336
49154
  init_registrationErrorPresentation();
49337
49155
  init_constants();
49156
+ init_registrationDerivations();
49338
49157
  init_sessionStorage();
49339
49158
  init_ticketSelectionLines();
49340
49159
  eventRegistrationSubmitDeps = {
@@ -49552,23 +49371,128 @@ var init_useWaitlistClaimRestoration = __esmMin((() => {
49552
49371
  }));
49553
49372
  //#endregion
49554
49373
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationCompletion.ts
49374
+ function isSelectionSoldOut(availability) {
49375
+ return availability?.kind === "unavailable" && availability.reason === "full";
49376
+ }
49555
49377
  function resolveRegistrationAvailabilityBlocker(input) {
49556
49378
  if (input.hasWaitlistClaim) return null;
49557
49379
  if (input.eligibilityError) return input.eligibilityError;
49558
49380
  if (!input.eligibility) return "Registration is not available for this event.";
49381
+ if (input.eligibility.registration.kind === "pending_payment") return null;
49382
+ if (isSelectionSoldOut(input.eligibility.availability)) return null;
49559
49383
  if (input.eligibility.availability.kind === "unavailable" && input.eligibility.availability.reason === "paymentUnavailable") return "Payment options are not available for this event.";
49560
- if (input.eligibility.availability.kind === "unavailable" || !input.eligibility.eligible) return "Registration is not available for this event.";
49384
+ if (input.eligibility.availability.kind === "unavailable" || input.eligibility.registration.kind === "waitlisted") return "Registration is not available for this event.";
49561
49385
  return null;
49562
49386
  }
49563
49387
  function resolvePricingSelectionBlocker(input) {
49564
49388
  if (input.selectionRequired && !input.hasValidSelection) return "Choose at least one available ticket to continue.";
49565
49389
  return input.slidingScaleSelectionMessage;
49566
49390
  }
49567
- function isSoldOutWithoutWaitlist(input) {
49568
- return Boolean(!input.hasWaitlistClaim && input.eligibility?.isFull && !input.eligibility.canJoinWaitlist);
49569
- }
49570
49391
  var init_registrationCompletion = __esmMin((() => {}));
49571
49392
  //#endregion
49393
+ //#region ../blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.ts
49394
+ function isCheckableRecovery(state) {
49395
+ return state.kind === "ready" || state.kind === "processing" || state.kind === "temporarilyUnavailable";
49396
+ }
49397
+ function assistanceRequired(recovery) {
49398
+ return {
49399
+ kind: "assistanceRequired",
49400
+ subject: recovery.subject
49401
+ };
49402
+ }
49403
+ function applyStatusOutcome(outcome, recovery, setters, setRecovery) {
49404
+ if (outcome.kind === "resolved") {
49405
+ setters.setPendingRegistrationReference(outcome.reference);
49406
+ setters.setRegistrationResult({ status: "confirmed" });
49407
+ setRecovery(null);
49408
+ setters.setStep("success");
49409
+ return;
49410
+ }
49411
+ switch (outcome.kind) {
49412
+ case "paymentProcessing":
49413
+ setRecovery({
49414
+ ...recovery,
49415
+ kind: "processing"
49416
+ });
49417
+ return;
49418
+ case "paymentAvailable":
49419
+ setRecovery({
49420
+ ...recovery,
49421
+ kind: "paymentAvailable",
49422
+ checkoutUrl: outcome.checkoutUrl
49423
+ });
49424
+ return;
49425
+ case "paymentCheckUnavailable":
49426
+ setRecovery({
49427
+ ...recovery,
49428
+ kind: "temporarilyUnavailable"
49429
+ });
49430
+ return;
49431
+ case "paymentRetryAvailable":
49432
+ setRecovery({
49433
+ ...recovery,
49434
+ kind: "retryAvailable"
49435
+ });
49436
+ return;
49437
+ case "abandoned":
49438
+ case "notFound":
49439
+ case "reconciliationRequired":
49440
+ case "paymentAssistanceRequired":
49441
+ setRecovery(assistanceRequired(recovery));
49442
+ return;
49443
+ }
49444
+ }
49445
+ function usePaymentStatusRecovery(options) {
49446
+ const [recovery, setRecovery] = useState(null);
49447
+ const checkRef = useRef(null);
49448
+ return {
49449
+ recovery,
49450
+ showRecovery: useCallback((next) => setRecovery(next), []),
49451
+ check: useCallback(() => {
49452
+ if (!recovery || !isCheckableRecovery(recovery) || checkRef.current) return;
49453
+ const pending = (async () => {
49454
+ setRecovery({
49455
+ ...recovery,
49456
+ kind: "checking"
49457
+ });
49458
+ try {
49459
+ applyStatusOutcome(await options.api.resolveEventCheckoutReturn({
49460
+ kind: "checkStatus",
49461
+ subject: recovery.subject
49462
+ }), recovery, options, setRecovery);
49463
+ } catch {
49464
+ setRecovery({
49465
+ ...recovery,
49466
+ kind: "temporarilyUnavailable"
49467
+ });
49468
+ }
49469
+ })();
49470
+ checkRef.current = pending;
49471
+ pending.finally(() => {
49472
+ if (checkRef.current === pending) checkRef.current = null;
49473
+ });
49474
+ }, [options, recovery]),
49475
+ continuePayment: useCallback(() => {
49476
+ if (recovery?.kind === "paymentAvailable") window.location.assign(recovery.checkoutUrl);
49477
+ }, [recovery]),
49478
+ returnToPayment: useCallback(() => {
49479
+ if (recovery?.kind !== "retryAvailable") return;
49480
+ options.beginNewSubmission();
49481
+ setRecovery(null);
49482
+ options.setOptionsRefreshKey((value) => value + 1);
49483
+ options.setStep("select-payment");
49484
+ }, [options, recovery]),
49485
+ returnToBooking: useCallback(() => {
49486
+ if (recovery?.kind !== "assistanceRequired") return;
49487
+ options.beginNewSubmission();
49488
+ setRecovery(null);
49489
+ options.setOptionsRefreshKey((value) => value + 1);
49490
+ options.setStep("select-tickets");
49491
+ }, [options, recovery])
49492
+ };
49493
+ }
49494
+ var init_usePaymentStatusRecovery = __esmMin((() => {}));
49495
+ //#endregion
49572
49496
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
49573
49497
  function usesTieredPricing(event) {
49574
49498
  return event !== null && event !== void 0 ? publicEventPricingStrategy(event.pricing) === "tiered" : false;
@@ -49615,6 +49539,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
49615
49539
  const [errorAction, setErrorAction] = useState("retry");
49616
49540
  const [optionsRefreshKey, setOptionsRefreshKey] = useState(0);
49617
49541
  const [altchaSolution, setAltchaSolution] = useState(null);
49542
+ const [checkingNextStep, setCheckingNextStep] = useState(false);
49618
49543
  const { authState: portalAuthState, profile: portalProfile } = deps.usePortalAuth();
49619
49544
  const waitlistClaim = deps.useWaitlistClaim();
49620
49545
  const [showMagicLinkModal, setShowMagicLinkModal] = useState(false);
@@ -49641,28 +49566,29 @@ function useEventRegistrationWizardWithDeps(options, deps) {
49641
49566
  }), [options.occurrenceContext, selectedEvent]);
49642
49567
  const registrationOccurrenceId = getRegistrationOccurrenceId(registrationTarget);
49643
49568
  const currentEvent = selectedEvent ?? preSelectedEvent;
49569
+ const commandRef = useRef(null);
49644
49570
  const setStep = useCallback((nextStep) => {
49645
49571
  dispatchFlow({
49646
49572
  type: "set-step",
49647
49573
  step: nextStep
49648
49574
  });
49649
49575
  }, []);
49650
- const { checkoutRecovery, startCheckoutRecovery } = useCheckoutRecovery(currentEvent, setStep);
49651
- const currentEventUsesTicketTypes = usesTieredPricing(currentEvent);
49652
- const currentCanJoinWaitlist = canJoinWaitlistOutsideRecovery(currentEvent, selectedAttendanceMode, checkoutRecovery);
49653
- const usesTicketTypeSelections = currentEventUsesTicketTypes && !currentCanJoinWaitlist;
49576
+ const { recovery: paymentStatusRecovery, showRecovery: setPaymentStatusRecovery, check: handleCheckPaymentStatus, continuePayment: handleContinueExistingPayment, returnToPayment: handleReturnToPayment, returnToBooking: handleReturnToBooking } = usePaymentStatusRecovery({
49577
+ api,
49578
+ beginNewSubmission: () => {
49579
+ commandRef.current = null;
49580
+ },
49581
+ setPendingRegistrationReference,
49582
+ setRegistrationResult,
49583
+ setOptionsRefreshKey,
49584
+ setStep
49585
+ });
49586
+ const usesTicketTypeSelections = usesTieredPricing(currentEvent);
49654
49587
  const eventTicketTypesForSelection = useMemo(() => getVisibleTicketTypes({
49655
49588
  event: currentEvent,
49656
49589
  eligibility: null,
49657
49590
  selectedAttendanceMode
49658
- }).map((option) => checkoutRecovery ? {
49659
- ...option,
49660
- availability: checkoutRecoveryOptionAvailability(option.availability)
49661
- } : option), [
49662
- currentEvent,
49663
- selectedAttendanceMode,
49664
- checkoutRecovery
49665
- ]);
49591
+ }), [currentEvent, selectedAttendanceMode]);
49666
49592
  const normalizedSelectedTicketLines = useMemo(() => normalizeTicketSelectionLines(selectedTicketLines), [selectedTicketLines]);
49667
49593
  const ticketTypeSelectionTotal = useMemo(() => getTicketSelectionTotal(normalizedSelectedTicketLines), [normalizedSelectedTicketLines]);
49668
49594
  const ticketsCount = usesTicketTypeSelections ? ticketTypeSelectionTotal : flowState.ticketsCount;
@@ -49700,7 +49626,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
49700
49626
  isAuthenticated: portalAuthState === "authenticated",
49701
49627
  occurrenceId: registrationOccurrenceId
49702
49628
  });
49703
- const eligibility = useCheckoutRecoveryEligibility(eligibilityResult.eligibility, step, checkoutRecovery, startCheckoutRecovery);
49629
+ const eligibility = eligibilityResult.eligibility;
49704
49630
  const eligibilityLoading = eligibilityResult.isLoading;
49705
49631
  const eligibilityError = eligibilityResult.error;
49706
49632
  const portalCreditState = eligibilityResult.creditState;
@@ -49812,14 +49738,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
49812
49738
  event: currentEvent,
49813
49739
  eligibility,
49814
49740
  selectedAttendanceMode
49815
- }).map((option) => checkoutRecovery ? {
49816
- ...option,
49817
- availability: checkoutRecoveryOptionAvailability(option.availability)
49818
- } : option), [
49741
+ }), [
49819
49742
  currentEvent,
49820
49743
  selectedAttendanceMode,
49821
- eligibility,
49822
- checkoutRecovery
49744
+ eligibility
49823
49745
  ]);
49824
49746
  const singleSelectedPricingOptionId = getSingleSelectedPricingOptionId(normalizedSelectedTicketLines);
49825
49747
  const selectedTicketType = useMemo(() => findSelectedTicketType({
@@ -49843,12 +49765,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
49843
49765
  const event = currentEvent;
49844
49766
  if (!usesTieredPricing(event)) return false;
49845
49767
  if ((event.deliveryMode ?? "in_person") === "hybrid" && !selectedAttendanceMode) return false;
49846
- return checkoutRecovery || !canJoinEventWaitlist(event, { attendanceMode: selectedAttendanceMode });
49847
- }, [
49848
- currentEvent,
49849
- selectedAttendanceMode,
49850
- checkoutRecovery
49851
- ]);
49768
+ return true;
49769
+ }, [currentEvent, selectedAttendanceMode]);
49852
49770
  const hasValidTicketSelection = hasValidPricingOptionSelection({
49853
49771
  selectionRequired: ticketTypeSelectionRequired,
49854
49772
  lines: normalizedSelectedTicketLines,
@@ -49859,8 +49777,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
49859
49777
  if (selectedTicketLines.length > 0) setSelectedTicketLines([]);
49860
49778
  return;
49861
49779
  }
49862
- const availableTicketTypes = eventTicketTypesForSelection.filter((ticketType) => ticketType.availability.kind === "available");
49863
- const implicitTicketType = getImplicitSingleAvailableTicketType(eventTicketTypesForSelection);
49780
+ const availableTicketTypes = eventTicketTypesForSelection.filter((ticketType) => canRequestTicketOption(ticketType.availability));
49781
+ const implicitTicketType = getImplicitSingleTicketType(eventTicketTypesForSelection);
49864
49782
  if (implicitTicketType && normalizedSelectedTicketLines.length === 0) {
49865
49783
  setSelectedTicketLines([{
49866
49784
  pricingOptionId: implicitTicketType.pricingOptionId,
@@ -49927,6 +49845,26 @@ function useEventRegistrationWizardWithDeps(options, deps) {
49927
49845
  selectedEventSlidingScale,
49928
49846
  selectedSlidingAmount
49929
49847
  ]);
49848
+ const checkDetailsNextStep = async () => {
49849
+ if (portalAuthState === "authenticated" || waitlistClaim.claim || eligibility?.availability.kind === "available" || !registrationTarget) return { kind: canRecoverToWaitlist(eligibility) ? "waitlist" : "continue" };
49850
+ setCheckingNextStep(true);
49851
+ try {
49852
+ return await api.checkRegistrationNextStep({
49853
+ subject: toRegistrationRequestSubject(registrationTarget.subject, selectedAttendanceMode),
49854
+ selections: ticketSelections,
49855
+ selectedSlidingAmount: selectedSlidingAmount ?? void 0,
49856
+ email: formData.email,
49857
+ altchaSolution
49858
+ });
49859
+ } catch {
49860
+ return {
49861
+ kind: "unavailable",
49862
+ message: "We could not check availability. Please try again."
49863
+ };
49864
+ } finally {
49865
+ setCheckingNextStep(false);
49866
+ }
49867
+ };
49930
49868
  const handleDetailsComplete = async () => {
49931
49869
  const blockDetailsCompletion = (message) => {
49932
49870
  setErrorAction("places");
@@ -49958,11 +49896,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
49958
49896
  message: "Check the highlighted fields and try again."
49959
49897
  };
49960
49898
  }
49961
- if (isSoldOutWithoutWaitlist({
49962
- hasWaitlistClaim: waitlistClaim.claim !== null,
49963
- eligibility
49964
- })) return blockDetailsCompletion("Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.");
49965
- if (!eligibility?.canJoinWaitlist && requiresPaymentStep({
49899
+ const next = await checkDetailsNextStep();
49900
+ if (next.kind === "unavailable") return blockDetailsCompletion(next.message);
49901
+ const canJoinWaitlist = next.kind === "waitlist";
49902
+ if (!canJoinWaitlist && requiresPaymentStep({
49966
49903
  eventRequiresPayment,
49967
49904
  paymentSelection
49968
49905
  })) {
@@ -49975,7 +49912,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
49975
49912
  const submitPlan = resolveEventRegistrationSubmitPlan({
49976
49913
  paymentSelection,
49977
49914
  eventRequiresPayment,
49978
- canJoinWaitlist: eligibility?.canJoinWaitlist
49915
+ canJoinWaitlist
49979
49916
  });
49980
49917
  if (!submitPlan.ok) return blockDetailsCompletion(submitPlan.message);
49981
49918
  const submitResult = await handleSubmit(submitPlan.args.method, submitPlan.args.passId, submitPlan.args.membershipId, submitPlan.args.selection);
@@ -49993,7 +49930,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
49993
49930
  const submitPlan = resolveEventRegistrationSubmitPlan({
49994
49931
  paymentSelection,
49995
49932
  eventRequiresPayment,
49996
- canJoinWaitlist: eligibility?.canJoinWaitlist
49933
+ canJoinWaitlist: false
49997
49934
  });
49998
49935
  if (!submitPlan.ok) {
49999
49936
  setErrorMessage(submitPlan.message);
@@ -50025,6 +49962,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
50025
49962
  const selectionMethod = paymentSelection.method;
50026
49963
  const shouldShowDiscountToggle = discountContext !== null && discountUi.manualCodeEntryAllowed && (selectionMethod === "stripe" || selectionMethod === "pass_bundle" || selectionMethod === "membership_bundle");
50027
49964
  const handleSubmit = deps.useEventRegistrationSubmit({
49965
+ commandRef,
50028
49966
  setErrorAction,
50029
49967
  api,
50030
49968
  registrationTarget,
@@ -50041,7 +49979,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
50041
49979
  setPendingRegistrationReference,
50042
49980
  setStep,
50043
49981
  setRegistrationResult: (result) => setRegistrationResult(result),
50044
- setErrorMessage
49982
+ setErrorMessage,
49983
+ setPaymentStatusRecovery
50045
49984
  });
50046
49985
  const handleEventSelect = (event) => {
50047
49986
  setSelectedEvent(event);
@@ -50100,8 +50039,6 @@ function useEventRegistrationWizardWithDeps(options, deps) {
50100
50039
  scopedEvents,
50101
50040
  preSelectedEvent,
50102
50041
  hasPreSelectedContext,
50103
- checkoutRecovery,
50104
- startCheckoutRecovery,
50105
50042
  step,
50106
50043
  setStep,
50107
50044
  selectedEvent,
@@ -50155,7 +50092,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
50155
50092
  waitlistClaim,
50156
50093
  eligibility,
50157
50094
  registrationOptionsState: eligibilityResult.state,
50158
- eligibilityLoading,
50095
+ eligibilityLoading: eligibilityLoading || checkingNextStep,
50159
50096
  eligibilityError,
50160
50097
  existingRegistration: existingRegistrationResult.registration,
50161
50098
  existingRegistrationLoading: existingRegistrationResult.isLoading || portalAuthState === "authenticated" && eligibilityLoading,
@@ -50175,6 +50112,11 @@ function useEventRegistrationWizardWithDeps(options, deps) {
50175
50112
  discountContext,
50176
50113
  shouldShowDiscountToggle,
50177
50114
  verification,
50115
+ paymentStatusRecovery,
50116
+ handleCheckPaymentStatus,
50117
+ handleContinueExistingPayment,
50118
+ handleReturnToPayment,
50119
+ handleReturnToBooking,
50178
50120
  handleDetailsComplete,
50179
50121
  handlePaymentSelect,
50180
50122
  handleUseCardInsteadOfPass,
@@ -50186,12 +50128,9 @@ function useEventRegistrationWizardWithDeps(options, deps) {
50186
50128
  }
50187
50129
  var eventRegistrationWizardDeps;
50188
50130
  var init_useEventRegistrationWizard = __esmMin((() => {
50189
- init_checkoutRecovery();
50190
- init_useCheckoutRecovery();
50191
50131
  init_src$2();
50192
50132
  init_registrationErrorRecovery();
50193
50133
  init_api();
50194
- init_domain();
50195
50134
  init_validation();
50196
50135
  init_hooks();
50197
50136
  init_portalLogout();
@@ -50211,6 +50150,7 @@ var init_useEventRegistrationWizard = __esmMin((() => {
50211
50150
  init_waitlistClaimRestoration();
50212
50151
  init_useWaitlistClaimRestoration();
50213
50152
  init_registrationCompletion();
50153
+ init_usePaymentStatusRecovery();
50214
50154
  eventRegistrationWizardDeps = {
50215
50155
  usePortalAuth,
50216
50156
  useEligibility,
@@ -50394,7 +50334,6 @@ var init_ErrorStep = __esmMin((() => {
50394
50334
  start: "Start again",
50395
50335
  details: "Check my details",
50396
50336
  "payment-options": "View payment options",
50397
- "payment-status": "Check payment status",
50398
50337
  portal: "View my bookings",
50399
50338
  event: "View event"
50400
50339
  };
@@ -50413,7 +50352,7 @@ var init_ErrorStep = __esmMin((() => {
50413
50352
  className: "er-text--muted er-message",
50414
50353
  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
50415
50354
  }),
50416
- actions: action === "none" ? void 0 : action === "portal" || action === "payment-status" ? /* @__PURE__ */ jsx("a", {
50355
+ actions: action === "none" ? void 0 : action === "portal" ? /* @__PURE__ */ jsx("a", {
50417
50356
  href: "/portal",
50418
50357
  className: "er-retry-btn",
50419
50358
  children: labels[action]
@@ -50674,8 +50613,11 @@ var init_EventRegistrationSummaryBar = __esmMin((() => {
50674
50613
  */
50675
50614
  function resolveDetailsButtonText(input) {
50676
50615
  const { wizard } = input;
50677
- if (wizard.eligibility?.canJoinWaitlist) return "Join waitlist";
50678
- if (!input.hasWaitlistClaim && wizard.eligibility?.isFull) return "Sold out";
50616
+ const availability = wizard.eligibility?.availability;
50617
+ const full = availability?.kind === "waitlist" || isSelectionSoldOut(availability);
50618
+ if (wizard.portalAuthState !== "authenticated" && full) return "Continue";
50619
+ if (canRecoverToWaitlist(wizard.eligibility)) return "Join waitlist";
50620
+ if (!input.hasWaitlistClaim && full && wizard.eligibility?.registration.kind !== "pending_payment") return "Sold out";
50679
50621
  if (wizard.paymentSelection.method === "pass") return "Book using class pass";
50680
50622
  if (wizard.paymentSelection.method === "membership") return input.fallbackText;
50681
50623
  return wizard.eventRequiresPayment ? "Continue to payment" : input.fallbackText;
@@ -50690,44 +50632,28 @@ function isExistingRegistrationBlocking$1(wizard) {
50690
50632
  hasWaitlistClaim: wizard.waitlistClaim.claim !== null
50691
50633
  });
50692
50634
  }
50693
- /**
50694
- * Full for the visitor's selected attendance mode (or the whole event when no
50695
- * mode is chosen) with no waitlist to fall back on. Reads the same capacity
50696
- * source as the steps above the action bar so the button never disagrees
50697
- * with them on a hybrid event.
50698
- */
50699
- function isFullWithNoWaitlist(event, attendanceMode) {
50700
- if (!event) return false;
50701
- const source = selectEventCapacitySource(event, attendanceMode);
50702
- return getEventAvailability(source).isFull && !source.waitlistEnabled;
50703
- }
50704
50635
  function resolveTicketSelectionContinueLabel(input) {
50705
50636
  if (input.isCheckingExistingRegistration) return "Checking registration...";
50706
50637
  if (input.registrationOptionsPending) return "Checking availability...";
50707
50638
  if (input.registrationOptionsFailed) return "Availability unavailable";
50708
50639
  if (input.hasExistingRegistration) return resolveExistingRegistrationLabel(input.wizard);
50709
- if (input.isSoldOutWithoutWaitlist) return "Sold out";
50710
50640
  if (input.ticketTypeSelectionBlocked) return "Choose a ticket";
50711
50641
  return "Continue";
50712
50642
  }
50713
50643
  function SelectTicketsActions(props) {
50714
50644
  const { wizard } = props;
50715
- const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
50716
- const currentEvent = wizard.selectedEvent ?? wizard.preSelectedEvent;
50717
50645
  const registrationOptionsPending = wizard.registrationOptionsState.tag === "idle" || wizard.registrationOptionsState.tag === "loading";
50718
50646
  const registrationOptionsFailed = wizard.registrationOptionsState.tag === "failed";
50719
- const isSoldOutWithoutWaitlist = !wizard.checkoutRecovery && !hasWaitlistClaim && isFullWithNoWaitlist(currentEvent, wizard.selectedAttendanceMode);
50720
50647
  const isCheckingExistingRegistration = wizard.portalAuthState === "authenticated" && wizard.existingRegistrationLoading;
50721
50648
  const hasExistingRegistration = isExistingRegistrationBlocking$1(wizard);
50722
50649
  const ticketTypeSelectionBlocked = wizard.ticketTypeSelectionRequired && !wizard.hasValidTicketSelection;
50723
- const isContinueDisabled = registrationOptionsPending || registrationOptionsFailed || isCheckingExistingRegistration || hasExistingRegistration || isSoldOutWithoutWaitlist || ticketTypeSelectionBlocked;
50650
+ const isContinueDisabled = registrationOptionsPending || registrationOptionsFailed || isCheckingExistingRegistration || hasExistingRegistration || ticketTypeSelectionBlocked;
50724
50651
  const continueLabel = resolveTicketSelectionContinueLabel({
50725
50652
  wizard,
50726
50653
  registrationOptionsPending,
50727
50654
  registrationOptionsFailed,
50728
50655
  isCheckingExistingRegistration,
50729
50656
  hasExistingRegistration,
50730
- isSoldOutWithoutWaitlist,
50731
50657
  ticketTypeSelectionBlocked
50732
50658
  });
50733
50659
  return /* @__PURE__ */ jsxs("div", {
@@ -50758,8 +50684,12 @@ function EnterDetailsActions(props) {
50758
50684
  const { wizard } = props;
50759
50685
  const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
50760
50686
  const isCheckingEligibility = wizard.eligibilityLoading;
50761
- const eligibilityUnavailable = !hasWaitlistClaim && (Boolean(wizard.eligibilityError) || !wizard.eligibility || wizard.eligibility.availability.kind === "unavailable" || !wizard.eligibility.eligible);
50762
- const isSoldOut = !hasWaitlistClaim && wizard.eligibility?.isFull === true && wizard.eligibility.canJoinWaitlist !== true;
50687
+ const eligibilityUnavailable = Boolean(resolveRegistrationAvailabilityBlocker({
50688
+ hasWaitlistClaim,
50689
+ eligibility: wizard.eligibility,
50690
+ eligibilityError: wizard.eligibilityError
50691
+ }));
50692
+ const isSoldOut = !hasWaitlistClaim && wizard.portalAuthState === "authenticated" && wizard.eligibility?.registration.kind !== "pending_payment" && isSelectionSoldOut(wizard.eligibility?.availability);
50763
50693
  const isContinueDisabled = isCheckingEligibility || eligibilityUnavailable || isSoldOut;
50764
50694
  const continueLabel = isCheckingEligibility ? "Checking availability..." : wizard.eligibilityError ? "Availability unavailable" : eligibilityUnavailable ? "Registration unavailable" : resolveDetailsButtonText({
50765
50695
  wizard,
@@ -50810,6 +50740,7 @@ function EventRegistrationWizardActions(props) {
50810
50740
  case "redirecting":
50811
50741
  case "verifying-payment":
50812
50742
  case "verifying-timeout":
50743
+ case "payment-status":
50813
50744
  case "payment-failed": return null;
50814
50745
  case "select-event": return null;
50815
50746
  case "select-tickets": return /* @__PURE__ */ jsx(SelectTicketsActions, { ...props });
@@ -50821,7 +50752,8 @@ function EventRegistrationWizardActions(props) {
50821
50752
  var init_EventRegistrationWizardActions = __esmMin((() => {
50822
50753
  init_registrationStateMachine();
50823
50754
  init_spinner$1();
50824
- init_domain();
50755
+ init_registrationCompletion();
50756
+ init_registrationErrorRecovery();
50825
50757
  }));
50826
50758
  //#endregion
50827
50759
  //#region ../blocks/src/system/runtime/nodes/event-registration/siteCreditPreview.ts
@@ -50902,7 +50834,7 @@ var init_siteCreditPreview = __esmMin((() => {
50902
50834
  function resolvePaymentStepStatus(input) {
50903
50835
  if (input.loading) return "loading";
50904
50836
  if (input.error || !input.eligibility) return "error";
50905
- if (input.eligibility.registration.kind !== "none" || !input.eligibility.eligible && !input.eligibility.isFree) return "not-eligible";
50837
+ if (input.eligibility.registration.kind === "waitlisted" || input.eligibility.paymentOptions.length === 0) return "not-eligible";
50906
50838
  return "ready";
50907
50839
  }
50908
50840
  function shouldPromptForLogin(status, isAuthenticated, eligibility) {
@@ -50937,7 +50869,7 @@ function UnavailableEntitlementMessage(props) {
50937
50869
  ] });
50938
50870
  }
50939
50871
  function IneligiblePaymentPanel(props) {
50940
- if (props.eligibility.isFull && !props.eligibility.canJoinWaitlist) return /* @__PURE__ */ jsxs("div", {
50872
+ if (isSelectionSoldOut(props.eligibility.availability)) return /* @__PURE__ */ jsxs("div", {
50941
50873
  className: "rb-reg-stack er-stack",
50942
50874
  children: [/* @__PURE__ */ jsx("h3", {
50943
50875
  className: "er-title",
@@ -51006,26 +50938,23 @@ function PaymentBlockingPanel(props) {
51006
50938
  })
51007
50939
  });
51008
50940
  if (!props.eligibility) return /* @__PURE__ */ jsx(MissingEligibilityPanel, {});
51009
- if (props.eligibility.registration.kind !== "none") {
51010
- const isBooked = props.eligibility.registration.kind === "booked";
51011
- return /* @__PURE__ */ jsxs("div", {
51012
- className: "rb-reg-stack er-stack",
51013
- children: [/* @__PURE__ */ jsx("h3", {
51014
- className: "er-title",
51015
- children: isBooked ? "Already booked" : "Already on the waitlist"
51016
- }), /* @__PURE__ */ jsxs("div", {
51017
- className: "er-center",
51018
- children: [/* @__PURE__ */ jsx("p", {
51019
- className: "er-text er-text--muted",
51020
- 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."
51021
- }), /* @__PURE__ */ jsx("a", {
51022
- href: "/portal",
51023
- className: "er-retry-btn",
51024
- children: "View my bookings"
51025
- })]
50941
+ if (props.eligibility.registration.kind === "waitlisted") return /* @__PURE__ */ jsxs("div", {
50942
+ className: "rb-reg-stack er-stack",
50943
+ children: [/* @__PURE__ */ jsx("h3", {
50944
+ className: "er-title",
50945
+ children: "Already on the waitlist"
50946
+ }), /* @__PURE__ */ jsxs("div", {
50947
+ className: "er-center",
50948
+ children: [/* @__PURE__ */ jsx("p", {
50949
+ className: "er-text er-text--muted",
50950
+ children: "You're already on the waitlist for this event."
50951
+ }), /* @__PURE__ */ jsx("a", {
50952
+ href: "/portal",
50953
+ className: "er-retry-btn",
50954
+ children: "View my bookings"
51026
50955
  })]
51027
- });
51028
- }
50956
+ })]
50957
+ });
51029
50958
  if (props.eligibility.isFree) return /* @__PURE__ */ jsxs("div", {
51030
50959
  className: "rb-reg-stack er-stack",
51031
50960
  children: [/* @__PURE__ */ jsx("h3", {
@@ -51046,7 +50975,7 @@ function PaymentBlockingPanel(props) {
51046
50975
  })]
51047
50976
  })]
51048
50977
  });
51049
- return props.eligibility.eligible ? null : /* @__PURE__ */ jsx(IneligiblePaymentPanel, {
50978
+ return props.eligibility.paymentOptions.length > 0 ? null : /* @__PURE__ */ jsx(IneligiblePaymentPanel, {
51050
50979
  eligibility: props.eligibility,
51051
50980
  email: props.email,
51052
50981
  isAuthenticated: props.isAuthenticated,
@@ -51056,6 +50985,7 @@ function PaymentBlockingPanel(props) {
51056
50985
  var init_PaymentBlockingPanel = __esmMin((() => {
51057
50986
  init_buttons();
51058
50987
  init_spinner$1();
50988
+ init_registrationCompletion();
51059
50989
  }));
51060
50990
  //#endregion
51061
50991
  //#region ../blocks/src/system/runtime/nodes/event-registration/types.ts
@@ -51185,7 +51115,7 @@ function SlidingScaleAmountField(props) {
51185
51115
  }
51186
51116
  function TicketTypeQuantityRows(props) {
51187
51117
  const totalSelectedQuantity = getTicketSelectionTotal(props.ticketSelections);
51188
- const effectiveMaxTickets = props.availableSpots == null ? props.maxTickets : Math.min(props.maxTickets, props.availableSpots);
51118
+ const effectiveMaxTickets = props.maxTickets;
51189
51119
  return /* @__PURE__ */ jsxs("div", {
51190
51120
  className: "er-ticket-lines",
51191
51121
  children: [
@@ -51195,16 +51125,14 @@ function TicketTypeQuantityRows(props) {
51195
51125
  "aria-label": props.bookingUnit === "place" ? "Places" : "Tickets",
51196
51126
  children: props.ticketTypes.map((ticketType) => {
51197
51127
  const quantity = getTicketLineQuantity(props.ticketSelections, ticketType.pricingOptionId);
51198
- const disabled = ticketType.availability.kind === "unavailable";
51128
+ const disabled = !canRequestTicketOption(ticketType.availability);
51199
51129
  const availabilityLabel = getTicketTypeAvailabilityLabel(ticketType);
51200
51130
  const ticketTypeRemainingLabel = formatTicketTypeRemaining(ticketType.availability.remainingPlaces);
51201
51131
  const priceLabel = ticketType.priceAmount > 0 ? formatPrice(ticketType.priceAmount, props.currency) : "Free";
51202
51132
  const maxAllowed = disabled ? 0 : getTicketTypeLineMax({
51203
51133
  currentQuantity: quantity,
51204
51134
  totalSelectedQuantity,
51205
- maxTickets: props.maxTickets,
51206
- availableSpots: props.availableSpots,
51207
- ticketTypeRemainingCapacity: ticketType.availability.remainingPlaces
51135
+ maxTickets: props.maxTickets
51208
51136
  });
51209
51137
  return /* @__PURE__ */ jsxs("div", {
51210
51138
  className: `er-ticket-line${disabled ? " er-ticket-line--disabled" : ""}`,
@@ -51309,33 +51237,13 @@ function AttendanceModeTiles(props) {
51309
51237
  })
51310
51238
  });
51311
51239
  }
51312
- function getMaxAllowedTicketCount(input) {
51313
- if (input.canJoinWaitlist) return input.maxTickets;
51314
- if (!input.usesTicketTypes) return Math.min(input.maxTickets, input.availableSpots ?? input.maxTickets);
51315
- if (!input.hasSelectedTicketType) return 1;
51316
- return Math.max(1, Math.min(input.maxTickets, input.selectedTicketTypeRemainingCapacity ?? input.maxTickets, input.availableSpots ?? input.maxTickets));
51317
- }
51318
51240
  function resolveTicketSelectionPricing(event) {
51319
51241
  return {
51320
51242
  mode: event ? publicEventPricingStrategy(event.pricing) : void 0,
51321
51243
  currency: event ? publicEventPricingCurrency(event.pricing) : null
51322
51244
  };
51323
51245
  }
51324
- function CheckoutRecoveryEntry(props) {
51325
- return props.onContinue ? /* @__PURE__ */ jsx("button", {
51326
- type: "button",
51327
- className: "er-back-btn",
51328
- onClick: props.onContinue,
51329
- children: "Continue an existing booking"
51330
- }) : null;
51331
- }
51332
- function getTicketSelectionCapacity(event, attendanceMode, checkoutRecovery) {
51333
- if (checkoutRecovery) return {
51334
- availableSpots: null,
51335
- isSoldOut: false,
51336
- canJoinWaitlist: false,
51337
- eventAvailabilityLabel: null
51338
- };
51246
+ function getTicketSelectionCapacity(event, attendanceMode) {
51339
51247
  const source = event ? selectEventCapacitySource(event, attendanceMode) : null;
51340
51248
  const availability = source ? getEventAvailability(source) : null;
51341
51249
  const canJoinWaitlist = source ? canJoinEventWaitlist(source) : false;
@@ -51352,29 +51260,21 @@ var init_TicketSelectionStep = __esmMin((() => {
51352
51260
  init_domain();
51353
51261
  init_utils();
51354
51262
  init_ticketSelectionLines();
51355
- 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 }) => {
51263
+ TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, selectedAttendanceMode = null, onAttendanceModeChange, ticketsCount, maxTickets, visibleTicketTypes: visibleTicketTypesOverride, ticketSelections = [], onTicketSelectionsChange, slidingScale = null, selectedSlidingAmountInput = "", slidingScaleSelectionMessage = null, onSlidingAmountChange, onTicketsChange, bookingUnit = { kind: "ticket" } }) => {
51356
51264
  const unit = bookingUnit.kind;
51357
51265
  const deliveryMode = event?.deliveryMode ?? "in_person";
51358
51266
  const attendanceModes = event?.attendanceModes ?? [];
51359
- const { availableSpots, isSoldOut, canJoinWaitlist, eventAvailabilityLabel } = getTicketSelectionCapacity(event, selectedAttendanceMode, checkoutRecovery);
51267
+ const { availableSpots, isSoldOut, canJoinWaitlist, eventAvailabilityLabel } = getTicketSelectionCapacity(event, selectedAttendanceMode);
51360
51268
  const { mode: eventPricingMode, currency: eventPricingCurrency } = resolveTicketSelectionPricing(event);
51361
- const usesTicketTypes = eventPricingMode === "tiered" && !canJoinWaitlist;
51269
+ const usesTicketTypes = eventPricingMode === "tiered";
51362
51270
  const visibleTicketTypes = usesTicketTypes ? visibleTicketTypesOverride ?? getVisibleTicketTypes({
51363
51271
  event,
51364
51272
  eligibility: null,
51365
51273
  selectedAttendanceMode
51366
51274
  }) : [];
51367
- const implicitTicketType = usesTicketTypes ? getImplicitSingleAvailableTicketType(visibleTicketTypes) : null;
51368
51275
  const noVisibleTicketTypes = usesTicketTypes && visibleTicketTypes.length === 0;
51369
- const hasAvailableTicketTypes = usesTicketTypes && visibleTicketTypes.some((ticketType) => ticketType.availability.kind === "available");
51370
- const maxAllowed = getMaxAllowedTicketCount({
51371
- canJoinWaitlist,
51372
- usesTicketTypes,
51373
- maxTickets,
51374
- availableSpots,
51375
- selectedTicketTypeRemainingCapacity: implicitTicketType?.availability.remainingPlaces ?? null,
51376
- hasSelectedTicketType: implicitTicketType !== null
51377
- });
51276
+ const hasAvailableTicketTypes = usesTicketTypes && visibleTicketTypes.some((ticketType) => canRequestTicketOption(ticketType.availability));
51277
+ const maxAllowed = maxTickets;
51378
51278
  if (deliveryMode === "hybrid" && !selectedAttendanceMode) return /* @__PURE__ */ jsxs("div", {
51379
51279
  className: "rb-reg-stack er-stack",
51380
51280
  children: [
@@ -51393,20 +51293,6 @@ var init_TicketSelectionStep = __esmMin((() => {
51393
51293
  })
51394
51294
  ]
51395
51295
  });
51396
- if (isSoldOut && !canJoinWaitlist) return /* @__PURE__ */ jsxs("div", {
51397
- className: "rb-reg-stack er-stack",
51398
- children: [
51399
- /* @__PURE__ */ jsx("h3", {
51400
- className: "er-title",
51401
- children: "Sold out"
51402
- }),
51403
- /* @__PURE__ */ jsx("p", {
51404
- className: "er-text er-text--muted",
51405
- children: "Sorry you missed out! This event is fully booked."
51406
- }),
51407
- /* @__PURE__ */ jsx(CheckoutRecoveryEntry, { onContinue: onCheckoutRecovery })
51408
- ]
51409
- });
51410
51296
  if (!eventPricingCurrency) return /* @__PURE__ */ jsx("div", {
51411
51297
  className: "rb-reg-stack er-stack",
51412
51298
  children: /* @__PURE__ */ jsx("p", {
@@ -51473,14 +51359,14 @@ var init_TicketSelectionStep = __esmMin((() => {
51473
51359
  })]
51474
51360
  })
51475
51361
  ] }),
51476
- canJoinWaitlist && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("p", {
51362
+ isSoldOut && !canJoinWaitlist && /* @__PURE__ */ jsx("p", {
51477
51363
  className: "er-text er-text--muted",
51478
- children: "This event is currently full. Continue to join the waitlist if a place opens up."
51479
- }), /* @__PURE__ */ jsx(CheckoutRecoveryEntry, { onContinue: onCheckoutRecovery })] }),
51480
- checkoutRecovery && /* @__PURE__ */ jsx("p", {
51364
+ children: "This event is fully booked."
51365
+ }),
51366
+ canJoinWaitlist && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("p", {
51481
51367
  className: "er-text er-text--muted",
51482
- children: "Enter the details from your earlier booking. We’ll check your checkout before continuing to payment."
51483
- })
51368
+ children: "This event is currently full. Continue to join the waitlist if a place opens up."
51369
+ }) })
51484
51370
  ]
51485
51371
  });
51486
51372
  };
@@ -106425,7 +106311,7 @@ var init_PaymentSelectionStep = __esmMin((() => {
106425
106311
  const occurrenceId = occurrenceContext?.id ?? (event?.registrationSubject.kind === "occurrence" ? event.registrationSubject.occurrenceId : "");
106426
106312
  const selectedMethod = selectedSelection.method;
106427
106313
  const totalPrice = directPaymentTotalCents;
106428
- const canShowDirectPaymentOptions = Boolean(eligibility?.eligible && eligibility.canPayDirectly && eligibility.price);
106314
+ const canShowDirectPaymentOptions = Boolean(eligibility?.requiresPayment && eligibility.price);
106429
106315
  const directPaymentOptions = eligibility && canShowDirectPaymentOptions ? buildEventRegistrationPaymentOptionsViewModel({
106430
106316
  eventTitle: event?.title ?? "Event",
106431
106317
  approvedPaymentOptions: eligibility.paymentOptions,
@@ -106488,7 +106374,7 @@ var init_PaymentSelectionStep = __esmMin((() => {
106488
106374
  onRequestLogin
106489
106375
  });
106490
106376
  if (eligibilityLoading || eligibilityError || !eligibility) return blockingPanel;
106491
- if (eligibility.isFree || !eligibility.eligible) return blockingPanel;
106377
+ if (eligibility.isFree || paymentStepStatus !== "ready") return blockingPanel;
106492
106378
  const isMultiTicket = areEntitlementsDisabledForTicketCount(ticketsCount);
106493
106379
  return /* @__PURE__ */ jsxs("div", {
106494
106380
  className: "rb-reg-stack er-stack",
@@ -106707,7 +106593,7 @@ var init_VerifyingTimeoutStep = __esmMin((() => {
106707
106593
  title,
106708
106594
  body: /* @__PURE__ */ jsx("p", {
106709
106595
  className: "er-text--muted er-message",
106710
- children: message
106596
+ 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."
106711
106597
  }),
106712
106598
  actionsClassName: "er-button-group",
106713
106599
  actions: onCheckAgain ? /* @__PURE__ */ jsx("button", {
@@ -106715,11 +106601,7 @@ var init_VerifyingTimeoutStep = __esmMin((() => {
106715
106601
  onClick: onCheckAgain,
106716
106602
  className: "er-btn er-btn--primary",
106717
106603
  children: "Check payment status"
106718
- }) : /* @__PURE__ */ jsx("a", {
106719
- href: "/portal",
106720
- className: "er-btn er-btn--primary",
106721
- children: "Check payment status"
106722
- }),
106604
+ }) : void 0,
106723
106605
  secondaryBody: supportEmail ? /* @__PURE__ */ jsxs("p", {
106724
106606
  className: "er-text--sm er-text--muted er-message",
106725
106607
  children: [
@@ -106909,6 +106791,7 @@ function EventRegistrationWizardContent(props) {
106909
106791
  case "redirecting":
106910
106792
  case "verifying-payment":
106911
106793
  case "verifying-timeout":
106794
+ case "payment-status":
106912
106795
  case "payment-failed": return null;
106913
106796
  case "select-event": return /* @__PURE__ */ jsx(EventSelectionStep, {
106914
106797
  events: wizard.scopedEvents,
@@ -106924,8 +106807,6 @@ function EventRegistrationWizardContent(props) {
106924
106807
  onBookForSomeoneElse: wizard.handleBookForSomeoneElse
106925
106808
  }), /* @__PURE__ */ jsx(TicketSelectionStep, {
106926
106809
  event: wizard.selectedEvent,
106927
- checkoutRecovery: wizard.checkoutRecovery,
106928
- onCheckoutRecovery: canRecoverEventCheckout(wizard.selectedEvent) ? wizard.startCheckoutRecovery : void 0,
106929
106810
  occurrenceContext: wizard.occurrenceContext,
106930
106811
  selectedAttendanceMode: wizard.selectedAttendanceMode,
106931
106812
  onAttendanceModeChange: wizard.setSelectedAttendanceMode,
@@ -106953,13 +106834,90 @@ var init_EventRegistrationWizardContent = __esmMin((() => {
106953
106834
  init_client();
106954
106835
  init_src();
106955
106836
  init_shared();
106956
- init_checkoutRecovery();
106957
106837
  init_registrationStateMachine();
106958
106838
  init_siteCreditPreview();
106959
106839
  init_PaymentBlockingPanel();
106960
106840
  init_event_registration();
106961
106841
  }));
106962
106842
  //#endregion
106843
+ //#region ../blocks/src/system/runtime/nodes/event-registration/PaymentStatusStep.tsx
106844
+ function presentation(state) {
106845
+ switch (state.kind) {
106846
+ case "ready": return {
106847
+ title: "We haven’t confirmed your payment yet",
106848
+ 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.",
106849
+ action: { label: "Check payment status" }
106850
+ };
106851
+ case "checking": return {
106852
+ title: "We haven’t confirmed your payment yet",
106853
+ 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.",
106854
+ action: {
106855
+ label: "Checking payment…",
106856
+ disabled: true
106857
+ }
106858
+ };
106859
+ case "processing": return {
106860
+ title: "Your payment is still being processed",
106861
+ message: "Please don’t make another payment. You can check its status again in a moment.",
106862
+ action: { label: "Check payment status" }
106863
+ };
106864
+ case "paymentAvailable": return {
106865
+ title: "Your payment hasn’t been completed",
106866
+ message: "Your booking details are still saved. Continue to payment to finish your booking.",
106867
+ action: { label: "Continue to payment" }
106868
+ };
106869
+ case "retryAvailable": return {
106870
+ title: "Continue your booking",
106871
+ message: "You can return to payment. We’ll check your booking, any existing payment and availability before starting another checkout.",
106872
+ action: { label: "Return to payment" }
106873
+ };
106874
+ case "temporarilyUnavailable": return {
106875
+ title: "We couldn’t check your payment",
106876
+ message: "Please don’t make another payment yet. Try checking again in a moment.",
106877
+ action: { label: "Check payment status" }
106878
+ };
106879
+ case "assistanceRequired": return {
106880
+ title: "We still can’t confirm your payment",
106881
+ message: "Please don’t make another payment. Contact the organiser so they can check your booking.",
106882
+ action: { label: "Return to booking" }
106883
+ };
106884
+ }
106885
+ }
106886
+ function PaymentStatusStep(props) {
106887
+ const view = presentation(props.state);
106888
+ const onClick = props.state.kind === "paymentAvailable" ? props.onContinuePayment : props.state.kind === "retryAvailable" ? props.onReturnToPayment : props.state.kind === "assistanceRequired" ? props.onReturnToBooking : props.onCheck;
106889
+ return /* @__PURE__ */ jsx(TerminalPanel, {
106890
+ tone: "warning",
106891
+ className: "er-center",
106892
+ titleClassName: "er-title--lg er-message",
106893
+ icon: /* @__PURE__ */ jsx(StateIcon, {
106894
+ variant: "warning",
106895
+ children: /* @__PURE__ */ jsx(ClockIcon, {})
106896
+ }),
106897
+ title: view.title,
106898
+ body: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("p", {
106899
+ className: "er-text--muted er-message",
106900
+ children: view.message
106901
+ }), /* @__PURE__ */ jsx("span", {
106902
+ className: "rb-sr-only",
106903
+ "aria-live": "polite",
106904
+ "aria-atomic": "true",
106905
+ children: props.state.kind === "checking" ? "Checking payment…" : view.title
106906
+ })] }),
106907
+ actionsClassName: "er-button-group",
106908
+ actions: view.action ? /* @__PURE__ */ jsx("button", {
106909
+ type: "button",
106910
+ onClick,
106911
+ disabled: view.action.disabled,
106912
+ className: "er-btn er-btn--primary",
106913
+ children: /* @__PURE__ */ jsx("span", { children: view.action.label })
106914
+ }) : void 0
106915
+ });
106916
+ }
106917
+ var init_PaymentStatusStep = __esmMin((() => {
106918
+ init_shared();
106919
+ }));
106920
+ //#endregion
106963
106921
  //#region ../blocks/src/system/runtime/nodes/event-registration/EventRegistrationSurface.tsx
106964
106922
  function EventPortalAuthPrompt(props) {
106965
106923
  return /* @__PURE__ */ jsxs("div", {
@@ -107044,6 +107002,13 @@ function EventRegistrationTerminalState(props) {
107044
107002
  message: wizard.verification.status === "timeout" ? void 0 : wizard.errorMessage,
107045
107003
  supportEmail: props.supportEmail
107046
107004
  });
107005
+ case "payment-status": return wizard.paymentStatusRecovery ? /* @__PURE__ */ jsx(PaymentStatusStep, {
107006
+ state: wizard.paymentStatusRecovery,
107007
+ onCheck: wizard.handleCheckPaymentStatus,
107008
+ onContinuePayment: wizard.handleContinueExistingPayment,
107009
+ onReturnToPayment: wizard.handleReturnToPayment,
107010
+ onReturnToBooking: wizard.handleReturnToBooking
107011
+ }) : null;
107047
107012
  case "success": return wizard.registrationResult ? /* @__PURE__ */ jsx(SuccessStep, {
107048
107013
  title: wizard.registrationResult.title,
107049
107014
  variant: wizard.registrationResult.variant,
@@ -107052,7 +107017,7 @@ function EventRegistrationTerminalState(props) {
107052
107017
  case "error": return /* @__PURE__ */ jsx(ErrorStep, {
107053
107018
  message: wizard.errorMessage,
107054
107019
  action: wizard.errorAction,
107055
- canJoinWaitlist: wizard.eligibility?.isFull && wizard.eligibility.canJoinWaitlist,
107020
+ canJoinWaitlist: wizard.eligibility?.availability.kind === "waitlist" && wizard.eligibility.registration.kind !== "pending_payment",
107056
107021
  onRetry: wizard.handleRetry
107057
107022
  });
107058
107023
  case "select-event":
@@ -107114,6 +107079,7 @@ var init_EventRegistrationSurface = __esmMin((() => {
107114
107079
  init_EventRegistrationWizardActions();
107115
107080
  init_EventRegistrationWizardContent();
107116
107081
  init_PaymentFailedStep();
107082
+ init_PaymentStatusStep();
107117
107083
  init_StepIndicator();
107118
107084
  init_SuccessStep();
107119
107085
  init_VerifyingPaymentStep();
@@ -107251,6 +107217,7 @@ function getWizardStepLabel(input) {
107251
107217
  case "redirecting":
107252
107218
  case "verifying-payment":
107253
107219
  case "verifying-timeout":
107220
+ case "payment-status":
107254
107221
  case "payment-failed": return "";
107255
107222
  }
107256
107223
  }