@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
@@ -32751,6 +32751,18 @@ var init_wizardSteps$1 = __esmMin((() => {
32751
32751
  }));
32752
32752
  //#endregion
32753
32753
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
32754
+ /** Public requests share subject identity without copying the run's display sessions. */
32755
+ function toRegistrationRequestSubject(subject, attendanceMode) {
32756
+ return subject.kind === "occurrence" ? {
32757
+ kind: "occurrence",
32758
+ occurrenceId: subject.occurrenceId,
32759
+ attendanceMode: attendanceMode ?? void 0
32760
+ } : {
32761
+ kind: "wholeSeries",
32762
+ eventSeriesId: subject.eventSeriesId,
32763
+ attendanceMode: attendanceMode ?? void 0
32764
+ };
32765
+ }
32754
32766
  function eventMatchesOccurrenceId(event, occurrenceId) {
32755
32767
  return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
32756
32768
  }
@@ -32980,6 +32992,7 @@ function shellLabelForRegistrationStep(step, events) {
32980
32992
  case "redirecting":
32981
32993
  case "verifying-payment":
32982
32994
  case "verifying-timeout":
32995
+ case "payment-status":
32983
32996
  case "payment-failed": return "Details";
32984
32997
  }
32985
32998
  }
@@ -92471,6 +92484,10 @@ var init_endpoints = __esmMin((() => {
92471
92484
  method: "POST",
92472
92485
  authScope: "portal"
92473
92486
  },
92487
+ registrationNextStep: {
92488
+ path: "/public/sites/{siteId}/events/registration-next-step",
92489
+ method: "POST"
92490
+ },
92474
92491
  registrationStatus: {
92475
92492
  path: "/public/sites/{siteId}/events/registration-status",
92476
92493
  method: "GET"
@@ -93053,6 +93070,13 @@ function createBlockApi(config) {
93053
93070
  body: data
93054
93071
  });
93055
93072
  },
93073
+ async checkRegistrationNextStep(data) {
93074
+ const path = buildPath(EVENTS.registrationNextStep.path, { siteId: requireSiteId() });
93075
+ return request(EVENTS.registrationNextStep, {
93076
+ path,
93077
+ body: data
93078
+ });
93079
+ },
93056
93080
  async getEventRegistrationStatus(params) {
93057
93081
  const sid = requireSiteId();
93058
93082
  const path = buildPath(EVENTS.registrationStatus.path, { siteId: sid });
@@ -101217,7 +101241,7 @@ var init_eventPaymentOptions = __esmMin((() => {
101217
101241
  //#endregion
101218
101242
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationStateMachine.ts
101219
101243
  function hasBlockingExistingRegistration(input) {
101220
- return !input.hasWaitlistClaim && input.isAuthenticated && input.registration.kind !== "none";
101244
+ return !input.hasWaitlistClaim && input.isAuthenticated && input.registration.kind === "waitlisted";
101221
101245
  }
101222
101246
  function createInitialRegistrationFlowState(hasPreSelectedContext) {
101223
101247
  return {
@@ -101269,7 +101293,7 @@ function computeAutoSelection(input) {
101269
101293
  return { method: null };
101270
101294
  }
101271
101295
  function computeDirectPaymentSelection(eligibility) {
101272
- if (!eligibility?.canPayDirectly) return { method: null };
101296
+ if (!eligibility?.requiresPayment) return { method: null };
101273
101297
  const approvedKinds = getApprovedDirectPaymentCollectionOptionKinds(eligibility.paymentOptions);
101274
101298
  const collectionOptionKind = approvedKinds.includes("upfront") ? "upfront" : approvedKinds[0];
101275
101299
  return collectionOptionKind ? {
@@ -101283,7 +101307,7 @@ function isSelectionValid(input) {
101283
101307
  if (!eligibility) return selection.method === "stripe" || selection.method === "pass_bundle" || selection.method === "membership_bundle";
101284
101308
  switch (selection.method) {
101285
101309
  case "free": return eligibility.isFree;
101286
- case "stripe": return Boolean(eligibility.canPayDirectly && eligibility.price);
101310
+ case "stripe": return Boolean(eligibility.requiresPayment && eligibility.price);
101287
101311
  case "pass": return isAuthenticated && ticketsCount === 1 && !!selection.passId && eligibility.eligiblePasses.some((pass) => pass.id === selection.passId);
101288
101312
  case "membership": return isAuthenticated && ticketsCount === 1 && !!selection.membershipId && eligibility.eligibleMemberships.some((membership) => membership.id === selection.membershipId);
101289
101313
  case "pass_bundle": return ticketsCount === 1 && !!selection.bundlePassId && eligibility.availablePasses.some((pass) => pass.id === selection.bundlePassId);
@@ -101302,7 +101326,7 @@ function normalizeRegistrationFlowState(state) {
101302
101326
  ticketsCount: state.ticketsCount,
101303
101327
  passOptOut: nextPassOptOut
101304
101328
  });
101305
- const canKeepManualSelection = state.step === "select-payment" && state.selectionSource === "manual" && isSelectionValid({
101329
+ const canKeepManualSelection = state.step !== "select-tickets" && state.selectionSource === "manual" && isSelectionValid({
101306
101330
  selection: state.paymentSelection,
101307
101331
  isAuthenticated: state.isAuthenticated,
101308
101332
  eligibility: state.eligibility,
@@ -101394,7 +101418,7 @@ function resolveEventRegistrationSubmitPlan(input) {
101394
101418
  const selection = input.paymentSelection.method ? input.paymentSelection : void 0;
101395
101419
  if (input.canJoinWaitlist) return {
101396
101420
  ok: true,
101397
- args: withOptionalSelection({ method: "free" }, selection)
101421
+ args: { method: "free" }
101398
101422
  };
101399
101423
  switch (input.paymentSelection.method) {
101400
101424
  case "pass": return input.paymentSelection.passId ? {
@@ -101463,92 +101487,55 @@ var init_event_registration_headless_state = __esmMin((() => {
101463
101487
  init_event_registration_headless_planning();
101464
101488
  }));
101465
101489
  //#endregion
101466
- //#region ../blocks/src/system/runtime/nodes/event-registration/checkoutRecovery.ts
101467
- /** Recovery may select held places; checkout still owns admission and payment validation. */
101468
- function checkoutRecoveryOptionAvailability(availability) {
101469
- if (availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable") return {
101470
- kind: "available",
101471
- remainingPlaces: null
101472
- };
101473
- return availability;
101490
+ //#region ../blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.ts
101491
+ /** Ticket selection requests a quote; only the server admits a booking. */
101492
+ function canRequestTicketOption(availability) {
101493
+ return availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable";
101474
101494
  }
101475
- /**
101476
- * A form-only projection for the explicit existing-checkout path. It permits
101477
- * collecting the original selection without claiming a new place is available.
101478
- * The public checkout service identifies the customer and remains the admission
101479
- * authority; no reservation/customer data is exposed through this projection.
101480
- */
101481
- function getCheckoutRecoveryFormEligibility(eligibility) {
101482
- 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;
101483
- const amountCents = eligibility.price ?? 0;
101484
- if (amountCents <= 0 || !eligibility.currency || eligibility.availability.kind === "unavailable" && eligibility.availability.reason === "selectionRequired") return eligibility.registration.kind === "pending_payment" ? {
101485
- ...eligibility,
101486
- registration: { kind: "none" },
101487
- ticketTypes: eligibility.ticketTypes.map((option) => ({
101488
- ...option,
101489
- availability: checkoutRecoveryOptionAvailability(option.availability)
101490
- }))
101491
- } : eligibility;
101492
- const currency = eligibility.currency;
101493
- const paymentOptions = eligibility.paymentTerms.allowedOptions.map((option) => {
101494
- switch (option.kind) {
101495
- case "upfront": return {
101496
- kind: "payInFull",
101497
- amountCents,
101498
- currency
101499
- };
101500
- case "deferred_manual": return {
101501
- kind: "deferredManual",
101502
- amountCents,
101503
- currency
101504
- };
101505
- case "instalment_plan": return {
101506
- kind: "instalmentPlan",
101507
- amountCents,
101508
- currency
101509
- };
101510
- case "flexible_balance": return {
101511
- kind: "flexibleBalance",
101512
- amountCents,
101513
- currency
101514
- };
101515
- }
101516
- });
101517
- return {
101518
- ...eligibility,
101519
- registration: { kind: "none" },
101520
- availability: {
101521
- kind: "available",
101522
- remainingPlaces: null,
101523
- waitlistEnabled: eligibility.waitlistEnabled
101524
- },
101525
- eligible: paymentOptions.length > 0,
101526
- isFull: false,
101527
- canJoinWaitlist: false,
101528
- isFree: false,
101529
- requiresPayment: true,
101530
- canPayDirectly: paymentOptions.length > 0,
101531
- paymentOptions,
101532
- eligiblePasses: [],
101533
- eligibleMemberships: [],
101534
- ticketTypes: eligibility.ticketTypes.map((option) => ({
101535
- ...option,
101536
- availability: checkoutRecoveryOptionAvailability(option.availability)
101537
- }))
101538
- };
101495
+ function normalizeTicketSelectionLines(lines) {
101496
+ const quantitiesByTicketType = /* @__PURE__ */ new Map();
101497
+ for (const line of lines) {
101498
+ const quantity = Math.floor(line.quantity);
101499
+ if (quantity <= 0) continue;
101500
+ const key = line.pricingOptionId ?? null;
101501
+ quantitiesByTicketType.set(key, (quantitiesByTicketType.get(key) ?? 0) + quantity);
101502
+ }
101503
+ return [...quantitiesByTicketType.entries()].map(([pricingOptionId, quantity]) => ({
101504
+ pricingOptionId,
101505
+ quantity
101506
+ }));
101507
+ }
101508
+ function getTicketSelectionTotal(lines) {
101509
+ return normalizeTicketSelectionLines(lines).reduce((total, line) => total + line.quantity, 0);
101539
101510
  }
101540
- function isSoldOutEventSelectable(event, waitlistAvailable) {
101541
- return waitlistAvailable || canRecoverEventCheckout(event);
101511
+ function getTicketLineQuantity(lines, pricingOptionId) {
101512
+ return normalizeTicketSelectionLines(lines).find((line) => line.pricingOptionId === pricingOptionId)?.quantity ?? 0;
101542
101513
  }
101543
- function canJoinWaitlistOutsideRecovery(event, attendanceMode, checkoutRecovery) {
101544
- return !checkoutRecovery && event !== null && canJoinEventWaitlist(event, { attendanceMode });
101514
+ function getSingleSelectedPricingOptionId(lines) {
101515
+ const normalized = normalizeTicketSelectionLines(lines);
101516
+ return normalized.length === 1 ? normalized[0]?.pricingOptionId ?? null : null;
101545
101517
  }
101546
- function canRecoverEventCheckout(event) {
101547
- return event !== null && (event.registrationSubject.kind === "wholeSeries" || event.pricing.kind !== "free" && event.pricing.kind !== "external");
101518
+ function hasValidPricingOptionSelection(input) {
101519
+ if (!input.selectionRequired) return true;
101520
+ if (input.lines.length === 0) return false;
101521
+ const availableOptionIds = new Set(input.visibleOptions.filter((option) => canRequestTicketOption(option.availability)).map((option) => option.pricingOptionId));
101522
+ return input.lines.every((line) => line.pricingOptionId !== null && availableOptionIds.has(line.pricingOptionId));
101548
101523
  }
101549
- var init_checkoutRecovery = __esmMin((() => {
101550
- init_domain();
101551
- }));
101524
+ function setTicketLineQuantity(input) {
101525
+ const nextQuantity = Math.max(0, Math.floor(input.quantity));
101526
+ const normalized = normalizeTicketSelectionLines(input.lines).filter((line) => line.pricingOptionId !== input.pricingOptionId);
101527
+ if (nextQuantity <= 0) return normalized;
101528
+ return [...normalized, {
101529
+ pricingOptionId: input.pricingOptionId,
101530
+ quantity: nextQuantity
101531
+ }];
101532
+ }
101533
+ function getTicketTypeLineMax(input) {
101534
+ const otherSelectedQuantity = input.totalSelectedQuantity - input.currentQuantity;
101535
+ const maxByBlock = input.maxTickets - otherSelectedQuantity;
101536
+ return Math.max(0, maxByBlock);
101537
+ }
101538
+ var init_ticketSelectionLines = __esmMin((() => {}));
101552
101539
  //#endregion
101553
101540
  //#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
101554
101541
  function getPortalSubjectEmail(profile) {
@@ -101612,8 +101599,6 @@ function formatPassCreditUsageLabel(creditsRemaining) {
101612
101599
  return `Uses 1 of ${creditsRemaining} credits`;
101613
101600
  }
101614
101601
  function transformRegistrationOptionsResponse(response) {
101615
- const canJoinWaitlist = response.availability.kind === "waitlist";
101616
- const isFull = response.availability.remainingPlaces === 0 || response.availability.kind === "unavailable" && response.availability.reason === "full";
101617
101602
  const eligiblePasses = response.entitlements.passes.map((pass) => ({
101618
101603
  id: pass.customerPassId,
101619
101604
  passName: pass.passName,
@@ -101626,7 +101611,6 @@ function transformRegistrationOptionsResponse(response) {
101626
101611
  const eventAcceptsPasses = response.entitlements.requiresLoginForPasses || eligiblePasses.length > 0 || response.entitlements.availableForPurchase.passes.length > 0;
101627
101612
  const eventAcceptsMemberships = response.entitlements.requiresLoginForMemberships || eligibleMemberships.length > 0 || response.entitlements.availableForPurchase.memberships.length > 0;
101628
101613
  const monetaryPaymentAvailable = hasMonetaryPaymentOption(response);
101629
- const registrationAvailable = response.availability.kind === "available" || response.availability.kind === "waitlist";
101630
101614
  return {
101631
101615
  availability: response.availability,
101632
101616
  registration: response.registration,
@@ -101641,7 +101625,6 @@ function transformRegistrationOptionsResponse(response) {
101641
101625
  },
101642
101626
  transactions: []
101643
101627
  } : null,
101644
- eligible: response.registration.kind === "none" && registrationAvailable,
101645
101628
  requiresPayment: monetaryPaymentAvailable,
101646
101629
  pricingStrategy: response.pricing.strategy,
101647
101630
  paymentTerms: response.pricing.paymentTerms,
@@ -101656,16 +101639,12 @@ function transformRegistrationOptionsResponse(response) {
101656
101639
  currency: response.pricing.currency
101657
101640
  })),
101658
101641
  ticketTypes: response.pricing.options,
101659
- isFull,
101660
- waitlistEnabled: response.availability.waitlistEnabled,
101661
- canJoinWaitlist,
101662
101642
  price: response.pricing.subtotalCents,
101663
101643
  currency: response.pricing.currency,
101664
101644
  requiresAuthForPasses: response.entitlements.requiresLoginForPasses,
101665
101645
  requiresAuthForMemberships: response.entitlements.requiresLoginForMemberships,
101666
101646
  eligiblePasses,
101667
101647
  eligibleMemberships,
101668
- canPayDirectly: monetaryPaymentAvailable,
101669
101648
  eventAcceptsPasses,
101670
101649
  eventAcceptsMemberships,
101671
101650
  availablePasses: [...response.entitlements.availableForPurchase.passes],
@@ -101695,8 +101674,8 @@ function getVisibleTicketTypes(input) {
101695
101674
  })) : [];
101696
101675
  return (input.eligibility?.ticketTypes ?? eventTicketTypes).filter((ticketType) => ticketType.isActive && (!input.selectedAttendanceMode || (ticketType.attendanceScope ?? "both") === "both" || (ticketType.attendanceScope ?? "both") === input.selectedAttendanceMode));
101697
101676
  }
101698
- function getImplicitSingleAvailableTicketType(ticketTypes) {
101699
- return ticketTypes.length === 1 && ticketTypes[0]?.availability.kind === "available" ? ticketTypes[0] : null;
101677
+ function getImplicitSingleTicketType(ticketTypes) {
101678
+ return ticketTypes.length === 1 && ticketTypes[0] && canRequestTicketOption(ticketTypes[0].availability) ? ticketTypes[0] : null;
101700
101679
  }
101701
101680
  function findSelectedTicketType(input) {
101702
101681
  if (!input.selectedPricingOptionId) return null;
@@ -101709,6 +101688,7 @@ function findSelectedTicketType(input) {
101709
101688
  var ENTITLEMENT_SINGLE_TICKET_TOOLTIP;
101710
101689
  var init_utils = __esmMin((() => {
101711
101690
  init_src$2();
101691
+ init_ticketSelectionLines();
101712
101692
  init_shared();
101713
101693
  ENTITLEMENT_SINGLE_TICKET_TOOLTIP = "Only available for single-ticket bookings";
101714
101694
  }));
@@ -101721,7 +101701,6 @@ function getEventSelectionMode(events) {
101721
101701
  }
101722
101702
  var EventSelectionStep;
101723
101703
  var init_EventSelectionStep = __esmMin((() => {
101724
- init_checkoutRecovery();
101725
101704
  init_utils();
101726
101705
  init_domain();
101727
101706
  EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCapacity }) => {
@@ -101738,25 +101717,19 @@ var init_EventSelectionStep = __esmMin((() => {
101738
101717
  const remaining = getRemainingPlaces(selectMostOpenCapacitySource(event));
101739
101718
  const isSoldOut = isEventFull(event);
101740
101719
  const canJoinWaitlist = canJoinEventWaitlistOnAnyMode(event);
101741
- const isUnavailable = isSoldOut && !isSoldOutEventSelectable(event, canJoinWaitlist);
101742
101720
  const isLowCapacity = remaining.kind === "low";
101743
101721
  const capacityLabel = formatEventRemainingPlaces(event, { full: "Sold out" });
101744
101722
  const timeZone = event.timeZone ?? null;
101745
- const cardClasses = [
101746
- "er-event-card",
101747
- isSelected && "er-event-card--selected",
101748
- isUnavailable && "er-event-card--disabled"
101749
- ].filter(Boolean).join(" ");
101723
+ const cardClasses = ["er-event-card", isSelected && "er-event-card--selected"].filter(Boolean).join(" ");
101750
101724
  const badgeClasses = [
101751
101725
  "er-capacity-badge",
101752
- isUnavailable && "er-capacity-badge--soldout",
101726
+ isSoldOut && "er-capacity-badge--soldout",
101753
101727
  isLowCapacity && "er-capacity-badge--low",
101754
- (canJoinWaitlist || !isUnavailable && !isLowCapacity) && "er-capacity-badge--available"
101728
+ (canJoinWaitlist || !isSoldOut && !isLowCapacity) && "er-capacity-badge--available"
101755
101729
  ].filter(Boolean).join(" ");
101756
101730
  return /* @__PURE__ */ jsx("button", {
101757
101731
  type: "button",
101758
- onClick: () => !isUnavailable && onSelect(event),
101759
- disabled: isUnavailable,
101732
+ onClick: () => onSelect(event),
101760
101733
  className: cardClasses,
101761
101734
  children: /* @__PURE__ */ jsxs("div", {
101762
101735
  className: "er-event-option",
@@ -101784,44 +101757,15 @@ var init_EventSelectionStep = __esmMin((() => {
101784
101757
  };
101785
101758
  }));
101786
101759
  //#endregion
101787
- //#region ../blocks/src/system/runtime/nodes/event-registration/useCheckoutRecovery.ts
101788
- /** Recovery belongs to the selected booking subject; changing events resets its scope. */
101789
- function useCheckoutRecovery(event, setStep) {
101790
- const [recoveryEventId, setRecoveryEventId] = useState(null);
101791
- return {
101792
- checkoutRecovery: event !== null && recoveryEventId === event.selectionId,
101793
- startCheckoutRecovery: useCallback(() => {
101794
- if (!event) return;
101795
- setRecoveryEventId(event.selectionId);
101796
- setStep("select-tickets");
101797
- }, [event, setStep])
101798
- };
101799
- }
101800
- /** Authenticated pending bookings enter the same form-only recovery path as guests. */
101801
- function useCheckoutRecoveryEligibility(eligibility, step, checkoutRecovery, startCheckoutRecovery) {
101802
- const registrationKind = eligibility?.registration.kind;
101803
- useEffect(() => {
101804
- if ((step === "select-event" || step === "select-tickets" || step === "enter-details" || step === "select-payment") && registrationKind === "pending_payment" && !checkoutRecovery) startCheckoutRecovery();
101805
- }, [
101806
- registrationKind,
101807
- step,
101808
- checkoutRecovery,
101809
- startCheckoutRecovery
101810
- ]);
101811
- return useMemo(() => checkoutRecovery ? getCheckoutRecoveryFormEligibility(eligibility) : eligibility, [checkoutRecovery, eligibility]);
101812
- }
101813
- var init_useCheckoutRecovery = __esmMin((() => {
101814
- init_checkoutRecovery();
101815
- }));
101816
- //#endregion
101817
101760
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.ts
101818
101761
  function resolveRegistrationRecoveryAction(step, action) {
101819
101762
  if (step === "payment-failed") return "payment-options";
101820
- if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "payment-status";
101763
+ if (step === "payment-status") return "none";
101764
+ if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "none";
101821
101765
  return action;
101822
101766
  }
101823
101767
  function canRecoverToWaitlist(eligibility) {
101824
- return Boolean(eligibility?.isFull && eligibility.canJoinWaitlist);
101768
+ return eligibility?.availability.kind === "waitlist" && eligibility.registration.kind !== "pending_payment";
101825
101769
  }
101826
101770
  function shouldRefreshAfterRegistrationError(step, action, enabled) {
101827
101771
  return enabled || step === "error" && action === "places";
@@ -101838,19 +101782,19 @@ function resetRegistrationAfterExpiry(input) {
101838
101782
  input.setErrorMessage("");
101839
101783
  input.setPendingRegistrationReference(null);
101840
101784
  }
101841
- /** Recovery never starts another payment. Unknown payment outcomes go to the portal. */
101785
+ /** Retry the retained submission in place; explicit payment uncertainty stays status-only. */
101842
101786
  function recoverRegistrationError(action, handlers) {
101843
101787
  switch (action) {
101844
101788
  case "none": return;
101845
101789
  case "portal":
101846
- case "payment-status":
101847
101790
  window.location.assign("/portal");
101848
101791
  return;
101849
101792
  case "event":
101850
101793
  window.location.assign(window.location.pathname);
101851
101794
  return;
101852
101795
  case "retry":
101853
- window.location.reload();
101796
+ handlers.clearError();
101797
+ handlers.setStep("select-payment");
101854
101798
  return;
101855
101799
  case "details":
101856
101800
  handlers.clearError();
@@ -101890,54 +101834,6 @@ function validateFormData(formData, requiresConsent = false) {
101890
101834
  }
101891
101835
  var init_validation = __esmMin((() => {}));
101892
101836
  //#endregion
101893
- //#region ../blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.ts
101894
- function normalizeTicketSelectionLines(lines) {
101895
- const quantitiesByTicketType = /* @__PURE__ */ new Map();
101896
- for (const line of lines) {
101897
- const quantity = Math.floor(line.quantity);
101898
- if (quantity <= 0) continue;
101899
- const key = line.pricingOptionId ?? null;
101900
- quantitiesByTicketType.set(key, (quantitiesByTicketType.get(key) ?? 0) + quantity);
101901
- }
101902
- return [...quantitiesByTicketType.entries()].map(([pricingOptionId, quantity]) => ({
101903
- pricingOptionId,
101904
- quantity
101905
- }));
101906
- }
101907
- function getTicketSelectionTotal(lines) {
101908
- return normalizeTicketSelectionLines(lines).reduce((total, line) => total + line.quantity, 0);
101909
- }
101910
- function getTicketLineQuantity(lines, pricingOptionId) {
101911
- return normalizeTicketSelectionLines(lines).find((line) => line.pricingOptionId === pricingOptionId)?.quantity ?? 0;
101912
- }
101913
- function getSingleSelectedPricingOptionId(lines) {
101914
- const normalized = normalizeTicketSelectionLines(lines);
101915
- return normalized.length === 1 ? normalized[0]?.pricingOptionId ?? null : null;
101916
- }
101917
- function hasValidPricingOptionSelection(input) {
101918
- if (!input.selectionRequired) return true;
101919
- if (input.lines.length === 0) return false;
101920
- const availableOptionIds = new Set(input.visibleOptions.filter((option) => option.availability.kind === "available").map((option) => option.pricingOptionId));
101921
- return input.lines.every((line) => line.pricingOptionId !== null && availableOptionIds.has(line.pricingOptionId));
101922
- }
101923
- function setTicketLineQuantity(input) {
101924
- const nextQuantity = Math.max(0, Math.floor(input.quantity));
101925
- const normalized = normalizeTicketSelectionLines(input.lines).filter((line) => line.pricingOptionId !== input.pricingOptionId);
101926
- if (nextQuantity <= 0) return normalized;
101927
- return [...normalized, {
101928
- pricingOptionId: input.pricingOptionId,
101929
- quantity: nextQuantity
101930
- }];
101931
- }
101932
- function getTicketTypeLineMax(input) {
101933
- const otherSelectedQuantity = input.totalSelectedQuantity - input.currentQuantity;
101934
- const maxByBlock = input.maxTickets - otherSelectedQuantity;
101935
- const maxByEvent = input.availableSpots == null ? input.maxTickets : input.availableSpots - otherSelectedQuantity;
101936
- const maxByTicketType = input.ticketTypeRemainingCapacity ?? input.maxTickets;
101937
- return Math.max(0, Math.min(maxByBlock, maxByEvent, maxByTicketType));
101938
- }
101939
- var init_ticketSelectionLines = __esmMin((() => {}));
101940
- //#endregion
101941
101837
  //#region ../blocks/src/system/runtime/nodes/event-registration/hooks.state.ts
101942
101838
  function eligibilityLookupReducer(state, action) {
101943
101839
  switch (action.type) {
@@ -102049,17 +101945,6 @@ function usePortalAuthWithDeps(deps) {
102049
101945
  logout
102050
101946
  };
102051
101947
  }
102052
- function toRegistrationOptionsSubject(subject, attendanceMode) {
102053
- return subject.kind === "occurrence" ? {
102054
- kind: "occurrence",
102055
- occurrenceId: subject.occurrenceId,
102056
- attendanceMode: attendanceMode ?? void 0
102057
- } : {
102058
- kind: "wholeSeries",
102059
- eventSeriesId: subject.eventSeriesId,
102060
- attendanceMode: attendanceMode ?? void 0
102061
- };
102062
- }
102063
101948
  function useEligibility(params) {
102064
101949
  return useEligibilityWithDeps(params, eventRegistrationHooksDeps);
102065
101950
  }
@@ -102100,7 +101985,7 @@ function useEligibilityWithDeps(params, deps) {
102100
101985
  requestIdRef.current = requestId;
102101
101986
  dispatch({ type: "loading-started" });
102102
101987
  try {
102103
- const subject = toRegistrationOptionsSubject(params.subject, params.attendanceMode);
101988
+ const subject = toRegistrationRequestSubject(params.subject, params.attendanceMode);
102104
101989
  const result = await api.getRegistrationOptions({
102105
101990
  subject,
102106
101991
  selections: ticketSelections.map((selection) => ({
@@ -102222,6 +102107,7 @@ var init_hooks = __esmMin((() => {
102222
102107
  init_api();
102223
102108
  init_utils();
102224
102109
  init_ticketSelectionLines();
102110
+ init_registrationDerivations();
102225
102111
  init_hooks_state();
102226
102112
  eventRegistrationHooksDeps = { useBlockApi };
102227
102113
  REGISTRATION_OPTIONS_DEBOUNCE_MS = 150;
@@ -102688,7 +102574,6 @@ var init_stripeMinimumCharge = __esmMin((() => {
102688
102574
  var init_stripeCheckoutReturnUrl = __esmMin((() => {}));
102689
102575
  var init_stateTransitions = __esmMin((() => {
102690
102576
  init_src$2();
102691
- init_assertNever();
102692
102577
  }));
102693
102578
  //#endregion
102694
102579
  //#region ../commerce/src/purchase/event-registration-errors.ts
@@ -102702,9 +102587,9 @@ var init_event_registration_errors = __esmMin((() => {
102702
102587
  message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
102703
102588
  action: "none"
102704
102589
  },
102705
- paymentUncertain: {
102706
- 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.",
102707
- action: "payment-status"
102590
+ paymentInvestigationRequired: {
102591
+ message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
102592
+ action: "none"
102708
102593
  },
102709
102594
  paymentProviderUnavailable: {
102710
102595
  message: "We couldn’t reach the payment provider. Please try again in a minute.",
@@ -102756,6 +102641,7 @@ var init_event_registration_errors = __esmMin((() => {
102756
102641
  }
102757
102642
  };
102758
102643
  }));
102644
+ var init_eventCheckoutRecoveryWindow = __esmMin((() => {}));
102759
102645
  //#endregion
102760
102646
  //#region ../commerce/src/purchase/index.ts
102761
102647
  var init_purchase = __esmMin((() => {
@@ -102817,6 +102703,7 @@ var init_purchase = __esmMin((() => {
102817
102703
  init_stripeCheckoutReturnUrl();
102818
102704
  init_stateTransitions();
102819
102705
  init_event_registration_errors();
102706
+ init_eventCheckoutRecoveryWindow();
102820
102707
  init_stripeCommissionMetadata();
102821
102708
  }));
102822
102709
  //#endregion
@@ -103262,7 +103149,30 @@ function checkoutReturnCommand(params) {
103262
103149
  };
103263
103150
  return null;
103264
103151
  }
103265
- async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
103152
+ function handleCheckoutReturnOutcome(options, deps, context, outcome) {
103153
+ const { pending, params } = context;
103154
+ if (outcome.kind === "resolved") {
103155
+ deps.clearReturnParams();
103156
+ options.setPendingRegistrationReference(outcome.reference);
103157
+ options.setStep("verifying-payment");
103158
+ return "settled";
103159
+ }
103160
+ if (outcome.kind === "abandoned") {
103161
+ deps.clearReturnParams();
103162
+ options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
103163
+ options.setStep("select-payment");
103164
+ return "settled";
103165
+ }
103166
+ if (outcome.kind === "notFound" && params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
103167
+ deps.clearReturnParams();
103168
+ options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
103169
+ options.setStep("select-payment");
103170
+ return "settled";
103171
+ }
103172
+ 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.");
103173
+ return outcome.kind === "notFound" ? "settled" : "retryable";
103174
+ }
103175
+ async function handleCheckoutReturn(options, deps, returnContextRef) {
103266
103176
  deps.cleanupStaleRegistrations();
103267
103177
  const params = deps.readReturnParams();
103268
103178
  if (params.registration !== "cancelled" && params.registration !== "success") return "settled";
@@ -103276,34 +103186,15 @@ async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
103276
103186
  }
103277
103187
  const { checkoutAttemptId } = command;
103278
103188
  const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
103279
- checkoutAttemptIdRef.current = checkoutAttemptId;
103189
+ returnContextRef.current = { checkoutAttemptId };
103280
103190
  if (pending) restorePendingPresentation(options, pending);
103281
103191
  options.setStep("verifying-payment");
103282
103192
  try {
103283
103193
  const outcome = await options.api.resolveEventCheckoutReturn(command);
103284
- switch (outcome.kind) {
103285
- case "resolved":
103286
- deps.clearReturnParams();
103287
- options.setPendingRegistrationReference(outcome.reference);
103288
- options.setStep("verifying-payment");
103289
- return "settled";
103290
- case "abandoned":
103291
- deps.clearReturnParams();
103292
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
103293
- options.setStep("select-payment");
103294
- return "settled";
103295
- case "notFound":
103296
- if (params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
103297
- deps.clearReturnParams();
103298
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
103299
- options.setStep("select-payment");
103300
- return "settled";
103301
- }
103302
- 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.");
103303
- return "settled";
103304
- case "reconciliationRequired": break;
103305
- }
103306
- 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.");
103194
+ return handleCheckoutReturnOutcome(options, deps, {
103195
+ pending,
103196
+ params
103197
+ }, outcome);
103307
103198
  } catch {
103308
103199
  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.");
103309
103200
  }
@@ -103312,9 +103203,16 @@ async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
103312
103203
  function useEventRegistrationStripeReturn(options) {
103313
103204
  return useEventRegistrationStripeReturnWithDeps(options, eventRegistrationStripeReturnDeps);
103314
103205
  }
103206
+ function completeVerifiedRegistration(options, deps, returnContext) {
103207
+ const siteId = options.api.config.siteId;
103208
+ const checkoutAttemptId = returnContext?.checkoutAttemptId;
103209
+ if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
103210
+ options.setRegistrationResult({ status: "confirmed" });
103211
+ options.setStep("success");
103212
+ }
103315
103213
  function useEventRegistrationStripeReturnWithDeps(options, deps) {
103316
103214
  const { api, pendingRegistrationReference, setErrorMessage, setRegistrationResult, setStep, step } = options;
103317
- const checkoutAttemptIdRef = useRef(null);
103215
+ const returnContextRef = useRef(null);
103318
103216
  const lookupInFlightRef = useRef(false);
103319
103217
  const [lookupState, setLookupState] = useState("settled");
103320
103218
  const resolveReturn = useCallback(async () => {
@@ -103322,7 +103220,7 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
103322
103220
  lookupInFlightRef.current = true;
103323
103221
  setLookupState("loading");
103324
103222
  try {
103325
- setLookupState(await handleCheckoutReturn(options, deps, checkoutAttemptIdRef));
103223
+ setLookupState(await handleCheckoutReturn(options, deps, returnContextRef));
103326
103224
  } finally {
103327
103225
  lookupInFlightRef.current = false;
103328
103226
  }
@@ -103345,13 +103243,8 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
103345
103243
  resolveReturn();
103346
103244
  }, []);
103347
103245
  useEffect(() => {
103348
- if (verification.status === "completed") {
103349
- const siteId = api.config.siteId;
103350
- const checkoutAttemptId = checkoutAttemptIdRef.current;
103351
- if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
103352
- setRegistrationResult({ status: "confirmed" });
103353
- setStep("success");
103354
- } else if (verification.status === "failed") {
103246
+ if (verification.status === "completed") completeVerifiedRegistration(options, deps, returnContextRef.current);
103247
+ else if (verification.status === "failed") {
103355
103248
  setErrorMessage("Please try again or choose another payment option. If this keeps happening, contact the organiser for help.");
103356
103249
  setStep("payment-failed");
103357
103250
  } else if (verification.status === "timeout") setStep("verifying-timeout");
@@ -103410,7 +103303,10 @@ function registrationErrorPresentation(error) {
103410
103303
  const reason = error instanceof BlockApiError ? parseEventRegistrationErrorReason(error.tag) : null;
103411
103304
  if (reason) return eventRegistrationErrors[reason];
103412
103305
  if (error instanceof BlockApiError && error.status < 500) return eventRegistrationErrors.invalidCommitInput;
103413
- return eventRegistrationErrors.paymentUncertain;
103306
+ return {
103307
+ message: "Something went wrong. Please try again.",
103308
+ action: "retry"
103309
+ };
103414
103310
  }
103415
103311
  var init_registrationErrorPresentation = __esmMin((() => {
103416
103312
  init_purchase();
@@ -103439,26 +103335,6 @@ function useEventRegistrationSubmit(options) {
103439
103335
  * and the balance left, which the block's copy cannot. Every other method keeps
103440
103336
  * whatever success message the site configured.
103441
103337
  */
103442
- function toRegistrationResult(result) {
103443
- if (result.alreadyRegistered) {
103444
- const waitlisted = result.status === "waitlist";
103445
- return {
103446
- status: result.status,
103447
- variant: "info",
103448
- title: waitlisted ? "Already waitlisted" : "Already registered",
103449
- message: result.message ?? (waitlisted ? "You are already on the waitlist for this event." : "You are already registered for this event.")
103450
- };
103451
- }
103452
- if (result.status === "waitlist") return {
103453
- status: "waitlist",
103454
- title: "Added to waitlist",
103455
- message: result.message ?? (typeof result.waitlistPosition === "number" ? `You've been added to the waitlist (position ${result.waitlistPosition}).` : "You've been added to the waitlist.")
103456
- };
103457
- return {
103458
- status: result.status,
103459
- message: result.paymentMethod === "pass" ? result.message : void 0
103460
- };
103461
- }
103462
103338
  function useEventRegistrationSubmitWithDeps(options, deps) {
103463
103339
  /**
103464
103340
  * The command identity for the submission currently in progress.
@@ -103472,7 +103348,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
103472
103348
  * Identical retries retain the command after a lost response. Changed form
103473
103349
  * details get a new command so the server applies the new booking intent.
103474
103350
  */
103475
- const commandRef = useRef(null);
103351
+ const { commandRef } = options;
103476
103352
  const inFlightRef = useRef(null);
103477
103353
  const submit = async (method, passId, membershipId, selection, submitOptions) => {
103478
103354
  const target = options.registrationTarget;
@@ -103485,19 +103361,15 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
103485
103361
  const registrationCommandId = commandRef.current?.id ?? deps.createClientCommandId();
103486
103362
  try {
103487
103363
  let prepared = prepareSubmitContext(options, registrationCommandId, target, method, passId, membershipId, selection);
103488
- if (prepared.subject.kind === "wholeSeries" && method === "stripe") {
103489
- commandRef.current = null;
103490
- return await submitWholeSeriesCheckout(options, deps, {
103364
+ let request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
103365
+ const intentKey = registrationRequestIntentKey(request);
103366
+ if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) {
103367
+ prepared = {
103491
103368
  ...prepared,
103492
- subject: prepared.subject
103493
- }, submitOptions);
103369
+ registrationCommandId: deps.createClientCommandId()
103370
+ };
103371
+ request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
103494
103372
  }
103495
- const request = buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId);
103496
- const intentKey = registrationRequestIntentKey(request);
103497
- if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) prepared = {
103498
- ...prepared,
103499
- registrationCommandId: deps.createClientCommandId()
103500
- };
103501
103373
  commandRef.current = {
103502
103374
  id: prepared.registrationCommandId,
103503
103375
  intentKey
@@ -103506,8 +103378,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
103506
103378
  ...request,
103507
103379
  registrationCommandId: prepared.registrationCommandId
103508
103380
  });
103509
- commandRef.current = null;
103510
- return await completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions);
103381
+ return await completeRegistrationSubmission(options, deps, prepared, result, submitOptions);
103511
103382
  } catch (error) {
103512
103383
  if (error instanceof BlockApiError && error.tag === "registrationPreparationChanged") commandRef.current = null;
103513
103384
  const { message, action } = registrationErrorPresentation(error);
@@ -103531,9 +103402,40 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
103531
103402
  return pending;
103532
103403
  };
103533
103404
  }
103534
- async function completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions) {
103535
- if (needsOccurrenceCheckout(result, method)) return await submitOccurrenceCheckout(options, deps, prepared, result, method, submitOptions);
103536
- options.setRegistrationResult(toRegistrationResult(result));
103405
+ async function completeRegistrationSubmission(options, deps, prepared, result, submitOptions) {
103406
+ switch (result.kind) {
103407
+ case "paymentStatusRequired":
103408
+ options.setPaymentStatusRecovery({
103409
+ kind: "ready",
103410
+ subject: result.subject
103411
+ });
103412
+ options.setStep("payment-status");
103413
+ return {
103414
+ ok: true,
103415
+ outcome: { kind: "payment_status" }
103416
+ };
103417
+ case "checkoutRequired":
103418
+ options.setPendingRegistrationReference(result.reference);
103419
+ savePendingCheckout(options, deps, prepared, result.submissionId, result.reference);
103420
+ options.setStep("redirecting");
103421
+ return redirectToCheckout(result.checkoutUrl, submitOptions);
103422
+ case "waitlisted":
103423
+ options.setRegistrationResult({
103424
+ status: "waitlist",
103425
+ title: "Added to waitlist",
103426
+ message: result.waitlist.message
103427
+ });
103428
+ break;
103429
+ case "bookingComplete":
103430
+ case "paymentDeferred":
103431
+ options.setPendingRegistrationReference(result.reference);
103432
+ options.setRegistrationResult({
103433
+ status: "confirmed",
103434
+ message: result.summary.paymentMethod === "pass" ? result.summary.message : void 0
103435
+ });
103436
+ break;
103437
+ }
103438
+ options.commandRef.current = null;
103537
103439
  options.setStep("success");
103538
103440
  return {
103539
103441
  ok: true,
@@ -103564,15 +103466,7 @@ function prepareSubmitContext(options, registrationCommandId, target, method, pa
103564
103466
  email: guest.email?.trim().toLowerCase() || void 0,
103565
103467
  phone: guest.phone?.trim() || void 0
103566
103468
  })) : void 0,
103567
- subject: target.subject.kind === "occurrence" ? {
103568
- kind: "occurrence",
103569
- occurrenceId: target.subject.occurrenceId,
103570
- attendanceMode: options.selectedAttendanceMode ?? void 0
103571
- } : {
103572
- kind: "wholeSeries",
103573
- eventSeriesId: target.subject.eventSeriesId,
103574
- attendanceMode: options.selectedAttendanceMode ?? void 0
103575
- }
103469
+ subject: toRegistrationRequestSubject(target.subject, options.selectedAttendanceMode)
103576
103470
  };
103577
103471
  }
103578
103472
  function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId, selection) {
@@ -103596,85 +103490,6 @@ function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId,
103596
103490
  if (method === "free") return { method };
103597
103491
  throw new Error("Choose an available payment option.");
103598
103492
  }
103599
- async function submitWholeSeriesCheckout(options, deps, prepared, submitOptions) {
103600
- options.setStep("redirecting");
103601
- if (prepared.selectionSnapshot.method !== "stripe") throw new Error("Choose an available payment option.");
103602
- const checkoutAttemptId = deps.createClientCommandId();
103603
- const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
103604
- const result = await options.api.createEventCheckout({
103605
- subject: prepared.subject,
103606
- ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
103607
- selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
103608
- email: options.formData.email.trim().toLowerCase(),
103609
- name: options.formData.name.trim(),
103610
- phone: options.formData.phone.trim() || void 0,
103611
- formData: options.formData,
103612
- consentAccepted: options.formData.consentAccepted,
103613
- altchaSolution: options.altchaSolution,
103614
- guests: prepared.guestsPayload,
103615
- claimToken: options.claimToken ?? void 0,
103616
- waitlistEntryId: options.waitlistEntryId ?? void 0,
103617
- discountCode: options.discountCode.trim() || void 0,
103618
- collectionOptionKind: prepared.selectionSnapshot.collectionOptionKind,
103619
- checkoutAttemptId,
103620
- ...urls
103621
- });
103622
- if (result.scope !== "wholeSeries") throw new Error("Unexpected registration scope for event checkout.");
103623
- if ("waitlistEntryId" in result) {
103624
- options.setRegistrationResult({
103625
- status: "waitlist",
103626
- variant: result.alreadyRegistered ? "info" : void 0,
103627
- title: result.alreadyRegistered ? "Already waitlisted" : "Added to waitlist",
103628
- message: result.alreadyRegistered ? "You are already on the waitlist for this event." : "You've been added to the waitlist."
103629
- });
103630
- options.setStep("success");
103631
- return {
103632
- ok: true,
103633
- outcome: { kind: "completed" }
103634
- };
103635
- }
103636
- if (result.bypassed) return completeBypassedCheckout(options);
103637
- if (!result.checkoutUrl) throw new Error("Checkout URL missing");
103638
- savePendingCheckout(options, deps, prepared, result.checkoutAttemptId, {
103639
- scope: "wholeSeries",
103640
- registrationId: result.registrationId
103641
- });
103642
- return redirectToCheckout(result.checkoutUrl, submitOptions);
103643
- }
103644
- function needsOccurrenceCheckout(result, method) {
103645
- return result.scope === "occurrence" && result.status === "confirmed" && result.pendingPayment && [
103646
- "stripe",
103647
- "pass_bundle",
103648
- "membership_bundle"
103649
- ].includes(method);
103650
- }
103651
- async function submitOccurrenceCheckout(options, deps, prepared, registration, method, submitOptions) {
103652
- const reference = {
103653
- scope: "occurrence",
103654
- attendeeId: registration.attendeeId
103655
- };
103656
- options.setPendingRegistrationReference(reference);
103657
- options.setStep("redirecting");
103658
- const checkoutAttemptId = deps.createClientCommandId();
103659
- const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
103660
- const result = await options.api.createEventCheckout({
103661
- subject: {
103662
- kind: "occurrence",
103663
- attendeeId: registration.attendeeId
103664
- },
103665
- registrationCommandId: prepared.registrationCommandId,
103666
- checkoutType: method === "pass_bundle" ? "pass_bundle" : method === "membership_bundle" ? "membership_bundle" : "event",
103667
- productId: prepared.bundleProductId,
103668
- discountCode: options.discountCode.trim() || void 0,
103669
- collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0,
103670
- ...urls
103671
- });
103672
- if (result.scope !== "occurrence") throw new Error("Unexpected registration scope for event checkout.");
103673
- if (result.bypassed) return completeBypassedCheckout(options);
103674
- if (!result.checkoutUrl) throw new Error("Checkout URL missing");
103675
- if (prepared.subject.kind === "occurrence") savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference);
103676
- return redirectToCheckout(result.checkoutUrl, submitOptions);
103677
- }
103678
103493
  function savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference) {
103679
103494
  const siteId = options.api.config.siteId;
103680
103495
  if (!siteId) return;
@@ -103687,14 +103502,6 @@ function savePendingCheckout(options, deps, prepared, checkoutAttemptId, referen
103687
103502
  paymentSelection: prepared.selectionSnapshot
103688
103503
  });
103689
103504
  }
103690
- function completeBypassedCheckout(options) {
103691
- options.setRegistrationResult({ status: "confirmed" });
103692
- options.setStep("success");
103693
- return {
103694
- ok: true,
103695
- outcome: { kind: "completed" }
103696
- };
103697
- }
103698
103505
  function redirectToCheckout(checkoutUrl, submitOptions) {
103699
103506
  if (submitOptions?.redirect !== "manual") window.location.href = checkoutUrl;
103700
103507
  return {
@@ -103706,12 +103513,23 @@ function redirectToCheckout(checkoutUrl, submitOptions) {
103706
103513
  };
103707
103514
  }
103708
103515
  function registrationRequestIntentKey(request) {
103709
- const { registrationCommandId: _command, altchaSolution: _proof, ...intent } = request;
103710
- return JSON.stringify(intent);
103516
+ const { registrationCommandId: _command, altchaSolution: _proof, checkout, ...intent } = request;
103517
+ return JSON.stringify({
103518
+ ...intent,
103519
+ checkout: checkout ? {
103520
+ discountCode: checkout.discountCode,
103521
+ collectionOptionKind: checkout.collectionOptionKind
103522
+ } : void 0
103523
+ });
103711
103524
  }
103712
- function buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId) {
103525
+ function buildRegistrationRequest(options, prepared, method, passId, membershipId) {
103713
103526
  return {
103714
103527
  registrationCommandId: prepared.registrationCommandId,
103528
+ checkout: {
103529
+ ...buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: prepared.registrationCommandId }),
103530
+ discountCode: options.discountCode.trim() || void 0,
103531
+ collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0
103532
+ },
103715
103533
  subject: prepared.subject,
103716
103534
  ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
103717
103535
  selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
@@ -103736,6 +103554,7 @@ var init_useEventRegistrationSubmit = __esmMin((() => {
103736
103554
  init_shared();
103737
103555
  init_registrationErrorPresentation();
103738
103556
  init_constants();
103557
+ init_registrationDerivations();
103739
103558
  init_sessionStorage();
103740
103559
  init_ticketSelectionLines();
103741
103560
  eventRegistrationSubmitDeps = {
@@ -103953,23 +103772,128 @@ var init_useWaitlistClaimRestoration = __esmMin((() => {
103953
103772
  }));
103954
103773
  //#endregion
103955
103774
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationCompletion.ts
103775
+ function isSelectionSoldOut(availability) {
103776
+ return availability?.kind === "unavailable" && availability.reason === "full";
103777
+ }
103956
103778
  function resolveRegistrationAvailabilityBlocker(input) {
103957
103779
  if (input.hasWaitlistClaim) return null;
103958
103780
  if (input.eligibilityError) return input.eligibilityError;
103959
103781
  if (!input.eligibility) return "Registration is not available for this event.";
103782
+ if (input.eligibility.registration.kind === "pending_payment") return null;
103783
+ if (isSelectionSoldOut(input.eligibility.availability)) return null;
103960
103784
  if (input.eligibility.availability.kind === "unavailable" && input.eligibility.availability.reason === "paymentUnavailable") return "Payment options are not available for this event.";
103961
- if (input.eligibility.availability.kind === "unavailable" || !input.eligibility.eligible) return "Registration is not available for this event.";
103785
+ if (input.eligibility.availability.kind === "unavailable" || input.eligibility.registration.kind === "waitlisted") return "Registration is not available for this event.";
103962
103786
  return null;
103963
103787
  }
103964
103788
  function resolvePricingSelectionBlocker(input) {
103965
103789
  if (input.selectionRequired && !input.hasValidSelection) return "Choose at least one available ticket to continue.";
103966
103790
  return input.slidingScaleSelectionMessage;
103967
103791
  }
103968
- function isSoldOutWithoutWaitlist(input) {
103969
- return Boolean(!input.hasWaitlistClaim && input.eligibility?.isFull && !input.eligibility.canJoinWaitlist);
103970
- }
103971
103792
  var init_registrationCompletion = __esmMin((() => {}));
103972
103793
  //#endregion
103794
+ //#region ../blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.ts
103795
+ function isCheckableRecovery(state) {
103796
+ return state.kind === "ready" || state.kind === "processing" || state.kind === "temporarilyUnavailable";
103797
+ }
103798
+ function assistanceRequired(recovery) {
103799
+ return {
103800
+ kind: "assistanceRequired",
103801
+ subject: recovery.subject
103802
+ };
103803
+ }
103804
+ function applyStatusOutcome(outcome, recovery, setters, setRecovery) {
103805
+ if (outcome.kind === "resolved") {
103806
+ setters.setPendingRegistrationReference(outcome.reference);
103807
+ setters.setRegistrationResult({ status: "confirmed" });
103808
+ setRecovery(null);
103809
+ setters.setStep("success");
103810
+ return;
103811
+ }
103812
+ switch (outcome.kind) {
103813
+ case "paymentProcessing":
103814
+ setRecovery({
103815
+ ...recovery,
103816
+ kind: "processing"
103817
+ });
103818
+ return;
103819
+ case "paymentAvailable":
103820
+ setRecovery({
103821
+ ...recovery,
103822
+ kind: "paymentAvailable",
103823
+ checkoutUrl: outcome.checkoutUrl
103824
+ });
103825
+ return;
103826
+ case "paymentCheckUnavailable":
103827
+ setRecovery({
103828
+ ...recovery,
103829
+ kind: "temporarilyUnavailable"
103830
+ });
103831
+ return;
103832
+ case "paymentRetryAvailable":
103833
+ setRecovery({
103834
+ ...recovery,
103835
+ kind: "retryAvailable"
103836
+ });
103837
+ return;
103838
+ case "abandoned":
103839
+ case "notFound":
103840
+ case "reconciliationRequired":
103841
+ case "paymentAssistanceRequired":
103842
+ setRecovery(assistanceRequired(recovery));
103843
+ return;
103844
+ }
103845
+ }
103846
+ function usePaymentStatusRecovery(options) {
103847
+ const [recovery, setRecovery] = useState(null);
103848
+ const checkRef = useRef(null);
103849
+ return {
103850
+ recovery,
103851
+ showRecovery: useCallback((next) => setRecovery(next), []),
103852
+ check: useCallback(() => {
103853
+ if (!recovery || !isCheckableRecovery(recovery) || checkRef.current) return;
103854
+ const pending = (async () => {
103855
+ setRecovery({
103856
+ ...recovery,
103857
+ kind: "checking"
103858
+ });
103859
+ try {
103860
+ applyStatusOutcome(await options.api.resolveEventCheckoutReturn({
103861
+ kind: "checkStatus",
103862
+ subject: recovery.subject
103863
+ }), recovery, options, setRecovery);
103864
+ } catch {
103865
+ setRecovery({
103866
+ ...recovery,
103867
+ kind: "temporarilyUnavailable"
103868
+ });
103869
+ }
103870
+ })();
103871
+ checkRef.current = pending;
103872
+ pending.finally(() => {
103873
+ if (checkRef.current === pending) checkRef.current = null;
103874
+ });
103875
+ }, [options, recovery]),
103876
+ continuePayment: useCallback(() => {
103877
+ if (recovery?.kind === "paymentAvailable") window.location.assign(recovery.checkoutUrl);
103878
+ }, [recovery]),
103879
+ returnToPayment: useCallback(() => {
103880
+ if (recovery?.kind !== "retryAvailable") return;
103881
+ options.beginNewSubmission();
103882
+ setRecovery(null);
103883
+ options.setOptionsRefreshKey((value) => value + 1);
103884
+ options.setStep("select-payment");
103885
+ }, [options, recovery]),
103886
+ returnToBooking: useCallback(() => {
103887
+ if (recovery?.kind !== "assistanceRequired") return;
103888
+ options.beginNewSubmission();
103889
+ setRecovery(null);
103890
+ options.setOptionsRefreshKey((value) => value + 1);
103891
+ options.setStep("select-tickets");
103892
+ }, [options, recovery])
103893
+ };
103894
+ }
103895
+ var init_usePaymentStatusRecovery = __esmMin((() => {}));
103896
+ //#endregion
103973
103897
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
103974
103898
  function usesTieredPricing(event) {
103975
103899
  return event !== null && event !== void 0 ? publicEventPricingStrategy(event.pricing) === "tiered" : false;
@@ -104016,6 +103940,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104016
103940
  const [errorAction, setErrorAction] = useState("retry");
104017
103941
  const [optionsRefreshKey, setOptionsRefreshKey] = useState(0);
104018
103942
  const [altchaSolution, setAltchaSolution] = useState(null);
103943
+ const [checkingNextStep, setCheckingNextStep] = useState(false);
104019
103944
  const { authState: portalAuthState, profile: portalProfile } = deps.usePortalAuth();
104020
103945
  const waitlistClaim = deps.useWaitlistClaim();
104021
103946
  const [showMagicLinkModal, setShowMagicLinkModal] = useState(false);
@@ -104042,28 +103967,29 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104042
103967
  }), [options.occurrenceContext, selectedEvent]);
104043
103968
  const registrationOccurrenceId = getRegistrationOccurrenceId(registrationTarget);
104044
103969
  const currentEvent = selectedEvent ?? preSelectedEvent;
103970
+ const commandRef = useRef(null);
104045
103971
  const setStep = useCallback((nextStep) => {
104046
103972
  dispatchFlow({
104047
103973
  type: "set-step",
104048
103974
  step: nextStep
104049
103975
  });
104050
103976
  }, []);
104051
- const { checkoutRecovery, startCheckoutRecovery } = useCheckoutRecovery(currentEvent, setStep);
104052
- const currentEventUsesTicketTypes = usesTieredPricing(currentEvent);
104053
- const currentCanJoinWaitlist = canJoinWaitlistOutsideRecovery(currentEvent, selectedAttendanceMode, checkoutRecovery);
104054
- const usesTicketTypeSelections = currentEventUsesTicketTypes && !currentCanJoinWaitlist;
103977
+ const { recovery: paymentStatusRecovery, showRecovery: setPaymentStatusRecovery, check: handleCheckPaymentStatus, continuePayment: handleContinueExistingPayment, returnToPayment: handleReturnToPayment, returnToBooking: handleReturnToBooking } = usePaymentStatusRecovery({
103978
+ api,
103979
+ beginNewSubmission: () => {
103980
+ commandRef.current = null;
103981
+ },
103982
+ setPendingRegistrationReference,
103983
+ setRegistrationResult,
103984
+ setOptionsRefreshKey,
103985
+ setStep
103986
+ });
103987
+ const usesTicketTypeSelections = usesTieredPricing(currentEvent);
104055
103988
  const eventTicketTypesForSelection = useMemo(() => getVisibleTicketTypes({
104056
103989
  event: currentEvent,
104057
103990
  eligibility: null,
104058
103991
  selectedAttendanceMode
104059
- }).map((option) => checkoutRecovery ? {
104060
- ...option,
104061
- availability: checkoutRecoveryOptionAvailability(option.availability)
104062
- } : option), [
104063
- currentEvent,
104064
- selectedAttendanceMode,
104065
- checkoutRecovery
104066
- ]);
103992
+ }), [currentEvent, selectedAttendanceMode]);
104067
103993
  const normalizedSelectedTicketLines = useMemo(() => normalizeTicketSelectionLines(selectedTicketLines), [selectedTicketLines]);
104068
103994
  const ticketTypeSelectionTotal = useMemo(() => getTicketSelectionTotal(normalizedSelectedTicketLines), [normalizedSelectedTicketLines]);
104069
103995
  const ticketsCount = usesTicketTypeSelections ? ticketTypeSelectionTotal : flowState.ticketsCount;
@@ -104101,7 +104027,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104101
104027
  isAuthenticated: portalAuthState === "authenticated",
104102
104028
  occurrenceId: registrationOccurrenceId
104103
104029
  });
104104
- const eligibility = useCheckoutRecoveryEligibility(eligibilityResult.eligibility, step, checkoutRecovery, startCheckoutRecovery);
104030
+ const eligibility = eligibilityResult.eligibility;
104105
104031
  const eligibilityLoading = eligibilityResult.isLoading;
104106
104032
  const eligibilityError = eligibilityResult.error;
104107
104033
  const portalCreditState = eligibilityResult.creditState;
@@ -104213,14 +104139,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104213
104139
  event: currentEvent,
104214
104140
  eligibility,
104215
104141
  selectedAttendanceMode
104216
- }).map((option) => checkoutRecovery ? {
104217
- ...option,
104218
- availability: checkoutRecoveryOptionAvailability(option.availability)
104219
- } : option), [
104142
+ }), [
104220
104143
  currentEvent,
104221
104144
  selectedAttendanceMode,
104222
- eligibility,
104223
- checkoutRecovery
104145
+ eligibility
104224
104146
  ]);
104225
104147
  const singleSelectedPricingOptionId = getSingleSelectedPricingOptionId(normalizedSelectedTicketLines);
104226
104148
  const selectedTicketType = useMemo(() => findSelectedTicketType({
@@ -104244,12 +104166,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104244
104166
  const event = currentEvent;
104245
104167
  if (!usesTieredPricing(event)) return false;
104246
104168
  if ((event.deliveryMode ?? "in_person") === "hybrid" && !selectedAttendanceMode) return false;
104247
- return checkoutRecovery || !canJoinEventWaitlist(event, { attendanceMode: selectedAttendanceMode });
104248
- }, [
104249
- currentEvent,
104250
- selectedAttendanceMode,
104251
- checkoutRecovery
104252
- ]);
104169
+ return true;
104170
+ }, [currentEvent, selectedAttendanceMode]);
104253
104171
  const hasValidTicketSelection = hasValidPricingOptionSelection({
104254
104172
  selectionRequired: ticketTypeSelectionRequired,
104255
104173
  lines: normalizedSelectedTicketLines,
@@ -104260,8 +104178,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104260
104178
  if (selectedTicketLines.length > 0) setSelectedTicketLines([]);
104261
104179
  return;
104262
104180
  }
104263
- const availableTicketTypes = eventTicketTypesForSelection.filter((ticketType) => ticketType.availability.kind === "available");
104264
- const implicitTicketType = getImplicitSingleAvailableTicketType(eventTicketTypesForSelection);
104181
+ const availableTicketTypes = eventTicketTypesForSelection.filter((ticketType) => canRequestTicketOption(ticketType.availability));
104182
+ const implicitTicketType = getImplicitSingleTicketType(eventTicketTypesForSelection);
104265
104183
  if (implicitTicketType && normalizedSelectedTicketLines.length === 0) {
104266
104184
  setSelectedTicketLines([{
104267
104185
  pricingOptionId: implicitTicketType.pricingOptionId,
@@ -104328,6 +104246,26 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104328
104246
  selectedEventSlidingScale,
104329
104247
  selectedSlidingAmount
104330
104248
  ]);
104249
+ const checkDetailsNextStep = async () => {
104250
+ if (portalAuthState === "authenticated" || waitlistClaim.claim || eligibility?.availability.kind === "available" || !registrationTarget) return { kind: canRecoverToWaitlist(eligibility) ? "waitlist" : "continue" };
104251
+ setCheckingNextStep(true);
104252
+ try {
104253
+ return await api.checkRegistrationNextStep({
104254
+ subject: toRegistrationRequestSubject(registrationTarget.subject, selectedAttendanceMode),
104255
+ selections: ticketSelections,
104256
+ selectedSlidingAmount: selectedSlidingAmount ?? void 0,
104257
+ email: formData.email,
104258
+ altchaSolution
104259
+ });
104260
+ } catch {
104261
+ return {
104262
+ kind: "unavailable",
104263
+ message: "We could not check availability. Please try again."
104264
+ };
104265
+ } finally {
104266
+ setCheckingNextStep(false);
104267
+ }
104268
+ };
104331
104269
  const handleDetailsComplete = async () => {
104332
104270
  const blockDetailsCompletion = (message) => {
104333
104271
  setErrorAction("places");
@@ -104359,11 +104297,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104359
104297
  message: "Check the highlighted fields and try again."
104360
104298
  };
104361
104299
  }
104362
- if (isSoldOutWithoutWaitlist({
104363
- hasWaitlistClaim: waitlistClaim.claim !== null,
104364
- eligibility
104365
- })) return blockDetailsCompletion("Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.");
104366
- if (!eligibility?.canJoinWaitlist && requiresPaymentStep({
104300
+ const next = await checkDetailsNextStep();
104301
+ if (next.kind === "unavailable") return blockDetailsCompletion(next.message);
104302
+ const canJoinWaitlist = next.kind === "waitlist";
104303
+ if (!canJoinWaitlist && requiresPaymentStep({
104367
104304
  eventRequiresPayment,
104368
104305
  paymentSelection
104369
104306
  })) {
@@ -104376,7 +104313,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104376
104313
  const submitPlan = resolveEventRegistrationSubmitPlan({
104377
104314
  paymentSelection,
104378
104315
  eventRequiresPayment,
104379
- canJoinWaitlist: eligibility?.canJoinWaitlist
104316
+ canJoinWaitlist
104380
104317
  });
104381
104318
  if (!submitPlan.ok) return blockDetailsCompletion(submitPlan.message);
104382
104319
  const submitResult = await handleSubmit(submitPlan.args.method, submitPlan.args.passId, submitPlan.args.membershipId, submitPlan.args.selection);
@@ -104394,7 +104331,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104394
104331
  const submitPlan = resolveEventRegistrationSubmitPlan({
104395
104332
  paymentSelection,
104396
104333
  eventRequiresPayment,
104397
- canJoinWaitlist: eligibility?.canJoinWaitlist
104334
+ canJoinWaitlist: false
104398
104335
  });
104399
104336
  if (!submitPlan.ok) {
104400
104337
  setErrorMessage(submitPlan.message);
@@ -104426,6 +104363,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104426
104363
  const selectionMethod = paymentSelection.method;
104427
104364
  const shouldShowDiscountToggle = discountContext !== null && discountUi.manualCodeEntryAllowed && (selectionMethod === "stripe" || selectionMethod === "pass_bundle" || selectionMethod === "membership_bundle");
104428
104365
  const handleSubmit = deps.useEventRegistrationSubmit({
104366
+ commandRef,
104429
104367
  setErrorAction,
104430
104368
  api,
104431
104369
  registrationTarget,
@@ -104442,7 +104380,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104442
104380
  setPendingRegistrationReference,
104443
104381
  setStep,
104444
104382
  setRegistrationResult: (result) => setRegistrationResult(result),
104445
- setErrorMessage
104383
+ setErrorMessage,
104384
+ setPaymentStatusRecovery
104446
104385
  });
104447
104386
  const handleEventSelect = (event) => {
104448
104387
  setSelectedEvent(event);
@@ -104501,8 +104440,6 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104501
104440
  scopedEvents,
104502
104441
  preSelectedEvent,
104503
104442
  hasPreSelectedContext,
104504
- checkoutRecovery,
104505
- startCheckoutRecovery,
104506
104443
  step,
104507
104444
  setStep,
104508
104445
  selectedEvent,
@@ -104556,7 +104493,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104556
104493
  waitlistClaim,
104557
104494
  eligibility,
104558
104495
  registrationOptionsState: eligibilityResult.state,
104559
- eligibilityLoading,
104496
+ eligibilityLoading: eligibilityLoading || checkingNextStep,
104560
104497
  eligibilityError,
104561
104498
  existingRegistration: existingRegistrationResult.registration,
104562
104499
  existingRegistrationLoading: existingRegistrationResult.isLoading || portalAuthState === "authenticated" && eligibilityLoading,
@@ -104576,6 +104513,11 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104576
104513
  discountContext,
104577
104514
  shouldShowDiscountToggle,
104578
104515
  verification,
104516
+ paymentStatusRecovery,
104517
+ handleCheckPaymentStatus,
104518
+ handleContinueExistingPayment,
104519
+ handleReturnToPayment,
104520
+ handleReturnToBooking,
104579
104521
  handleDetailsComplete,
104580
104522
  handlePaymentSelect,
104581
104523
  handleUseCardInsteadOfPass,
@@ -104587,12 +104529,9 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104587
104529
  }
104588
104530
  var eventRegistrationWizardDeps;
104589
104531
  var init_useEventRegistrationWizard = __esmMin((() => {
104590
- init_checkoutRecovery();
104591
- init_useCheckoutRecovery();
104592
104532
  init_src$2();
104593
104533
  init_registrationErrorRecovery();
104594
104534
  init_api();
104595
- init_domain();
104596
104535
  init_validation();
104597
104536
  init_hooks();
104598
104537
  init_portalLogout();
@@ -104612,6 +104551,7 @@ var init_useEventRegistrationWizard = __esmMin((() => {
104612
104551
  init_waitlistClaimRestoration();
104613
104552
  init_useWaitlistClaimRestoration();
104614
104553
  init_registrationCompletion();
104554
+ init_usePaymentStatusRecovery();
104615
104555
  eventRegistrationWizardDeps = {
104616
104556
  usePortalAuth,
104617
104557
  useEligibility,
@@ -104795,7 +104735,6 @@ var init_ErrorStep = __esmMin((() => {
104795
104735
  start: "Start again",
104796
104736
  details: "Check my details",
104797
104737
  "payment-options": "View payment options",
104798
- "payment-status": "Check payment status",
104799
104738
  portal: "View my bookings",
104800
104739
  event: "View event"
104801
104740
  };
@@ -104814,7 +104753,7 @@ var init_ErrorStep = __esmMin((() => {
104814
104753
  className: "er-text--muted er-message",
104815
104754
  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
104816
104755
  }),
104817
- actions: action === "none" ? void 0 : action === "portal" || action === "payment-status" ? /* @__PURE__ */ jsx("a", {
104756
+ actions: action === "none" ? void 0 : action === "portal" ? /* @__PURE__ */ jsx("a", {
104818
104757
  href: "/portal",
104819
104758
  className: "er-retry-btn",
104820
104759
  children: labels[action]
@@ -105075,8 +105014,11 @@ var init_EventRegistrationSummaryBar = __esmMin((() => {
105075
105014
  */
105076
105015
  function resolveDetailsButtonText(input) {
105077
105016
  const { wizard } = input;
105078
- if (wizard.eligibility?.canJoinWaitlist) return "Join waitlist";
105079
- if (!input.hasWaitlistClaim && wizard.eligibility?.isFull) return "Sold out";
105017
+ const availability = wizard.eligibility?.availability;
105018
+ const full = availability?.kind === "waitlist" || isSelectionSoldOut(availability);
105019
+ if (wizard.portalAuthState !== "authenticated" && full) return "Continue";
105020
+ if (canRecoverToWaitlist(wizard.eligibility)) return "Join waitlist";
105021
+ if (!input.hasWaitlistClaim && full && wizard.eligibility?.registration.kind !== "pending_payment") return "Sold out";
105080
105022
  if (wizard.paymentSelection.method === "pass") return "Book using class pass";
105081
105023
  if (wizard.paymentSelection.method === "membership") return input.fallbackText;
105082
105024
  return wizard.eventRequiresPayment ? "Continue to payment" : input.fallbackText;
@@ -105091,44 +105033,28 @@ function isExistingRegistrationBlocking$1(wizard) {
105091
105033
  hasWaitlistClaim: wizard.waitlistClaim.claim !== null
105092
105034
  });
105093
105035
  }
105094
- /**
105095
- * Full for the visitor's selected attendance mode (or the whole event when no
105096
- * mode is chosen) with no waitlist to fall back on. Reads the same capacity
105097
- * source as the steps above the action bar so the button never disagrees
105098
- * with them on a hybrid event.
105099
- */
105100
- function isFullWithNoWaitlist(event, attendanceMode) {
105101
- if (!event) return false;
105102
- const source = selectEventCapacitySource(event, attendanceMode);
105103
- return getEventAvailability(source).isFull && !source.waitlistEnabled;
105104
- }
105105
105036
  function resolveTicketSelectionContinueLabel(input) {
105106
105037
  if (input.isCheckingExistingRegistration) return "Checking registration...";
105107
105038
  if (input.registrationOptionsPending) return "Checking availability...";
105108
105039
  if (input.registrationOptionsFailed) return "Availability unavailable";
105109
105040
  if (input.hasExistingRegistration) return resolveExistingRegistrationLabel(input.wizard);
105110
- if (input.isSoldOutWithoutWaitlist) return "Sold out";
105111
105041
  if (input.ticketTypeSelectionBlocked) return "Choose a ticket";
105112
105042
  return "Continue";
105113
105043
  }
105114
105044
  function SelectTicketsActions(props) {
105115
105045
  const { wizard } = props;
105116
- const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
105117
- const currentEvent = wizard.selectedEvent ?? wizard.preSelectedEvent;
105118
105046
  const registrationOptionsPending = wizard.registrationOptionsState.tag === "idle" || wizard.registrationOptionsState.tag === "loading";
105119
105047
  const registrationOptionsFailed = wizard.registrationOptionsState.tag === "failed";
105120
- const isSoldOutWithoutWaitlist = !wizard.checkoutRecovery && !hasWaitlistClaim && isFullWithNoWaitlist(currentEvent, wizard.selectedAttendanceMode);
105121
105048
  const isCheckingExistingRegistration = wizard.portalAuthState === "authenticated" && wizard.existingRegistrationLoading;
105122
105049
  const hasExistingRegistration = isExistingRegistrationBlocking$1(wizard);
105123
105050
  const ticketTypeSelectionBlocked = wizard.ticketTypeSelectionRequired && !wizard.hasValidTicketSelection;
105124
- const isContinueDisabled = registrationOptionsPending || registrationOptionsFailed || isCheckingExistingRegistration || hasExistingRegistration || isSoldOutWithoutWaitlist || ticketTypeSelectionBlocked;
105051
+ const isContinueDisabled = registrationOptionsPending || registrationOptionsFailed || isCheckingExistingRegistration || hasExistingRegistration || ticketTypeSelectionBlocked;
105125
105052
  const continueLabel = resolveTicketSelectionContinueLabel({
105126
105053
  wizard,
105127
105054
  registrationOptionsPending,
105128
105055
  registrationOptionsFailed,
105129
105056
  isCheckingExistingRegistration,
105130
105057
  hasExistingRegistration,
105131
- isSoldOutWithoutWaitlist,
105132
105058
  ticketTypeSelectionBlocked
105133
105059
  });
105134
105060
  return /* @__PURE__ */ jsxs("div", {
@@ -105159,8 +105085,12 @@ function EnterDetailsActions(props) {
105159
105085
  const { wizard } = props;
105160
105086
  const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
105161
105087
  const isCheckingEligibility = wizard.eligibilityLoading;
105162
- const eligibilityUnavailable = !hasWaitlistClaim && (Boolean(wizard.eligibilityError) || !wizard.eligibility || wizard.eligibility.availability.kind === "unavailable" || !wizard.eligibility.eligible);
105163
- const isSoldOut = !hasWaitlistClaim && wizard.eligibility?.isFull === true && wizard.eligibility.canJoinWaitlist !== true;
105088
+ const eligibilityUnavailable = Boolean(resolveRegistrationAvailabilityBlocker({
105089
+ hasWaitlistClaim,
105090
+ eligibility: wizard.eligibility,
105091
+ eligibilityError: wizard.eligibilityError
105092
+ }));
105093
+ const isSoldOut = !hasWaitlistClaim && wizard.portalAuthState === "authenticated" && wizard.eligibility?.registration.kind !== "pending_payment" && isSelectionSoldOut(wizard.eligibility?.availability);
105164
105094
  const isContinueDisabled = isCheckingEligibility || eligibilityUnavailable || isSoldOut;
105165
105095
  const continueLabel = isCheckingEligibility ? "Checking availability..." : wizard.eligibilityError ? "Availability unavailable" : eligibilityUnavailable ? "Registration unavailable" : resolveDetailsButtonText({
105166
105096
  wizard,
@@ -105211,6 +105141,7 @@ function EventRegistrationWizardActions(props) {
105211
105141
  case "redirecting":
105212
105142
  case "verifying-payment":
105213
105143
  case "verifying-timeout":
105144
+ case "payment-status":
105214
105145
  case "payment-failed": return null;
105215
105146
  case "select-event": return null;
105216
105147
  case "select-tickets": return /* @__PURE__ */ jsx(SelectTicketsActions, { ...props });
@@ -105222,7 +105153,8 @@ function EventRegistrationWizardActions(props) {
105222
105153
  var init_EventRegistrationWizardActions = __esmMin((() => {
105223
105154
  init_registrationStateMachine();
105224
105155
  init_spinner();
105225
- init_domain();
105156
+ init_registrationCompletion();
105157
+ init_registrationErrorRecovery();
105226
105158
  }));
105227
105159
  //#endregion
105228
105160
  //#region ../blocks/src/system/runtime/nodes/event-registration/siteCreditPreview.ts
@@ -105303,7 +105235,7 @@ var init_siteCreditPreview = __esmMin((() => {
105303
105235
  function resolvePaymentStepStatus(input) {
105304
105236
  if (input.loading) return "loading";
105305
105237
  if (input.error || !input.eligibility) return "error";
105306
- if (input.eligibility.registration.kind !== "none" || !input.eligibility.eligible && !input.eligibility.isFree) return "not-eligible";
105238
+ if (input.eligibility.registration.kind === "waitlisted" || input.eligibility.paymentOptions.length === 0) return "not-eligible";
105307
105239
  return "ready";
105308
105240
  }
105309
105241
  function shouldPromptForLogin(status, isAuthenticated, eligibility) {
@@ -105338,7 +105270,7 @@ function UnavailableEntitlementMessage(props) {
105338
105270
  ] });
105339
105271
  }
105340
105272
  function IneligiblePaymentPanel(props) {
105341
- if (props.eligibility.isFull && !props.eligibility.canJoinWaitlist) return /* @__PURE__ */ jsxs("div", {
105273
+ if (isSelectionSoldOut(props.eligibility.availability)) return /* @__PURE__ */ jsxs("div", {
105342
105274
  className: "rb-reg-stack er-stack",
105343
105275
  children: [/* @__PURE__ */ jsx("h3", {
105344
105276
  className: "er-title",
@@ -105407,26 +105339,23 @@ function PaymentBlockingPanel(props) {
105407
105339
  })
105408
105340
  });
105409
105341
  if (!props.eligibility) return /* @__PURE__ */ jsx(MissingEligibilityPanel, {});
105410
- if (props.eligibility.registration.kind !== "none") {
105411
- const isBooked = props.eligibility.registration.kind === "booked";
105412
- return /* @__PURE__ */ jsxs("div", {
105413
- className: "rb-reg-stack er-stack",
105414
- children: [/* @__PURE__ */ jsx("h3", {
105415
- className: "er-title",
105416
- children: isBooked ? "Already booked" : "Already on the waitlist"
105417
- }), /* @__PURE__ */ jsxs("div", {
105418
- className: "er-center",
105419
- children: [/* @__PURE__ */ jsx("p", {
105420
- className: "er-text er-text--muted",
105421
- 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."
105422
- }), /* @__PURE__ */ jsx("a", {
105423
- href: "/portal",
105424
- className: "er-retry-btn",
105425
- children: "View my bookings"
105426
- })]
105342
+ if (props.eligibility.registration.kind === "waitlisted") return /* @__PURE__ */ jsxs("div", {
105343
+ className: "rb-reg-stack er-stack",
105344
+ children: [/* @__PURE__ */ jsx("h3", {
105345
+ className: "er-title",
105346
+ children: "Already on the waitlist"
105347
+ }), /* @__PURE__ */ jsxs("div", {
105348
+ className: "er-center",
105349
+ children: [/* @__PURE__ */ jsx("p", {
105350
+ className: "er-text er-text--muted",
105351
+ children: "You're already on the waitlist for this event."
105352
+ }), /* @__PURE__ */ jsx("a", {
105353
+ href: "/portal",
105354
+ className: "er-retry-btn",
105355
+ children: "View my bookings"
105427
105356
  })]
105428
- });
105429
- }
105357
+ })]
105358
+ });
105430
105359
  if (props.eligibility.isFree) return /* @__PURE__ */ jsxs("div", {
105431
105360
  className: "rb-reg-stack er-stack",
105432
105361
  children: [/* @__PURE__ */ jsx("h3", {
@@ -105447,7 +105376,7 @@ function PaymentBlockingPanel(props) {
105447
105376
  })]
105448
105377
  })]
105449
105378
  });
105450
- return props.eligibility.eligible ? null : /* @__PURE__ */ jsx(IneligiblePaymentPanel, {
105379
+ return props.eligibility.paymentOptions.length > 0 ? null : /* @__PURE__ */ jsx(IneligiblePaymentPanel, {
105451
105380
  eligibility: props.eligibility,
105452
105381
  email: props.email,
105453
105382
  isAuthenticated: props.isAuthenticated,
@@ -105457,6 +105386,7 @@ function PaymentBlockingPanel(props) {
105457
105386
  var init_PaymentBlockingPanel = __esmMin((() => {
105458
105387
  init_buttons();
105459
105388
  init_spinner();
105389
+ init_registrationCompletion();
105460
105390
  }));
105461
105391
  //#endregion
105462
105392
  //#region ../blocks/src/system/runtime/nodes/event-registration/types.ts
@@ -105586,7 +105516,7 @@ function SlidingScaleAmountField(props) {
105586
105516
  }
105587
105517
  function TicketTypeQuantityRows(props) {
105588
105518
  const totalSelectedQuantity = getTicketSelectionTotal(props.ticketSelections);
105589
- const effectiveMaxTickets = props.availableSpots == null ? props.maxTickets : Math.min(props.maxTickets, props.availableSpots);
105519
+ const effectiveMaxTickets = props.maxTickets;
105590
105520
  return /* @__PURE__ */ jsxs("div", {
105591
105521
  className: "er-ticket-lines",
105592
105522
  children: [
@@ -105596,16 +105526,14 @@ function TicketTypeQuantityRows(props) {
105596
105526
  "aria-label": props.bookingUnit === "place" ? "Places" : "Tickets",
105597
105527
  children: props.ticketTypes.map((ticketType) => {
105598
105528
  const quantity = getTicketLineQuantity(props.ticketSelections, ticketType.pricingOptionId);
105599
- const disabled = ticketType.availability.kind === "unavailable";
105529
+ const disabled = !canRequestTicketOption(ticketType.availability);
105600
105530
  const availabilityLabel = getTicketTypeAvailabilityLabel(ticketType);
105601
105531
  const ticketTypeRemainingLabel = formatTicketTypeRemaining(ticketType.availability.remainingPlaces);
105602
105532
  const priceLabel = ticketType.priceAmount > 0 ? formatPrice(ticketType.priceAmount, props.currency) : "Free";
105603
105533
  const maxAllowed = disabled ? 0 : getTicketTypeLineMax({
105604
105534
  currentQuantity: quantity,
105605
105535
  totalSelectedQuantity,
105606
- maxTickets: props.maxTickets,
105607
- availableSpots: props.availableSpots,
105608
- ticketTypeRemainingCapacity: ticketType.availability.remainingPlaces
105536
+ maxTickets: props.maxTickets
105609
105537
  });
105610
105538
  return /* @__PURE__ */ jsxs("div", {
105611
105539
  className: `er-ticket-line${disabled ? " er-ticket-line--disabled" : ""}`,
@@ -105710,33 +105638,13 @@ function AttendanceModeTiles(props) {
105710
105638
  })
105711
105639
  });
105712
105640
  }
105713
- function getMaxAllowedTicketCount(input) {
105714
- if (input.canJoinWaitlist) return input.maxTickets;
105715
- if (!input.usesTicketTypes) return Math.min(input.maxTickets, input.availableSpots ?? input.maxTickets);
105716
- if (!input.hasSelectedTicketType) return 1;
105717
- return Math.max(1, Math.min(input.maxTickets, input.selectedTicketTypeRemainingCapacity ?? input.maxTickets, input.availableSpots ?? input.maxTickets));
105718
- }
105719
105641
  function resolveTicketSelectionPricing(event) {
105720
105642
  return {
105721
105643
  mode: event ? publicEventPricingStrategy(event.pricing) : void 0,
105722
105644
  currency: event ? publicEventPricingCurrency(event.pricing) : null
105723
105645
  };
105724
105646
  }
105725
- function CheckoutRecoveryEntry(props) {
105726
- return props.onContinue ? /* @__PURE__ */ jsx("button", {
105727
- type: "button",
105728
- className: "er-back-btn",
105729
- onClick: props.onContinue,
105730
- children: "Continue an existing booking"
105731
- }) : null;
105732
- }
105733
- function getTicketSelectionCapacity(event, attendanceMode, checkoutRecovery) {
105734
- if (checkoutRecovery) return {
105735
- availableSpots: null,
105736
- isSoldOut: false,
105737
- canJoinWaitlist: false,
105738
- eventAvailabilityLabel: null
105739
- };
105647
+ function getTicketSelectionCapacity(event, attendanceMode) {
105740
105648
  const source = event ? selectEventCapacitySource(event, attendanceMode) : null;
105741
105649
  const availability = source ? getEventAvailability(source) : null;
105742
105650
  const canJoinWaitlist = source ? canJoinEventWaitlist(source) : false;
@@ -105753,29 +105661,21 @@ var init_TicketSelectionStep = __esmMin((() => {
105753
105661
  init_domain();
105754
105662
  init_utils();
105755
105663
  init_ticketSelectionLines();
105756
- 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 }) => {
105664
+ TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, selectedAttendanceMode = null, onAttendanceModeChange, ticketsCount, maxTickets, visibleTicketTypes: visibleTicketTypesOverride, ticketSelections = [], onTicketSelectionsChange, slidingScale = null, selectedSlidingAmountInput = "", slidingScaleSelectionMessage = null, onSlidingAmountChange, onTicketsChange, bookingUnit = { kind: "ticket" } }) => {
105757
105665
  const unit = bookingUnit.kind;
105758
105666
  const deliveryMode = event?.deliveryMode ?? "in_person";
105759
105667
  const attendanceModes = event?.attendanceModes ?? [];
105760
- const { availableSpots, isSoldOut, canJoinWaitlist, eventAvailabilityLabel } = getTicketSelectionCapacity(event, selectedAttendanceMode, checkoutRecovery);
105668
+ const { availableSpots, isSoldOut, canJoinWaitlist, eventAvailabilityLabel } = getTicketSelectionCapacity(event, selectedAttendanceMode);
105761
105669
  const { mode: eventPricingMode, currency: eventPricingCurrency } = resolveTicketSelectionPricing(event);
105762
- const usesTicketTypes = eventPricingMode === "tiered" && !canJoinWaitlist;
105670
+ const usesTicketTypes = eventPricingMode === "tiered";
105763
105671
  const visibleTicketTypes = usesTicketTypes ? visibleTicketTypesOverride ?? getVisibleTicketTypes({
105764
105672
  event,
105765
105673
  eligibility: null,
105766
105674
  selectedAttendanceMode
105767
105675
  }) : [];
105768
- const implicitTicketType = usesTicketTypes ? getImplicitSingleAvailableTicketType(visibleTicketTypes) : null;
105769
105676
  const noVisibleTicketTypes = usesTicketTypes && visibleTicketTypes.length === 0;
105770
- const hasAvailableTicketTypes = usesTicketTypes && visibleTicketTypes.some((ticketType) => ticketType.availability.kind === "available");
105771
- const maxAllowed = getMaxAllowedTicketCount({
105772
- canJoinWaitlist,
105773
- usesTicketTypes,
105774
- maxTickets,
105775
- availableSpots,
105776
- selectedTicketTypeRemainingCapacity: implicitTicketType?.availability.remainingPlaces ?? null,
105777
- hasSelectedTicketType: implicitTicketType !== null
105778
- });
105677
+ const hasAvailableTicketTypes = usesTicketTypes && visibleTicketTypes.some((ticketType) => canRequestTicketOption(ticketType.availability));
105678
+ const maxAllowed = maxTickets;
105779
105679
  if (deliveryMode === "hybrid" && !selectedAttendanceMode) return /* @__PURE__ */ jsxs("div", {
105780
105680
  className: "rb-reg-stack er-stack",
105781
105681
  children: [
@@ -105794,20 +105694,6 @@ var init_TicketSelectionStep = __esmMin((() => {
105794
105694
  })
105795
105695
  ]
105796
105696
  });
105797
- if (isSoldOut && !canJoinWaitlist) return /* @__PURE__ */ jsxs("div", {
105798
- className: "rb-reg-stack er-stack",
105799
- children: [
105800
- /* @__PURE__ */ jsx("h3", {
105801
- className: "er-title",
105802
- children: "Sold out"
105803
- }),
105804
- /* @__PURE__ */ jsx("p", {
105805
- className: "er-text er-text--muted",
105806
- children: "Sorry you missed out! This event is fully booked."
105807
- }),
105808
- /* @__PURE__ */ jsx(CheckoutRecoveryEntry, { onContinue: onCheckoutRecovery })
105809
- ]
105810
- });
105811
105697
  if (!eventPricingCurrency) return /* @__PURE__ */ jsx("div", {
105812
105698
  className: "rb-reg-stack er-stack",
105813
105699
  children: /* @__PURE__ */ jsx("p", {
@@ -105874,14 +105760,14 @@ var init_TicketSelectionStep = __esmMin((() => {
105874
105760
  })]
105875
105761
  })
105876
105762
  ] }),
105877
- canJoinWaitlist && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("p", {
105763
+ isSoldOut && !canJoinWaitlist && /* @__PURE__ */ jsx("p", {
105878
105764
  className: "er-text er-text--muted",
105879
- children: "This event is currently full. Continue to join the waitlist if a place opens up."
105880
- }), /* @__PURE__ */ jsx(CheckoutRecoveryEntry, { onContinue: onCheckoutRecovery })] }),
105881
- checkoutRecovery && /* @__PURE__ */ jsx("p", {
105765
+ children: "This event is fully booked."
105766
+ }),
105767
+ canJoinWaitlist && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("p", {
105882
105768
  className: "er-text er-text--muted",
105883
- children: "Enter the details from your earlier booking. We’ll check your checkout before continuing to payment."
105884
- })
105769
+ children: "This event is currently full. Continue to join the waitlist if a place opens up."
105770
+ }) })
105885
105771
  ]
105886
105772
  });
105887
105773
  };
@@ -106469,7 +106355,7 @@ var init_PaymentSelectionStep = __esmMin((() => {
106469
106355
  const occurrenceId = occurrenceContext?.id ?? (event?.registrationSubject.kind === "occurrence" ? event.registrationSubject.occurrenceId : "");
106470
106356
  const selectedMethod = selectedSelection.method;
106471
106357
  const totalPrice = directPaymentTotalCents;
106472
- const canShowDirectPaymentOptions = Boolean(eligibility?.eligible && eligibility.canPayDirectly && eligibility.price);
106358
+ const canShowDirectPaymentOptions = Boolean(eligibility?.requiresPayment && eligibility.price);
106473
106359
  const directPaymentOptions = eligibility && canShowDirectPaymentOptions ? buildEventRegistrationPaymentOptionsViewModel({
106474
106360
  eventTitle: event?.title ?? "Event",
106475
106361
  approvedPaymentOptions: eligibility.paymentOptions,
@@ -106532,7 +106418,7 @@ var init_PaymentSelectionStep = __esmMin((() => {
106532
106418
  onRequestLogin
106533
106419
  });
106534
106420
  if (eligibilityLoading || eligibilityError || !eligibility) return blockingPanel;
106535
- if (eligibility.isFree || !eligibility.eligible) return blockingPanel;
106421
+ if (eligibility.isFree || paymentStepStatus !== "ready") return blockingPanel;
106536
106422
  const isMultiTicket = areEntitlementsDisabledForTicketCount(ticketsCount);
106537
106423
  return /* @__PURE__ */ jsxs("div", {
106538
106424
  className: "rb-reg-stack er-stack",
@@ -106751,7 +106637,7 @@ var init_VerifyingTimeoutStep = __esmMin((() => {
106751
106637
  title,
106752
106638
  body: /* @__PURE__ */ jsx("p", {
106753
106639
  className: "er-text--muted er-message",
106754
- children: message
106640
+ 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."
106755
106641
  }),
106756
106642
  actionsClassName: "er-button-group",
106757
106643
  actions: onCheckAgain ? /* @__PURE__ */ jsx("button", {
@@ -106759,11 +106645,7 @@ var init_VerifyingTimeoutStep = __esmMin((() => {
106759
106645
  onClick: onCheckAgain,
106760
106646
  className: "er-btn er-btn--primary",
106761
106647
  children: "Check payment status"
106762
- }) : /* @__PURE__ */ jsx("a", {
106763
- href: "/portal",
106764
- className: "er-btn er-btn--primary",
106765
- children: "Check payment status"
106766
- }),
106648
+ }) : void 0,
106767
106649
  secondaryBody: supportEmail ? /* @__PURE__ */ jsxs("p", {
106768
106650
  className: "er-text--sm er-text--muted er-message",
106769
106651
  children: [
@@ -106953,6 +106835,7 @@ function EventRegistrationWizardContent(props) {
106953
106835
  case "redirecting":
106954
106836
  case "verifying-payment":
106955
106837
  case "verifying-timeout":
106838
+ case "payment-status":
106956
106839
  case "payment-failed": return null;
106957
106840
  case "select-event": return /* @__PURE__ */ jsx(EventSelectionStep, {
106958
106841
  events: wizard.scopedEvents,
@@ -106968,8 +106851,6 @@ function EventRegistrationWizardContent(props) {
106968
106851
  onBookForSomeoneElse: wizard.handleBookForSomeoneElse
106969
106852
  }), /* @__PURE__ */ jsx(TicketSelectionStep, {
106970
106853
  event: wizard.selectedEvent,
106971
- checkoutRecovery: wizard.checkoutRecovery,
106972
- onCheckoutRecovery: canRecoverEventCheckout(wizard.selectedEvent) ? wizard.startCheckoutRecovery : void 0,
106973
106854
  occurrenceContext: wizard.occurrenceContext,
106974
106855
  selectedAttendanceMode: wizard.selectedAttendanceMode,
106975
106856
  onAttendanceModeChange: wizard.setSelectedAttendanceMode,
@@ -106997,13 +106878,90 @@ var init_EventRegistrationWizardContent = __esmMin((() => {
106997
106878
  init_client();
106998
106879
  init_src();
106999
106880
  init_shared();
107000
- init_checkoutRecovery();
107001
106881
  init_registrationStateMachine();
107002
106882
  init_siteCreditPreview();
107003
106883
  init_PaymentBlockingPanel();
107004
106884
  init_event_registration();
107005
106885
  }));
107006
106886
  //#endregion
106887
+ //#region ../blocks/src/system/runtime/nodes/event-registration/PaymentStatusStep.tsx
106888
+ function presentation(state) {
106889
+ switch (state.kind) {
106890
+ case "ready": return {
106891
+ title: "We haven’t confirmed your payment yet",
106892
+ 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.",
106893
+ action: { label: "Check payment status" }
106894
+ };
106895
+ case "checking": return {
106896
+ title: "We haven’t confirmed your payment yet",
106897
+ 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.",
106898
+ action: {
106899
+ label: "Checking payment…",
106900
+ disabled: true
106901
+ }
106902
+ };
106903
+ case "processing": return {
106904
+ title: "Your payment is still being processed",
106905
+ message: "Please don’t make another payment. You can check its status again in a moment.",
106906
+ action: { label: "Check payment status" }
106907
+ };
106908
+ case "paymentAvailable": return {
106909
+ title: "Your payment hasn’t been completed",
106910
+ message: "Your booking details are still saved. Continue to payment to finish your booking.",
106911
+ action: { label: "Continue to payment" }
106912
+ };
106913
+ case "retryAvailable": return {
106914
+ title: "Continue your booking",
106915
+ message: "You can return to payment. We’ll check your booking, any existing payment and availability before starting another checkout.",
106916
+ action: { label: "Return to payment" }
106917
+ };
106918
+ case "temporarilyUnavailable": return {
106919
+ title: "We couldn’t check your payment",
106920
+ message: "Please don’t make another payment yet. Try checking again in a moment.",
106921
+ action: { label: "Check payment status" }
106922
+ };
106923
+ case "assistanceRequired": return {
106924
+ title: "We still can’t confirm your payment",
106925
+ message: "Please don’t make another payment. Contact the organiser so they can check your booking.",
106926
+ action: { label: "Return to booking" }
106927
+ };
106928
+ }
106929
+ }
106930
+ function PaymentStatusStep(props) {
106931
+ const view = presentation(props.state);
106932
+ const onClick = props.state.kind === "paymentAvailable" ? props.onContinuePayment : props.state.kind === "retryAvailable" ? props.onReturnToPayment : props.state.kind === "assistanceRequired" ? props.onReturnToBooking : props.onCheck;
106933
+ return /* @__PURE__ */ jsx(TerminalPanel, {
106934
+ tone: "warning",
106935
+ className: "er-center",
106936
+ titleClassName: "er-title--lg er-message",
106937
+ icon: /* @__PURE__ */ jsx(StateIcon, {
106938
+ variant: "warning",
106939
+ children: /* @__PURE__ */ jsx(ClockIcon, {})
106940
+ }),
106941
+ title: view.title,
106942
+ body: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("p", {
106943
+ className: "er-text--muted er-message",
106944
+ children: view.message
106945
+ }), /* @__PURE__ */ jsx("span", {
106946
+ className: "rb-sr-only",
106947
+ "aria-live": "polite",
106948
+ "aria-atomic": "true",
106949
+ children: props.state.kind === "checking" ? "Checking payment…" : view.title
106950
+ })] }),
106951
+ actionsClassName: "er-button-group",
106952
+ actions: view.action ? /* @__PURE__ */ jsx("button", {
106953
+ type: "button",
106954
+ onClick,
106955
+ disabled: view.action.disabled,
106956
+ className: "er-btn er-btn--primary",
106957
+ children: /* @__PURE__ */ jsx("span", { children: view.action.label })
106958
+ }) : void 0
106959
+ });
106960
+ }
106961
+ var init_PaymentStatusStep = __esmMin((() => {
106962
+ init_shared();
106963
+ }));
106964
+ //#endregion
107007
106965
  //#region ../blocks/src/system/runtime/nodes/event-registration/EventRegistrationSurface.tsx
107008
106966
  function EventPortalAuthPrompt(props) {
107009
106967
  return /* @__PURE__ */ jsxs("div", {
@@ -107088,6 +107046,13 @@ function EventRegistrationTerminalState(props) {
107088
107046
  message: wizard.verification.status === "timeout" ? void 0 : wizard.errorMessage,
107089
107047
  supportEmail: props.supportEmail
107090
107048
  });
107049
+ case "payment-status": return wizard.paymentStatusRecovery ? /* @__PURE__ */ jsx(PaymentStatusStep, {
107050
+ state: wizard.paymentStatusRecovery,
107051
+ onCheck: wizard.handleCheckPaymentStatus,
107052
+ onContinuePayment: wizard.handleContinueExistingPayment,
107053
+ onReturnToPayment: wizard.handleReturnToPayment,
107054
+ onReturnToBooking: wizard.handleReturnToBooking
107055
+ }) : null;
107091
107056
  case "success": return wizard.registrationResult ? /* @__PURE__ */ jsx(SuccessStep, {
107092
107057
  title: wizard.registrationResult.title,
107093
107058
  variant: wizard.registrationResult.variant,
@@ -107096,7 +107061,7 @@ function EventRegistrationTerminalState(props) {
107096
107061
  case "error": return /* @__PURE__ */ jsx(ErrorStep, {
107097
107062
  message: wizard.errorMessage,
107098
107063
  action: wizard.errorAction,
107099
- canJoinWaitlist: wizard.eligibility?.isFull && wizard.eligibility.canJoinWaitlist,
107064
+ canJoinWaitlist: wizard.eligibility?.availability.kind === "waitlist" && wizard.eligibility.registration.kind !== "pending_payment",
107100
107065
  onRetry: wizard.handleRetry
107101
107066
  });
107102
107067
  case "select-event":
@@ -107158,6 +107123,7 @@ var init_EventRegistrationSurface = __esmMin((() => {
107158
107123
  init_EventRegistrationWizardActions();
107159
107124
  init_EventRegistrationWizardContent();
107160
107125
  init_PaymentFailedStep();
107126
+ init_PaymentStatusStep();
107161
107127
  init_StepIndicator();
107162
107128
  init_SuccessStep();
107163
107129
  init_VerifyingPaymentStep();
@@ -107295,6 +107261,7 @@ function getWizardStepLabel(input) {
107295
107261
  case "redirecting":
107296
107262
  case "verifying-payment":
107297
107263
  case "verifying-timeout":
107264
+ case "payment-status":
107298
107265
  case "payment-failed": return "";
107299
107266
  }
107300
107267
  }
@@ -157712,6 +157679,17 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
157712
157679
  //#region ../api/src/publicEventEndpointDefinitions.ts
157713
157680
  init_src$2();
157714
157681
  const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
157682
+ checkPublicEventRegistrationNextStep: {
157683
+ path: "/public/sites/{siteId}/events/registration-next-step",
157684
+ method: "POST",
157685
+ auth: "public",
157686
+ responseKind: "json",
157687
+ errors: [
157688
+ "validation:invalid_input",
157689
+ "auth:forbidden",
157690
+ "server:internal_error"
157691
+ ]
157692
+ },
157715
157693
  listPublicEventCalendarWindow: {
157716
157694
  path: "/public/sites/{siteId}/events/calendar-window",
157717
157695
  method: "GET",