@riverbankcms/sdk 0.148.0 → 0.149.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 (154) hide show
  1. package/README.md +1 -1
  2. package/dist/{PreviewEditorSidebar-DvEPG3Z2.mjs → PreviewEditorSidebar-DBKln68M.mjs} +103 -66
  3. package/dist/{PreviewEditorUI-D6eb6fkx.mjs → PreviewEditorUI-DpRX4Mum.mjs} +3 -6
  4. package/dist/{PreviewQueryProvider-5znTyJuz.mjs → PreviewQueryProvider-C0mndwHB.mjs} +3 -3
  5. package/dist/{SdkPreviewModeRuntime-DJ6utQ_R.mjs → SdkPreviewModeRuntime-DJPmPY-r.mjs} +95 -67
  6. package/dist/{SiteChromeCustomizeContext-CFJYh6vo.mjs → SiteChromeCustomizeContext-JYA0cJ_Z.mjs} +982 -734
  7. package/dist/_dts/api/src/bookingConfig.d.ts +33 -48
  8. package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +2 -6
  9. package/dist/_dts/api/src/bookingOperations.d.ts +5 -7
  10. package/dist/_dts/api/src/bookingRecords.d.ts +15 -11
  11. package/dist/_dts/api/src/bookingRefundOutcomes.d.ts +5 -5
  12. package/dist/_dts/api/src/clientErrorReporting.d.ts +11 -0
  13. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +0 -2
  14. package/dist/_dts/api/src/common/cancellation.d.ts +23 -0
  15. package/dist/_dts/api/src/customerMembershipOutcomes.d.ts +1 -1
  16. package/dist/_dts/api/src/endpoints.d.ts +2 -10
  17. package/dist/_dts/api/src/eventManagementContracts.d.ts +4 -7
  18. package/dist/_dts/api/src/index.d.ts +3 -3
  19. package/dist/_dts/api/src/publicAppointmentBookingContracts.d.ts +2 -2
  20. package/dist/_dts/api/src/publicExperience/commerceEndpoints.d.ts +2 -29
  21. package/dist/_dts/api/src/request.d.ts +1 -1
  22. package/dist/_dts/api/src/sdk-event-upsert.d.ts +1 -1
  23. package/dist/_dts/api/src/sdkPullEventContracts.d.ts +1 -1
  24. package/dist/_dts/api/src/siteOperations.d.ts +6 -2
  25. package/dist/_dts/blocks/src/contracts/index.d.ts +1 -1
  26. package/dist/_dts/blocks/src/contracts/non-block-islands.d.ts +2 -2
  27. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +38 -10
  28. package/dist/_dts/blocks/src/portal/types.d.ts +9 -6
  29. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +24 -24
  30. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +1 -1
  31. package/dist/_dts/blocks/src/system/blocks/shared/bookingPaymentTerms.d.ts +84 -160
  32. package/dist/_dts/blocks/src/system/blocks/shop.d.ts +2 -2
  33. package/dist/_dts/blocks/src/system/blocks/shop.shared.d.ts +31 -4
  34. package/dist/_dts/blocks/src/system/runtime/api/types/appointments.d.ts +2 -2
  35. package/dist/_dts/blocks/src/system/runtime/api/types/core.d.ts +3 -1
  36. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +48 -6
  37. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +24 -3
  38. package/dist/_dts/blocks/src/system/runtime/hooks/useBookingNowIso.d.ts +8 -0
  39. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.state.d.ts +2 -1
  40. package/dist/_dts/blocks/src/system/runtime/nodes/commerce/shared/display.d.ts +9 -2
  41. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/presentation.d.ts +14 -2
  42. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PaymentSelectionStep.d.ts +2 -0
  43. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventPaymentOptions.d.ts +3 -3
  44. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +4 -0
  45. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +24 -24
  46. package/dist/_dts/blocks/src/system/runtime/nodes/shop.interactive.d.ts +41 -6
  47. package/dist/_dts/blocks/src/system/runtime/shared/bookingPaymentOptions.d.ts +7 -2
  48. package/dist/_dts/commerce/src/purchase/bookingPaymentSelection.d.ts +54 -0
  49. package/dist/_dts/commerce/src/purchase/checkoutCommitPlan.d.ts +58 -13
  50. package/dist/_dts/commerce/src/purchase/checkoutErrorCodes.d.ts +1 -1
  51. package/dist/_dts/commerce/src/purchase/checkoutPaymentPlanPlanning.d.ts +16 -21
  52. package/dist/_dts/commerce/src/purchase/checkoutPaymentTerms.d.ts +23 -40
  53. package/dist/_dts/commerce/src/purchase/checkoutSessionMetadata.d.ts +2 -2
  54. package/dist/_dts/commerce/src/purchase/checkoutStripeSessionPlanning.d.ts +5 -4
  55. package/dist/_dts/commerce/src/purchase/index.d.ts +1 -3
  56. package/dist/_dts/commerce/src/purchase/membershipOrderItemMetadata.d.ts +4 -0
  57. package/dist/_dts/commerce/src/purchase/oneTimeCheckoutPlanning.d.ts +9 -4
  58. package/dist/_dts/commerce/src/purchase/orderInstalmentClosure.d.ts +13 -1
  59. package/dist/_dts/commerce/src/purchase/orderInstalmentLifecycle.d.ts +5 -0
  60. package/dist/_dts/commerce/src/purchase/orderItemMetadata.d.ts +3 -1
  61. package/dist/_dts/commerce/src/purchase/orderTypes.d.ts +7 -1
  62. package/dist/_dts/commerce/src/purchase/refundRailSplit.d.ts +1 -1
  63. package/dist/_dts/commerce/src/purchase/stateTransitions.d.ts +2 -2
  64. package/dist/_dts/commerce/src/purchase/stripeMinimumCharge.d.ts +6 -0
  65. package/dist/_dts/commerce/src/purchase/types.d.ts +2 -1
  66. package/dist/_dts/content-editor/src/controller/editLeaseHandover.d.ts +30 -0
  67. package/dist/_dts/content-editor/src/lib/browserStorage.d.ts +5 -0
  68. package/dist/_dts/core/src/booking-flexible-balance.d.ts +2 -2
  69. package/dist/_dts/core/src/booking-instalment-deposit.d.ts +20 -0
  70. package/dist/_dts/core/src/booking-live-payment-terms.d.ts +72 -0
  71. package/dist/_dts/core/src/booking-payment-options.d.ts +24 -0
  72. package/dist/_dts/core/src/booking-payment-schemas.d.ts +522 -0
  73. package/dist/_dts/core/src/branded.d.ts +3 -0
  74. package/dist/_dts/core/src/edit-lease.d.ts +5 -0
  75. package/dist/_dts/core/src/index.d.ts +3 -0
  76. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +297 -36
  77. package/dist/_dts/media-editor/src/MediaPickerDialog.d.ts +3 -1
  78. package/dist/_dts/media-editor/src/MediaPickerMiniDialog.d.ts +10 -0
  79. package/dist/_dts/media-editor/src/index.d.ts +2 -0
  80. package/dist/_dts/preview-next/src/client/preview/PreviewEntryControllerProvider.d.ts +0 -1
  81. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +1 -1
  82. package/dist/_dts/preview-next/src/client/previewAuthStore.d.ts +7 -0
  83. package/dist/_dts/preview-next/src/constants.d.ts +4 -0
  84. package/dist/_dts/preview-next/src/keepAlive.d.ts +1 -0
  85. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +2 -12
  86. package/dist/_dts/sdk/src/version.d.ts +1 -1
  87. package/dist/_dts/theme-core/src/site-styles/pageDesignIntent.d.ts +0 -5
  88. package/dist/_dts/ui/src/color-picker.d.ts +1 -1
  89. package/dist/_dts/ui/src/palette/useHexDraft.d.ts +7 -0
  90. package/dist/client/{BookingMailingListNote-CzRt2dF_.mjs → BookingMailingListNote-Cr3EeTP5.mjs} +408 -69
  91. package/dist/client/{DemoBookingPortalAccess-mxqwap3f.mjs → DemoBookingPortalAccess-BFGB1Fay.mjs} +2 -2
  92. package/dist/client/{EventCombined.client-CDb11igO.mjs → EventCombined.client-DKYV0_ft.mjs} +6 -6
  93. package/dist/client/{EventListing.client-EgYhzKPa.mjs → EventListing.client-B9UIcEYc.mjs} +2 -2
  94. package/dist/client/{LeafletStaticMap-gtmtaA2b.mjs → LeafletStaticMap-CFLPkP0K.mjs} +1 -1
  95. package/dist/client/{TerminalPanel-DvNUP5ot.mjs → TerminalPanel-JjmgxEsR.mjs} +1 -1
  96. package/dist/client/{ThemedButton-C7CeUJjW.mjs → ThemedButton-CKV1Jh2m.mjs} +1 -1
  97. package/dist/client/{accordion-kjvt49rA.mjs → accordion-DXWIfT3T.mjs} +1 -1
  98. package/dist/client/{bookingForm-pbRZordh.mjs → bookingForm-CjZgHNvv.mjs} +11 -8
  99. package/dist/client/bookings.mjs +424 -320
  100. package/dist/client/{carousel-f4Zbmicv.mjs → carousel-DSLikmvZ.mjs} +1 -1
  101. package/dist/client/{cart-DO20An50.mjs → cart-HDjWReFt.mjs} +3 -3
  102. package/dist/client/{checkout-Du5amDR_.mjs → checkout-CUvRZA3W.mjs} +3 -3
  103. package/dist/client/client.mjs +963 -866
  104. package/dist/client/{context-eW97E945.mjs → context-DFmaZa-Q.mjs} +1 -1
  105. package/dist/client/{dates-jPCirRea.mjs → dates-BBep1JnF.mjs} +2 -2
  106. package/dist/client/{eventCalendar-C2M-iE4j.mjs → eventCalendar-zEobhxo4.mjs} +9 -9
  107. package/dist/client/{eventCombined-W6ns3LHg.mjs → eventCombined-Dp7bz5k-.mjs} +4 -4
  108. package/dist/client/{eventDetails-CR-GT0f0.mjs → eventDetails-FE-zqTt7.mjs} +4 -4
  109. package/dist/client/{eventListing-BK8AfYZz.mjs → eventListing-BMt5snal.mjs} +4 -4
  110. package/dist/client/{eventRegistration-BJSd4KUu.mjs → eventRegistration-O6ZxHfOb.mjs} +67 -342
  111. package/dist/client/{form-BvpfbQaT.mjs → form-DFa1D8vt.mjs} +3 -3
  112. package/dist/client/{headerSection-I5sUQ8x-.mjs → headerSection-CmjHLR-N.mjs} +3 -3
  113. package/dist/client/hooks.mjs +160 -129
  114. package/dist/client/{locationMap-BLvwf9_f.mjs → locationMap-BXKP_lGh.mjs} +3 -3
  115. package/dist/client/{newsletterForm-DrQ2weE8.mjs → newsletterForm-CU-HmxGx.mjs} +3 -3
  116. package/dist/client/{pricing-BES87mrR.mjs → pricing-KEAEsibq.mjs} +1 -1
  117. package/dist/client/{productDetail-Url9jcc5.mjs → productDetail-Ckp7MGnt.mjs} +3 -3
  118. package/dist/client/{productList-DE7ngEZJ.mjs → productList-D91V0sYa.mjs} +3 -3
  119. package/dist/client/{propsDecoder-D1OtGXDV.mjs → propsDecoder-DZd6RJeA.mjs} +155 -77
  120. package/dist/client/rendering/client.mjs +3356 -3192
  121. package/dist/client/rendering/islands.mjs +17 -17
  122. package/dist/client/rendering.mjs +956 -841
  123. package/dist/client/{routeIslandApiConfig-BG9Y-SHg.mjs → routeIslandApiConfig-E1EkhhYY.mjs} +1 -1
  124. package/dist/client/{shop-CJkuySJ3.mjs → shop-4F2jLQPI.mjs} +12 -13
  125. package/dist/client/{shop-commerce-4rKj5n9h.mjs → shop-commerce-BbfCJjB3.mjs} +6 -6
  126. package/dist/client/{shop-commerce-store-Bxm75Pg6.mjs → shop-commerce-store-vicweP2K.mjs} +1 -1
  127. package/dist/client/{shopShared-DpoQDWfz.mjs → shopShared-DlONJt0T.mjs} +4 -4
  128. package/dist/client/{useEventFilters-D8HliSqR.mjs → useEventFilters-COYyL3m7.mjs} +6 -6
  129. package/dist/preview-next/before-render.mjs +15 -22
  130. package/dist/preview-next/client/runtime.mjs +4 -4
  131. package/dist/preview-next/constants.mjs +5 -1
  132. package/dist/preview-next/index.mjs +5 -1
  133. package/dist/preview-next/keepAlive.mjs +149 -82
  134. package/dist/preview-next/middleware.mjs +15 -22
  135. package/dist/{previewAuthStore-BXXF3hhW.mjs → previewAuthStore-BBmV7UsW.mjs} +49 -29
  136. package/dist/{sdk-runtime-C2a05WjL.mjs → sdk-runtime-CwvFFjB-.mjs} +2 -2
  137. package/dist/{separator-CuNhBAhS.mjs → separator-ByL72zUT.mjs} +1 -1
  138. package/dist/server/components.mjs +167 -131
  139. package/dist/server/config-validation.mjs +160 -129
  140. package/dist/server/config.mjs +160 -129
  141. package/dist/server/data.mjs +160 -129
  142. package/dist/server/index.mjs +20 -27
  143. package/dist/server/next.mjs +174 -156
  144. package/dist/server/page-converter.mjs +145 -65
  145. package/dist/server/prebuild.mjs +1 -1
  146. package/dist/server/rendering/server.mjs +169 -131
  147. package/dist/server/rendering.mjs +167 -131
  148. package/dist/server/routing.mjs +165 -118
  149. package/dist/server/server.mjs +167 -154
  150. package/package.json +1 -1
  151. package/dist/_dts/api/src/bookingPaymentTermSchemas.d.ts +0 -123
  152. package/dist/_dts/commerce/src/purchase/checkoutPaymentTermPlanning.d.ts +0 -10
  153. package/dist/_dts/commerce/src/purchase/checkoutValidatedItemPlanning.d.ts +0 -55
  154. package/dist/_dts/commerce/src/purchase/orderInstalmentPayoff.d.ts +0 -24
@@ -2539,7 +2539,7 @@ function subtractDaysFromIso(isoString, dayCount) {
2539
2539
  }
2540
2540
  //#endregion
2541
2541
  //#region ../core/src/assert-never.ts
2542
- function assertNever$3(value, message = "Unexpected variant") {
2542
+ function assertNever$4(value, message = "Unexpected variant") {
2543
2543
  throw new Error(`${message}: ${String(value)}`);
2544
2544
  }
2545
2545
  //#endregion
@@ -2632,7 +2632,7 @@ function isPublicEventPricingOptionDisplayable(option) {
2632
2632
  case "not_on_sale_yet":
2633
2633
  case "sale_ended":
2634
2634
  case "attendance_mode_unavailable": return false;
2635
- default: return assertNever$3(reason);
2635
+ default: return assertNever$4(reason);
2636
2636
  }
2637
2637
  }
2638
2638
  function publicEventPricingDisplay(pricing) {
@@ -2753,7 +2753,7 @@ function canonicalEventPricingDisplay(pricing) {
2753
2753
  currency: pricing.currency,
2754
2754
  purpose: "configured"
2755
2755
  });
2756
- default: return assertNever$3(pricing);
2756
+ default: return assertNever$4(pricing);
2757
2757
  }
2758
2758
  }
2759
2759
  //#endregion
@@ -2884,10 +2884,10 @@ function resolveFlexibleBalanceDueAt(input) {
2884
2884
  switch (input.dueDateRule.kind) {
2885
2885
  case "relative_to_start_date": return subtractDaysFromIso(input.bookingStartAt, input.dueDateRule.daysBeforeStart);
2886
2886
  case "fixed_calendar_date": return input.dueDateRule.dueAt;
2887
- default: return assertNever$2(input.dueDateRule);
2887
+ default: return assertNever$3(input.dueDateRule);
2888
2888
  }
2889
2889
  }
2890
- function assertNever$2(value) {
2890
+ function assertNever$3(value) {
2891
2891
  throw new Error(`Unexpected value: ${String(value)}`);
2892
2892
  }
2893
2893
  //#endregion
@@ -2897,7 +2897,7 @@ function isDepositBearingBookingInstalmentPlan(plan) {
2897
2897
  case "deposit_plus_one_remainder":
2898
2898
  case "deposit_plus_scheduled_instalments": return true;
2899
2899
  case "equal_scheduled_instalments": return false;
2900
- default: return assertNever$1(plan);
2900
+ default: return assertNever$2(plan);
2901
2901
  }
2902
2902
  }
2903
2903
  function getBookingInstalmentDepositRefundability(plan) {
@@ -2923,7 +2923,7 @@ function addIntervalPreservingMonthAnchor(isoString, intervalCount, intervalUnit
2923
2923
  date.setUTCDate(date.getUTCDate() + intervalCount * 7);
2924
2924
  return date.toISOString();
2925
2925
  case "month": return addMonthsPreservingAnchorDay(date, intervalCount).toISOString();
2926
- default: return assertNever$1(intervalUnit);
2926
+ default: return assertNever$2(intervalUnit);
2927
2927
  }
2928
2928
  }
2929
2929
  function getBookingInstalmentPlanIntervalCount(plan) {
@@ -2931,7 +2931,7 @@ function getBookingInstalmentPlanIntervalCount(plan) {
2931
2931
  case "deposit_plus_one_remainder": return plan.remainderDueCount;
2932
2932
  case "deposit_plus_scheduled_instalments":
2933
2933
  case "equal_scheduled_instalments": return plan.intervalCount;
2934
- default: return assertNever$1(plan);
2934
+ default: return assertNever$2(plan);
2935
2935
  }
2936
2936
  }
2937
2937
  function omitZeroAmountFutureRows(rows) {
@@ -2947,10 +2947,20 @@ function addMonthsPreservingAnchorDay(date, intervalCount) {
2947
2947
  nextMonth.setUTCDate(Math.min(anchorDay, lastDayOfTargetMonth));
2948
2948
  return nextMonth;
2949
2949
  }
2950
- function assertNever$1(value) {
2950
+ function assertNever$2(value) {
2951
2951
  throw new Error(`Unexpected value: ${String(value)}`);
2952
2952
  }
2953
2953
  //#endregion
2954
+ //#region ../core/src/booking-payment-options.ts
2955
+ /** Automatic instalments and a flexible balance cannot share one booking offer. */
2956
+ function validateBookingPaymentOptionKinds(kinds) {
2957
+ if (kinds.length === 0) return err$1("no_options");
2958
+ const uniqueKinds = new Set(kinds);
2959
+ if (uniqueKinds.size !== kinds.length) return err$1("duplicate_kind");
2960
+ if (uniqueKinds.has("instalment_plan") && uniqueKinds.has("flexible_balance")) return err$1("incompatible_collection_options");
2961
+ return ok$1(void 0);
2962
+ }
2963
+ //#endregion
2954
2964
  //#region ../core/src/booking-time-zone.ts
2955
2965
  const TIME_ZONE_VALIDITY_CACHE_LIMIT = 100;
2956
2966
  const timeZoneValidityCache = /* @__PURE__ */ new Map();
@@ -7859,68 +7869,115 @@ const RichTextDocSchema = z.object({
7859
7869
  content: z.array(TipTapNodeSchema)
7860
7870
  }).strict();
7861
7871
  //#endregion
7862
- //#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
7863
- const bookingDepositRefundPolicySchema = z.enum(["refundable", "non_refundable"]);
7864
- const bookingInstalmentPlanSchema = z.union([
7865
- z.object({
7866
- kind: z.literal("deposit_plus_one_remainder"),
7867
- depositAmountCents: z.number().int().min(0),
7868
- depositRefundability: bookingDepositRefundPolicySchema,
7869
- remainderDueCount: z.number().int().positive(),
7870
- intervalUnit: z.enum([
7871
- "day",
7872
- "week",
7873
- "month"
7874
- ])
7875
- }),
7876
- z.object({
7877
- kind: z.literal("deposit_plus_scheduled_instalments"),
7878
- depositAmountCents: z.number().int().min(0),
7879
- depositRefundability: bookingDepositRefundPolicySchema,
7880
- instalmentCount: z.number().int().positive(),
7881
- intervalCount: z.number().int().positive(),
7882
- intervalUnit: z.enum([
7883
- "day",
7884
- "week",
7885
- "month"
7886
- ])
7887
- }),
7888
- z.object({
7889
- kind: z.literal("equal_scheduled_instalments"),
7890
- instalmentCount: z.number().int().positive(),
7891
- intervalCount: z.number().int().positive(),
7892
- intervalUnit: z.enum([
7893
- "day",
7894
- "week",
7895
- "month"
7896
- ])
7897
- })
7898
- ]);
7899
- const bookingFlexibleBalanceDueDateRuleSchema = z.union([z.object({
7900
- kind: z.literal("relative_to_start_date"),
7901
- daysBeforeStart: z.number().int().positive()
7902
- }), z.object({
7903
- kind: z.literal("fixed_calendar_date"),
7904
- dueAt: z.string().datetime()
7905
- })]);
7906
- const bookingFlexibleBalanceConfigSchema = z.object({
7907
- upfrontAmountCents: z.number().int().min(0),
7908
- dueDateRule: bookingFlexibleBalanceDueDateRuleSchema,
7909
- depositRefundability: bookingDepositRefundPolicySchema
7910
- });
7911
- const blockBookingPaymentCollectionOptionSchema = z.union([
7912
- z.object({ kind: z.literal("upfront") }),
7913
- z.object({ kind: z.literal("deferred_manual") }),
7914
- z.object({
7915
- kind: z.literal("instalment_plan"),
7916
- plan: bookingInstalmentPlanSchema
7917
- }),
7918
- z.object({
7919
- kind: z.literal("flexible_balance"),
7920
- config: bookingFlexibleBalanceConfigSchema
7921
- })
7872
+ //#region ../core/src/booking-payment-schemas.ts
7873
+ const stripObject = (shape) => z.object(shape);
7874
+ const strictObject = (shape) => z.strictObject(shape);
7875
+ const depositRefundPolicySchema = z.enum(["refundable", "non_refundable"]);
7876
+ const intervalUnitSchema = z.enum([
7877
+ "day",
7878
+ "week",
7879
+ "month"
7922
7880
  ]);
7923
- const blockBookingPaymentTermsSchema = z.object({ allowedOptions: z.array(blockBookingPaymentCollectionOptionSchema).min(1) });
7881
+ const nonNegativeIntegerSchema = z.number().int().nonnegative();
7882
+ const positiveIntegerSchema = z.number().int().positive();
7883
+ function createInstalmentPlanSchema(object) {
7884
+ return z.discriminatedUnion("kind", [
7885
+ object({
7886
+ kind: z.literal("deposit_plus_one_remainder"),
7887
+ depositAmountCents: nonNegativeIntegerSchema,
7888
+ depositRefundability: depositRefundPolicySchema,
7889
+ remainderDueCount: positiveIntegerSchema,
7890
+ intervalUnit: intervalUnitSchema
7891
+ }),
7892
+ object({
7893
+ kind: z.literal("deposit_plus_scheduled_instalments"),
7894
+ depositAmountCents: nonNegativeIntegerSchema,
7895
+ depositRefundability: depositRefundPolicySchema,
7896
+ instalmentCount: positiveIntegerSchema,
7897
+ intervalCount: positiveIntegerSchema,
7898
+ intervalUnit: intervalUnitSchema
7899
+ }),
7900
+ object({
7901
+ kind: z.literal("equal_scheduled_instalments"),
7902
+ instalmentCount: positiveIntegerSchema,
7903
+ intervalCount: positiveIntegerSchema,
7904
+ intervalUnit: intervalUnitSchema
7905
+ })
7906
+ ]);
7907
+ }
7908
+ function createFlexibleBalanceSchemas(object) {
7909
+ const dueDateRule = z.discriminatedUnion("kind", [object({
7910
+ kind: z.literal("relative_to_start_date"),
7911
+ daysBeforeStart: positiveIntegerSchema
7912
+ }), object({
7913
+ kind: z.literal("fixed_calendar_date"),
7914
+ dueAt: z.string().datetime()
7915
+ })]);
7916
+ return {
7917
+ dueDateRule,
7918
+ config: object({
7919
+ upfrontAmountCents: nonNegativeIntegerSchema,
7920
+ dueDateRule,
7921
+ depositRefundability: depositRefundPolicySchema
7922
+ })
7923
+ };
7924
+ }
7925
+ const paymentOptionKindsMessages = {
7926
+ no_options: "Choose at least one way for customers to pay.",
7927
+ duplicate_kind: "Choose each payment option only once.",
7928
+ incompatible_collection_options: "Offer instalments or a deposit with the rest paid later, but not both."
7929
+ };
7930
+ function buildBookingPaymentOptionSchemas(object) {
7931
+ const instalmentPlan = createInstalmentPlanSchema(object);
7932
+ const flexibleBalance = createFlexibleBalanceSchemas(object);
7933
+ const paymentCollectionOption = z.discriminatedUnion("kind", [
7934
+ object({ kind: z.literal("upfront") }),
7935
+ object({ kind: z.literal("deferred_manual") }),
7936
+ object({
7937
+ kind: z.literal("instalment_plan"),
7938
+ plan: instalmentPlan
7939
+ }),
7940
+ object({
7941
+ kind: z.literal("flexible_balance"),
7942
+ config: flexibleBalance.config
7943
+ })
7944
+ ]);
7945
+ const paymentTerms = object({ allowedOptions: z.array(paymentCollectionOption) }).superRefine(({ allowedOptions }, ctx) => {
7946
+ const result = validateBookingPaymentOptionKinds(allowedOptions.map(({ kind }) => kind));
7947
+ if (!result.ok) ctx.addIssue({
7948
+ code: "custom",
7949
+ path: ["allowedOptions"],
7950
+ message: paymentOptionKindsMessages[result.error]
7951
+ });
7952
+ });
7953
+ const paymentOptionsChoice = z.discriminatedUnion("source", [z.strictObject({ source: z.literal("default") }), z.strictObject({
7954
+ source: z.literal("custom"),
7955
+ paymentTerms
7956
+ })]);
7957
+ return {
7958
+ depositRefundPolicy: depositRefundPolicySchema,
7959
+ instalmentPlan,
7960
+ flexibleBalanceDueDateRule: flexibleBalance.dueDateRule,
7961
+ flexibleBalanceConfig: flexibleBalance.config,
7962
+ paymentCollectionOption,
7963
+ paymentTerms,
7964
+ paymentOptionsChoice
7965
+ };
7966
+ }
7967
+ function createBookingPaymentOptionSchemas(mode) {
7968
+ return mode === "strict" ? buildBookingPaymentOptionSchemas(strictObject) : buildBookingPaymentOptionSchemas(stripObject);
7969
+ }
7970
+ const bookingPaymentOptionSchemas = createBookingPaymentOptionSchemas("strip");
7971
+ bookingPaymentOptionSchemas.depositRefundPolicy;
7972
+ bookingPaymentOptionSchemas.instalmentPlan;
7973
+ bookingPaymentOptionSchemas.flexibleBalanceDueDateRule;
7974
+ bookingPaymentOptionSchemas.flexibleBalanceConfig;
7975
+ bookingPaymentOptionSchemas.paymentCollectionOption;
7976
+ const bookingPaymentTermsSchema = bookingPaymentOptionSchemas.paymentTerms;
7977
+ bookingPaymentOptionSchemas.paymentOptionsChoice;
7978
+ //#endregion
7979
+ //#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
7980
+ const blockBookingPaymentTermsSchema = bookingPaymentTermsSchema;
7924
7981
  //#endregion
7925
7982
  //#region ../blocks/src/system/blocks/shared/bookingConsent.ts
7926
7983
  const BOOKING_REQUIREMENT_CONSENT_FIELD_PREFIX = "booking_requirement_consent_";
@@ -9492,7 +9549,7 @@ function err(error) {
9492
9549
  error
9493
9550
  };
9494
9551
  }
9495
- function assertNever(value, message) {
9552
+ function assertNever$1(value, message) {
9496
9553
  throw new Error(message ?? `Unexpected value: ${String(value)}`);
9497
9554
  }
9498
9555
  //#endregion
@@ -9641,7 +9698,7 @@ function deriveBookingFormViewState(input) {
9641
9698
  kind: "success",
9642
9699
  resourceName: input.verificationState.resourceName
9643
9700
  };
9644
- default: return assertNever(input.verificationState);
9701
+ default: return assertNever$1(input.verificationState);
9645
9702
  }
9646
9703
  }
9647
9704
  function resolveBookingSiteId(siteId, form) {
@@ -9805,19 +9862,17 @@ function getBookingServicePaymentSelectionMode(service) {
9805
9862
  if (service?.paymentTermsAvailability?.kind === "pending_stripe_setup") return "pending_stripe_setup";
9806
9863
  const allowedKinds = service?.paymentTerms?.allowedOptions.map((option) => option.kind) ?? [];
9807
9864
  if (allowedKinds.length === 0) return "implicit_upfront";
9808
- if (allowedKinds.length === 1) {
9809
- const onlyKind = allowedKinds[0];
9810
- if (!onlyKind) return "unsupported";
9811
- switch (onlyKind) {
9812
- case "upfront": return "implicit_upfront";
9813
- case "deferred_manual": return "implicit_deferred_manual";
9814
- case "instalment_plan": return "implicit_instalment_plan";
9815
- case "flexible_balance": return "implicit_flexible_balance";
9816
- default: return assertNever(onlyKind);
9817
- }
9865
+ if (!validateBookingPaymentOptionKinds(allowedKinds).ok) return "unsupported";
9866
+ if (allowedKinds.length > 1) return "choice_required";
9867
+ const onlyKind = allowedKinds[0];
9868
+ switch (onlyKind) {
9869
+ case "upfront": return "implicit_upfront";
9870
+ case "deferred_manual": return "implicit_deferred_manual";
9871
+ case "instalment_plan": return "implicit_instalment_plan";
9872
+ case "flexible_balance": return "implicit_flexible_balance";
9873
+ case void 0: return "unsupported";
9874
+ default: return assertNever$1(onlyKind);
9818
9875
  }
9819
- if (allowedKinds.length === 2 && allowedKinds.includes("upfront") && (allowedKinds.includes("deferred_manual") || allowedKinds.includes("instalment_plan") || allowedKinds.includes("flexible_balance"))) return "choice_required";
9820
- return "unsupported";
9821
9876
  }
9822
9877
  function resolveDefaultBookingServiceId(formConfig, services) {
9823
9878
  const configuredServiceId = toTrimmedString(formConfig?.settings?.serviceId);
@@ -9989,7 +10044,7 @@ function formatBookingSubmissionPreparationError(error) {
9989
10044
  case "sliding-amount-out-of-range": return `Please choose an amount within the sliding scale for "${error.serviceTitle}".`;
9990
10045
  case "payment-option-unsupported": return `Service "${error.serviceTitle}" has a payment option that is not supported yet.`;
9991
10046
  case "service-missing-duration": return `Service "${error.serviceTitle}" is missing duration. Please update the service in the dashboard to include a duration (e.g., 30 minutes).`;
9992
- default: return assertNever(error);
10047
+ default: return assertNever$1(error);
9993
10048
  }
9994
10049
  }
9995
10050
  const DEFAULT_BOOKING_SUCCESS_COPY = {
@@ -10242,7 +10297,7 @@ function availableDatesReducer(state, action) {
10242
10297
  data: state.data,
10243
10298
  message: action.message
10244
10299
  };
10245
- default: return assertNever(action);
10300
+ default: return assertNever$1(action);
10246
10301
  }
10247
10302
  }
10248
10303
  //#endregion
@@ -10379,7 +10434,7 @@ function getAvailableSlots(state) {
10379
10434
  case "loaded":
10380
10435
  case "refreshing":
10381
10436
  case "error": return state.slots;
10382
- default: return assertNever(state);
10437
+ default: return assertNever$1(state);
10383
10438
  }
10384
10439
  }
10385
10440
  function hasLoadedAvailableSlots(state) {
@@ -10389,7 +10444,7 @@ function hasLoadedAvailableSlots(state) {
10389
10444
  case "refreshing":
10390
10445
  case "error": return state.hasLoaded;
10391
10446
  case "loaded": return true;
10392
- default: return assertNever(state);
10447
+ default: return assertNever$1(state);
10393
10448
  }
10394
10449
  }
10395
10450
  function isLoadingAvailableSlots(state) {
@@ -10423,7 +10478,7 @@ function availableSlotsReducer(state, action) {
10423
10478
  hasLoaded: hasLoadedAvailableSlots(state),
10424
10479
  message: action.message
10425
10480
  };
10426
- default: return assertNever(action);
10481
+ default: return assertNever$1(action);
10427
10482
  }
10428
10483
  }
10429
10484
  //#endregion
@@ -10518,6 +10573,19 @@ function useAvailableSlots({ siteId: _siteId, serviceId, resourceId, selectedDat
10518
10573
  };
10519
10574
  }
10520
10575
  //#endregion
10576
+ //#region ../blocks/src/system/runtime/hooks/useBookingNowIso.ts
10577
+ /**
10578
+ * The moment a booking or registration flow opened, as an ISO timestamp.
10579
+ *
10580
+ * Payment previews take this as their "now" so the pure view-model builders
10581
+ * never read the clock themselves. It's captured once per mount, which keeps
10582
+ * memoised previews stable across renders.
10583
+ */
10584
+ function useBookingNowIso() {
10585
+ const [nowIso] = useState(() => (/* @__PURE__ */ new Date()).toISOString());
10586
+ return nowIso;
10587
+ }
10588
+ //#endregion
10521
10589
  //#region ../blocks/src/system/runtime/hooks/useBookingSubmission.state.ts
10522
10590
  const initialBookingSubmissionState = {
10523
10591
  status: { tag: "idle" },
@@ -10539,7 +10607,7 @@ function bookingSubmissionReducer(state, action) {
10539
10607
  feedback: reportWorkflowError(state, action.message).feedback
10540
10608
  };
10541
10609
  case "feedback-cleared": return clearWorkflowFeedback(state);
10542
- default: return assertNever(action);
10610
+ default: return assertNever$1(action);
10543
10611
  }
10544
10612
  }
10545
10613
  function selectIsSubmitting(state) {
@@ -10901,6 +10969,233 @@ function useDiscountCodeUi(options) {
10901
10969
  };
10902
10970
  }
10903
10971
  //#endregion
10972
+ //#region ../commerce/src/utils/assertNever.ts
10973
+ function assertNever(value, message) {
10974
+ if (message) throw new Error(message);
10975
+ throw new Error(`Unexpected value: ${String(value)}`);
10976
+ }
10977
+ //#endregion
10978
+ //#region ../commerce/src/purchase/bookingInstalmentSchedule.ts
10979
+ function resolveBookingInitialInstalmentAmountCents(input) {
10980
+ const totalAmountCents = Math.max(0, input.totalAmountCents);
10981
+ switch (input.plan.kind) {
10982
+ case "deposit_plus_one_remainder":
10983
+ case "deposit_plus_scheduled_instalments": return clampConfiguredAmount(input.plan.depositAmountCents, totalAmountCents);
10984
+ case "equal_scheduled_instalments": return splitAmountWithRemainderInFirst(totalAmountCents, input.plan.instalmentCount)[0] ?? 0;
10985
+ default: return assertNever(input.plan);
10986
+ }
10987
+ }
10988
+ function buildBookingInstalmentSchedule(input) {
10989
+ const totalAmountCents = Math.max(0, input.totalAmountCents);
10990
+ switch (input.plan.kind) {
10991
+ case "deposit_plus_one_remainder": {
10992
+ const depositAmountCents = resolveBookingInitialInstalmentAmountCents(input);
10993
+ const remainderAmountCents = Math.max(0, totalAmountCents - depositAmountCents);
10994
+ return omitZeroAmountFutureRows([createScheduleRow({
10995
+ sequence: 1,
10996
+ stateAtBooking: "paid_today",
10997
+ dueAt: input.anchorAt,
10998
+ amountCents: depositAmountCents
10999
+ }), createScheduleRow({
11000
+ sequence: 2,
11001
+ stateAtBooking: "scheduled",
11002
+ dueAt: addIntervalPreservingMonthAnchor(input.anchorAt, input.plan.remainderDueCount, input.plan.intervalUnit),
11003
+ amountCents: remainderAmountCents
11004
+ })]);
11005
+ }
11006
+ case "deposit_plus_scheduled_instalments": {
11007
+ const plan = input.plan;
11008
+ const depositAmountCents = resolveBookingInitialInstalmentAmountCents(input);
11009
+ const instalmentAmounts = splitAmountWithRemainderInFirst(Math.max(0, totalAmountCents - depositAmountCents), plan.instalmentCount);
11010
+ return omitZeroAmountFutureRows([createScheduleRow({
11011
+ sequence: 1,
11012
+ stateAtBooking: "paid_today",
11013
+ dueAt: input.anchorAt,
11014
+ amountCents: depositAmountCents
11015
+ }), ...instalmentAmounts.map((amountCents, index) => createScheduleRow({
11016
+ sequence: index + 2,
11017
+ stateAtBooking: "scheduled",
11018
+ dueAt: addIntervalPreservingMonthAnchor(input.anchorAt, plan.intervalCount * (index + 1), plan.intervalUnit),
11019
+ amountCents
11020
+ }))]);
11021
+ }
11022
+ case "equal_scheduled_instalments": {
11023
+ const plan = input.plan;
11024
+ return omitZeroAmountFutureRows(splitAmountWithRemainderInFirst(totalAmountCents, plan.instalmentCount).map((amountCents, index) => createScheduleRow({
11025
+ sequence: index + 1,
11026
+ stateAtBooking: index === 0 ? "paid_today" : "scheduled",
11027
+ dueAt: index === 0 ? input.anchorAt : addIntervalPreservingMonthAnchor(input.anchorAt, plan.intervalCount * index, plan.intervalUnit),
11028
+ amountCents
11029
+ })));
11030
+ }
11031
+ default: return assertNever(input.plan);
11032
+ }
11033
+ }
11034
+ function createScheduleRow(input) {
11035
+ return {
11036
+ id: `payment-${input.sequence}`,
11037
+ sequence: input.sequence,
11038
+ stateAtBooking: input.stateAtBooking,
11039
+ dueAt: input.dueAt,
11040
+ amountCents: input.amountCents
11041
+ };
11042
+ }
11043
+ //#endregion
11044
+ //#region ../commerce/src/purchase/checkoutSessionMetadata.ts
11045
+ const datedOfferingSharedEngineMetadataShape = {
11046
+ datedOfferingEngineContractVersion: z.literal("shared_v1"),
11047
+ datedOfferingEngineRouteKind: z.literal("shared_whole_series_registration"),
11048
+ datedOfferingCapacityHoldId: z.string().uuid(),
11049
+ datedOfferingCapacityHoldAuditRef: z.string().uuid(),
11050
+ customerId: z.string().uuid(),
11051
+ eventSeriesId: z.string().uuid()
11052
+ };
11053
+ z.object(datedOfferingSharedEngineMetadataShape);
11054
+ const orderCheckoutSessionMetadataBaseShape = {
11055
+ type: z.literal("order"),
11056
+ site_id: z.string().uuid(),
11057
+ order_id: z.string().uuid().optional(),
11058
+ customer_email: z.string().email().optional(),
11059
+ customer_name: z.string().optional(),
11060
+ product_id: z.string().uuid().optional(),
11061
+ attendee_id: z.string().uuid().optional(),
11062
+ occurrence_id: z.string().uuid().optional(),
11063
+ tickets_count: z.string().optional(),
11064
+ notes: z.string().optional(),
11065
+ discount_redemption_id: z.string().uuid().optional(),
11066
+ discount_code_id: z.string().uuid().optional(),
11067
+ discount_code: z.string().optional(),
11068
+ discount_public_label: z.string().optional(),
11069
+ credit_reservation_id: z.string().uuid().optional(),
11070
+ credit_reserved_cents: z.string().optional(),
11071
+ discount_code_amount_cents: z.string().optional(),
11072
+ order_payment_reason: z.enum([
11073
+ "instalment_payoff",
11074
+ "flexible_balance_initial",
11075
+ "flexible_balance_paydown"
11076
+ ]).optional(),
11077
+ order_payment_plan_id: z.string().uuid().optional(),
11078
+ order_flexible_balance_contract_id: z.string().uuid().optional()
11079
+ };
11080
+ const absentDatedOfferingSharedEngineMetadataShape = {
11081
+ datedOfferingEngineContractVersion: z.never().optional(),
11082
+ datedOfferingEngineRouteKind: z.never().optional(),
11083
+ datedOfferingCapacityHoldId: z.never().optional(),
11084
+ datedOfferingCapacityHoldAuditRef: z.never().optional(),
11085
+ customerId: z.never().optional(),
11086
+ eventSeriesId: z.never().optional()
11087
+ };
11088
+ const LegacyOrderCheckoutSessionMetadataSchema = z.object({
11089
+ ...orderCheckoutSessionMetadataBaseShape,
11090
+ ...absentDatedOfferingSharedEngineMetadataShape
11091
+ });
11092
+ const SharedDatedOfferingOrderCheckoutSessionMetadataSchema = z.object({
11093
+ ...orderCheckoutSessionMetadataBaseShape,
11094
+ ...datedOfferingSharedEngineMetadataShape
11095
+ });
11096
+ z.union([SharedDatedOfferingOrderCheckoutSessionMetadataSchema, LegacyOrderCheckoutSessionMetadataSchema]);
11097
+ //#endregion
11098
+ //#region ../commerce/src/purchase/stripeCommissionMetadata.ts
11099
+ /** Reasons are payment evidence, not an independent pricing policy. */
11100
+ const STRIPE_COMMISSION_FREE_REASONS = [
11101
+ "managed_billing",
11102
+ "no_commission_plan",
11103
+ "billing_evidence_invalid",
11104
+ "fee_rounds_to_zero",
11105
+ "payment_not_stripe"
11106
+ ];
11107
+ const historicalContext = {
11108
+ currency: z.string().refine((value) => parseCurrencyCode(value) !== null).optional(),
11109
+ sourcePlanId: z.string().trim().min(1).optional()
11110
+ };
11111
+ const percentSchema = z.number().finite().min(0).max(100);
11112
+ z.discriminatedUnion("kind", [
11113
+ z.object({
11114
+ kind: z.literal("commission_free"),
11115
+ reason: z.enum(STRIPE_COMMISSION_FREE_REASONS),
11116
+ ...historicalContext
11117
+ }),
11118
+ z.object({
11119
+ kind: z.literal("application_fee_amount"),
11120
+ amountCents: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
11121
+ percent: percentSchema,
11122
+ ...historicalContext
11123
+ }),
11124
+ z.object({
11125
+ kind: z.literal("application_fee_percent"),
11126
+ percent: percentSchema,
11127
+ ...historicalContext
11128
+ })
11129
+ ]);
11130
+ toNonNegativeCents(0);
11131
+ //#endregion
11132
+ //#region ../commerce/src/purchase/event-registration-errors.ts
11133
+ const eventRegistrationErrors = {
11134
+ registrationClosed: {
11135
+ message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
11136
+ action: "none"
11137
+ },
11138
+ paymentInvestigationRequired: {
11139
+ message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
11140
+ action: "none"
11141
+ },
11142
+ paymentProviderUnavailable: {
11143
+ message: "We couldn’t reach the payment provider. Please try again in a minute.",
11144
+ action: "retry"
11145
+ },
11146
+ paymentPageUnavailable: {
11147
+ message: "We couldn’t open the payment page. Please refresh this page and try again. If this keeps happening, contact the organiser for help.",
11148
+ action: "retry"
11149
+ },
11150
+ paymentUnavailable: {
11151
+ message: "Online payment is not available for this event right now. Please contact the organiser for help with booking.",
11152
+ action: "none"
11153
+ },
11154
+ capacityChanged: {
11155
+ message: "Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.",
11156
+ action: "places"
11157
+ },
11158
+ selectionChanged: {
11159
+ message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
11160
+ action: "places"
11161
+ },
11162
+ registrationPreparationChanged: {
11163
+ message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
11164
+ action: "places"
11165
+ },
11166
+ registrationAlreadyExists: {
11167
+ message: "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser.",
11168
+ action: "portal"
11169
+ },
11170
+ holdExpired: {
11171
+ message: "Your reservation has timed out. Please check availability and choose your places again.",
11172
+ action: "start"
11173
+ },
11174
+ waitlistUnavailable: {
11175
+ message: "Sorry, the waiting list place offered in this invitation is no longer available. Please check the event for available places or contact the organiser for help.",
11176
+ action: "event"
11177
+ },
11178
+ paymentContextMismatch: {
11179
+ message: "The payment options for this event have changed. Please check the latest options before continuing.",
11180
+ action: "payment-options"
11181
+ },
11182
+ verificationFailed: {
11183
+ message: "We couldn’t confirm this request came from a person. Please refresh the page and try again.",
11184
+ action: "none"
11185
+ },
11186
+ idempotencyConflict: {
11187
+ message: "You’ve already started booking this event. Please finish in the other tab if it’s still open, or check your booking status before starting again.",
11188
+ action: "portal"
11189
+ },
11190
+ invalidCommitInput: {
11191
+ message: "We couldn’t accept your booking details. Please check the information you entered and try again. If this keeps happening, contact the organiser for help.",
11192
+ action: "details"
11193
+ }
11194
+ };
11195
+ function parseEventRegistrationErrorReason(value) {
11196
+ return typeof value === "string" && Object.prototype.hasOwnProperty.call(eventRegistrationErrors, value) ? value : null;
11197
+ }
11198
+ //#endregion
10904
11199
  //#region ../blocks/src/system/runtime/shared/bookingPaymentOptionCopy.ts
10905
11200
  function buildUpfrontBookingPaymentOptionCopy(formattedTotal) {
10906
11201
  return {
@@ -10967,16 +11262,15 @@ function resolveBookingPaymentDueNowCents(input) {
10967
11262
  switch (input.option.kind) {
10968
11263
  case "upfront": return input.totalCents;
10969
11264
  case "deferred_manual": return 0;
10970
- case "instalment_plan": return buildInstalmentSchedulePreview({
10971
- totalCents: input.totalCents,
10972
- option: input.option,
10973
- bookingStartAt: input.bookingStartAt
10974
- })[0]?.amountCents ?? input.totalCents;
11265
+ case "instalment_plan": return resolveBookingInitialInstalmentAmountCents({
11266
+ totalAmountCents: input.totalCents,
11267
+ plan: input.option.plan
11268
+ });
10975
11269
  case "flexible_balance": return resolveFlexibleBalanceInitialPaymentCents({
10976
11270
  totalAmountCents: input.totalCents,
10977
11271
  config: input.option.config
10978
11272
  });
10979
- default: return assertNever(input.option);
11273
+ default: return assertNever$1(input.option);
10980
11274
  }
10981
11275
  }
10982
11276
  function buildBookingPaymentSelectionViewModel(input) {
@@ -10993,6 +11287,7 @@ function buildBookingPaymentSelectionViewModel(input) {
10993
11287
  totalCents,
10994
11288
  currency,
10995
11289
  bookingStartAt: input.bookingStartAt,
11290
+ nowIso: input.nowIso,
10996
11291
  locale: input.locale
10997
11292
  }))
10998
11293
  };
@@ -11035,17 +11330,12 @@ function buildBookingPaymentOptionViewModel(input) {
11035
11330
  };
11036
11331
  }
11037
11332
  case "instalment_plan": {
11038
- const schedulePreview = buildInstalmentSchedulePreview({
11039
- totalCents: input.totalCents,
11040
- option: input.option,
11041
- bookingStartAt: input.bookingStartAt
11042
- });
11043
- const dueToday = resolveBookingPaymentDueNowCents({
11044
- option: input.option,
11045
- totalCents: input.totalCents,
11046
- bookingStartAt: input.bookingStartAt
11333
+ const [firstRow, ...futureRows] = buildBookingInstalmentSchedule({
11334
+ anchorAt: input.nowIso,
11335
+ totalAmountCents: input.totalCents,
11336
+ plan: input.option.plan
11047
11337
  });
11048
- const futureRows = schedulePreview.slice(1);
11338
+ const dueToday = firstRow?.amountCents ?? 0;
11049
11339
  const formattedTotal = formatPrice(input.totalCents, input.currency, input.locale);
11050
11340
  const formattedDueToday = formatPrice(dueToday, input.currency, input.locale);
11051
11341
  const depositRefundability = getBookingInstalmentDepositRefundability(input.option.plan);
@@ -11092,7 +11382,7 @@ function buildBookingPaymentOptionViewModel(input) {
11092
11382
  const formattedDueToday = formatPrice(dueToday, input.currency, input.locale);
11093
11383
  const formattedRemainingBalance = formatPrice(remainingBalance, input.currency, input.locale);
11094
11384
  const dueAt = resolveFlexibleBalanceDueAt({
11095
- bookingStartAt: input.bookingStartAt ?? (/* @__PURE__ */ new Date()).toISOString(),
11385
+ bookingStartAt: input.bookingStartAt ?? input.nowIso,
11096
11386
  dueDateRule: input.option.config.dueDateRule
11097
11387
  });
11098
11388
  const copy = buildFlexibleBalanceBookingPaymentOptionCopy({
@@ -11130,43 +11420,7 @@ function buildBookingPaymentOptionViewModel(input) {
11130
11420
  ctaLabel: copy.ctaLabel
11131
11421
  };
11132
11422
  }
11133
- default: return assertNever(input.option);
11134
- }
11135
- }
11136
- function buildInstalmentSchedulePreview(input) {
11137
- const startAt = input.bookingStartAt ?? (/* @__PURE__ */ new Date()).toISOString();
11138
- switch (input.option.plan.kind) {
11139
- case "deposit_plus_one_remainder": {
11140
- const deposit = clampConfiguredAmount(input.option.plan.depositAmountCents, input.totalCents);
11141
- const remainder = Math.max(0, input.totalCents - deposit);
11142
- return compactSchedulePreview([{
11143
- dueAt: startAt,
11144
- amountCents: deposit
11145
- }, {
11146
- dueAt: addIntervalPreservingMonthAnchor(startAt, input.option.plan.remainderDueCount, input.option.plan.intervalUnit),
11147
- amountCents: remainder
11148
- }]);
11149
- }
11150
- case "deposit_plus_scheduled_instalments": {
11151
- const plan = input.option.plan;
11152
- const deposit = clampConfiguredAmount(plan.depositAmountCents, input.totalCents);
11153
- const instalments = splitAmountWithRemainderInFirst(Math.max(0, input.totalCents - deposit), plan.instalmentCount);
11154
- return compactSchedulePreview([{
11155
- dueAt: startAt,
11156
- amountCents: deposit
11157
- }, ...instalments.map((amountCents, index) => ({
11158
- dueAt: addIntervalPreservingMonthAnchor(startAt, plan.intervalCount * (index + 1), plan.intervalUnit),
11159
- amountCents
11160
- }))]);
11161
- }
11162
- case "equal_scheduled_instalments": {
11163
- const plan = input.option.plan;
11164
- return compactSchedulePreview(splitAmountWithRemainderInFirst(input.totalCents, plan.instalmentCount).map((amountCents, index) => ({
11165
- dueAt: index === 0 ? startAt : addIntervalPreservingMonthAnchor(startAt, plan.intervalCount * index, plan.intervalUnit),
11166
- amountCents
11167
- })));
11168
- }
11169
- default: return assertNever(input.option.plan);
11423
+ default: return assertNever$1(input.option);
11170
11424
  }
11171
11425
  }
11172
11426
  function getPaymentCadenceLabel(plan) {
@@ -11174,9 +11428,6 @@ function getPaymentCadenceLabel(plan) {
11174
11428
  const unitLabel = intervalCount === 1 ? plan.intervalUnit : `${plan.intervalUnit}s`;
11175
11429
  return intervalCount === 1 ? unitLabel : `every ${intervalCount} ${unitLabel}`;
11176
11430
  }
11177
- function compactSchedulePreview(schedule) {
11178
- return omitZeroAmountFutureRows(schedule);
11179
- }
11180
11431
  function formatScheduleDate(isoString, locale) {
11181
11432
  const date = new Date(isoString);
11182
11433
  if (!Number.isFinite(date.getTime())) return isoString;
@@ -11459,7 +11710,7 @@ function bookingFlowReducer(state, event) {
11459
11710
  phase: "editing"
11460
11711
  } : state;
11461
11712
  case "reset": return event.initial;
11462
- default: return assertNever(event);
11713
+ default: return assertNever$1(event);
11463
11714
  }
11464
11715
  }
11465
11716
  function applyBookingServiceSelection(state, serviceId) {
@@ -11629,7 +11880,7 @@ function validateBookingStep(input) {
11629
11880
  errors: createFieldBookingValidationErrors(errors)
11630
11881
  } : { ok: true };
11631
11882
  }
11632
- default: return assertNever(input.stepId);
11883
+ default: return assertNever$1(input.stepId);
11633
11884
  }
11634
11885
  }
11635
11886
  function validateBookingFields(input) {
@@ -11929,7 +12180,7 @@ function resolveAppointmentPackagesModel(input) {
11929
12180
  selected
11930
12181
  };
11931
12182
  }
11932
- default: return assertNever(input.state);
12183
+ default: return assertNever$1(input.state);
11933
12184
  }
11934
12185
  }
11935
12186
  function toHeadlessEligibleAppointmentPackage(appointmentPackage) {
@@ -12484,13 +12735,16 @@ function useHeadlessBookingFlow(options) {
12484
12735
  defaultServiceId,
12485
12736
  options.services
12486
12737
  ]);
12738
+ const bookingNowIso = useBookingNowIso();
12487
12739
  const paymentSelection = useMemo(() => selectedService && paymentResolution.mode !== "unsupported" ? buildBookingPaymentSelectionViewModel({
12488
12740
  serviceTitle: selectedService.title,
12489
12741
  paymentTerms: selectedService.paymentTerms,
12490
12742
  priceAmount: selectedAppointmentPriceAmount,
12491
12743
  priceCurrency: selectedService.priceCurrency,
12492
- bookingStartAt: state.selectedSlot?.startAt
12744
+ bookingStartAt: state.selectedSlot?.startAt,
12745
+ nowIso: bookingNowIso
12493
12746
  }) : null, [
12747
+ bookingNowIso,
12494
12748
  paymentResolution.mode,
12495
12749
  selectedAppointmentPriceAmount,
12496
12750
  selectedService,
@@ -12683,14 +12937,14 @@ function pollingReducer(state, action) {
12683
12937
  case "completed":
12684
12938
  case "failed":
12685
12939
  case "timeout": return state;
12686
- default: return assertNever(state);
12940
+ default: return assertNever$1(state);
12687
12941
  }
12688
12942
  case "polling-timed-out": return {
12689
12943
  tag: "timeout",
12690
12944
  result: state.result,
12691
12945
  error: /* @__PURE__ */ new Error("Polling timed out")
12692
12946
  };
12693
- default: return assertNever(action);
12947
+ default: return assertNever$1(action);
12694
12948
  }
12695
12949
  }
12696
12950
  //#endregion
@@ -14318,7 +14572,7 @@ function DefaultServiceChoices({ booking }) {
14318
14572
  })]
14319
14573
  }, group.key))
14320
14574
  });
14321
- default: return assertNever(layout);
14575
+ default: return assertNever$1(layout);
14322
14576
  }
14323
14577
  }
14324
14578
  function ServiceChoiceGrid({ booking, choices }) {
@@ -14479,7 +14733,7 @@ function DefaultBookingStepContent({ booking, errorSummaryId }) {
14479
14733
  fields: booking.fields.items,
14480
14734
  booking
14481
14735
  });
14482
- default: return assertNever(stepId);
14736
+ default: return assertNever$1(stepId);
14483
14737
  }
14484
14738
  }
14485
14739
  function DefaultServiceSelectionStep({ booking }) {
@@ -15946,7 +16200,7 @@ function eligibilityLookupReducer(state, action) {
15946
16200
  settledRequestKey: null,
15947
16201
  error: action.message
15948
16202
  };
15949
- default: return assertNever(action);
16203
+ default: return assertNever$1(action);
15950
16204
  }
15951
16205
  }
15952
16206
  const initialExistingRegistrationLookupState = {
@@ -15964,7 +16218,7 @@ function existingRegistrationLookupReducer(state, action) {
15964
16218
  tag: "resolved",
15965
16219
  registration: action.registration
15966
16220
  };
15967
- default: return assertNever(action);
16221
+ default: return assertNever$1(action);
15968
16222
  }
15969
16223
  }
15970
16224
  //#endregion
@@ -16218,161 +16472,6 @@ function logoutPortal(anchorId) {
16218
16472
  form.submit();
16219
16473
  }
16220
16474
  //#endregion
16221
- //#region ../commerce/src/purchase/checkoutSessionMetadata.ts
16222
- const datedOfferingSharedEngineMetadataShape = {
16223
- datedOfferingEngineContractVersion: z.literal("shared_v1"),
16224
- datedOfferingEngineRouteKind: z.literal("shared_whole_series_registration"),
16225
- datedOfferingCapacityHoldId: z.string().uuid(),
16226
- datedOfferingCapacityHoldAuditRef: z.string().uuid(),
16227
- customerId: z.string().uuid(),
16228
- eventSeriesId: z.string().uuid()
16229
- };
16230
- z.object(datedOfferingSharedEngineMetadataShape);
16231
- const orderCheckoutSessionMetadataBaseShape = {
16232
- type: z.literal("order"),
16233
- site_id: z.string().uuid(),
16234
- order_id: z.string().uuid().optional(),
16235
- customer_email: z.string().email(),
16236
- customer_name: z.string().optional(),
16237
- product_id: z.string().uuid().optional(),
16238
- attendee_id: z.string().uuid().optional(),
16239
- occurrence_id: z.string().uuid().optional(),
16240
- tickets_count: z.string().optional(),
16241
- notes: z.string().optional(),
16242
- discount_redemption_id: z.string().uuid().optional(),
16243
- discount_code_id: z.string().uuid().optional(),
16244
- discount_code: z.string().optional(),
16245
- discount_public_label: z.string().optional(),
16246
- credit_reservation_id: z.string().uuid().optional(),
16247
- credit_reserved_cents: z.string().optional(),
16248
- discount_code_amount_cents: z.string().optional(),
16249
- order_payment_reason: z.enum([
16250
- "instalment_payoff",
16251
- "flexible_balance_initial",
16252
- "flexible_balance_paydown"
16253
- ]).optional(),
16254
- order_payment_plan_id: z.string().uuid().optional(),
16255
- order_flexible_balance_contract_id: z.string().uuid().optional()
16256
- };
16257
- const absentDatedOfferingSharedEngineMetadataShape = {
16258
- datedOfferingEngineContractVersion: z.never().optional(),
16259
- datedOfferingEngineRouteKind: z.never().optional(),
16260
- datedOfferingCapacityHoldId: z.never().optional(),
16261
- datedOfferingCapacityHoldAuditRef: z.never().optional(),
16262
- customerId: z.never().optional(),
16263
- eventSeriesId: z.never().optional()
16264
- };
16265
- const LegacyOrderCheckoutSessionMetadataSchema = z.object({
16266
- ...orderCheckoutSessionMetadataBaseShape,
16267
- ...absentDatedOfferingSharedEngineMetadataShape
16268
- });
16269
- const SharedDatedOfferingOrderCheckoutSessionMetadataSchema = z.object({
16270
- ...orderCheckoutSessionMetadataBaseShape,
16271
- ...datedOfferingSharedEngineMetadataShape
16272
- });
16273
- z.union([SharedDatedOfferingOrderCheckoutSessionMetadataSchema, LegacyOrderCheckoutSessionMetadataSchema]);
16274
- //#endregion
16275
- //#region ../commerce/src/purchase/stripeCommissionMetadata.ts
16276
- /** Reasons are payment evidence, not an independent pricing policy. */
16277
- const STRIPE_COMMISSION_FREE_REASONS = [
16278
- "managed_billing",
16279
- "no_commission_plan",
16280
- "billing_evidence_invalid",
16281
- "fee_rounds_to_zero",
16282
- "payment_not_stripe"
16283
- ];
16284
- const historicalContext = {
16285
- currency: z.string().refine((value) => parseCurrencyCode(value) !== null).optional(),
16286
- sourcePlanId: z.string().trim().min(1).optional()
16287
- };
16288
- const percentSchema = z.number().finite().min(0).max(100);
16289
- z.discriminatedUnion("kind", [
16290
- z.object({
16291
- kind: z.literal("commission_free"),
16292
- reason: z.enum(STRIPE_COMMISSION_FREE_REASONS),
16293
- ...historicalContext
16294
- }),
16295
- z.object({
16296
- kind: z.literal("application_fee_amount"),
16297
- amountCents: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
16298
- percent: percentSchema,
16299
- ...historicalContext
16300
- }),
16301
- z.object({
16302
- kind: z.literal("application_fee_percent"),
16303
- percent: percentSchema,
16304
- ...historicalContext
16305
- })
16306
- ]);
16307
- toNonNegativeCents(0);
16308
- //#endregion
16309
- //#region ../commerce/src/purchase/event-registration-errors.ts
16310
- const eventRegistrationErrors = {
16311
- registrationClosed: {
16312
- message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
16313
- action: "none"
16314
- },
16315
- paymentInvestigationRequired: {
16316
- message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
16317
- action: "none"
16318
- },
16319
- paymentProviderUnavailable: {
16320
- message: "We couldn’t reach the payment provider. Please try again in a minute.",
16321
- action: "retry"
16322
- },
16323
- paymentPageUnavailable: {
16324
- message: "We couldn’t open the payment page. Please refresh this page and try again. If this keeps happening, contact the organiser for help.",
16325
- action: "retry"
16326
- },
16327
- paymentUnavailable: {
16328
- message: "Online payment is not available for this event right now. Please contact the organiser for help with booking.",
16329
- action: "none"
16330
- },
16331
- capacityChanged: {
16332
- message: "Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.",
16333
- action: "places"
16334
- },
16335
- selectionChanged: {
16336
- message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
16337
- action: "places"
16338
- },
16339
- registrationPreparationChanged: {
16340
- message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
16341
- action: "places"
16342
- },
16343
- registrationAlreadyExists: {
16344
- message: "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser.",
16345
- action: "portal"
16346
- },
16347
- holdExpired: {
16348
- message: "Your reservation has timed out. Please check availability and choose your places again.",
16349
- action: "start"
16350
- },
16351
- waitlistUnavailable: {
16352
- message: "Sorry, the waiting list place offered in this invitation is no longer available. Please check the event for available places or contact the organiser for help.",
16353
- action: "event"
16354
- },
16355
- paymentContextMismatch: {
16356
- message: "The payment options for this event have changed. Please check the latest options before continuing.",
16357
- action: "payment-options"
16358
- },
16359
- verificationFailed: {
16360
- message: "We couldn’t confirm this request came from a person. Please refresh the page and try again.",
16361
- action: "none"
16362
- },
16363
- idempotencyConflict: {
16364
- message: "You’ve already started booking this event. Please finish in the other tab if it’s still open, or check your booking status before starting again.",
16365
- action: "portal"
16366
- },
16367
- invalidCommitInput: {
16368
- message: "We couldn’t accept your booking details. Please check the information you entered and try again. If this keeps happening, contact the organiser for help.",
16369
- action: "details"
16370
- }
16371
- };
16372
- function parseEventRegistrationErrorReason(value) {
16373
- return typeof value === "string" && Object.prototype.hasOwnProperty.call(eventRegistrationErrors, value) ? value : null;
16374
- }
16375
- //#endregion
16376
16475
  //#region ../blocks/src/system/runtime/shared/useWaitlistClaim.state.ts
16377
16476
  const DEFAULT_WAITLIST_CLAIM_ERROR = "Online booking is unavailable right now. Please contact the organiser for help with booking.";
16378
16477
  function createInitialWaitlistClaimState(hasToken) {
@@ -17293,6 +17392,7 @@ function buildEventRegistrationPaymentOptionsViewModel(input) {
17293
17392
  priceAmount: input.totalPriceCents,
17294
17393
  priceCurrency: input.currency,
17295
17394
  bookingStartAt: input.startsAt,
17395
+ nowIso: input.nowIso,
17296
17396
  locale: input.locale
17297
17397
  });
17298
17398
  return {
@@ -17300,7 +17400,7 @@ function buildEventRegistrationPaymentOptionsViewModel(input) {
17300
17400
  sectionTitle: selection.sectionTitle,
17301
17401
  options: selection.options.flatMap((option, index) => {
17302
17402
  const sourceOption = approvedOptions[index];
17303
- return sourceOption ? [toEventDirectPaymentOption(option, sourceOption, selection.mode, input.totalPriceCents, input.startsAt)] : [];
17403
+ return sourceOption ? [toEventDirectPaymentOption(option, sourceOption, selection.mode, input.totalPriceCents)] : [];
17304
17404
  })
17305
17405
  };
17306
17406
  }
@@ -17308,11 +17408,10 @@ function selectApprovedEventDirectPaymentOptions(approvedPaymentOptions, payment
17308
17408
  const approvedKinds = new Set(getApprovedDirectPaymentCollectionOptionKinds(approvedPaymentOptions));
17309
17409
  return paymentTerms.allowedOptions.filter((option) => approvedKinds.has(option.kind));
17310
17410
  }
17311
- function toEventDirectPaymentOption(option, sourceOption, mode, totalCents, startsAt) {
17411
+ function toEventDirectPaymentOption(option, sourceOption, mode, totalCents) {
17312
17412
  const configuredPaymentDueNowCents = resolveBookingPaymentDueNowCents({
17313
17413
  option: sourceOption,
17314
- totalCents,
17315
- bookingStartAt: startsAt
17414
+ totalCents
17316
17415
  });
17317
17416
  switch (option.kind) {
17318
17417
  case "upfront": return {
@@ -18299,13 +18398,15 @@ const eventRegistrationWizardDeps = {
18299
18398
  useWaitlistClaim,
18300
18399
  useEventRegistrationStripeReturn,
18301
18400
  useEventRegistrationSubmit,
18302
- useDiscountCodeUi
18401
+ useDiscountCodeUi,
18402
+ useBookingNowIso
18303
18403
  };
18304
18404
  function useEventRegistrationWizard(options) {
18305
18405
  return useEventRegistrationWizardWithDeps(options, eventRegistrationWizardDeps);
18306
18406
  }
18307
18407
  function useEventRegistrationWizardWithDeps(options, deps) {
18308
18408
  const api = useBlockApi();
18409
+ const nowIso = deps.useBookingNowIso();
18309
18410
  const registrationEvents = useMemo(() => [...toRegistrationEvents(options.events ?? []), ...toWholeSeriesRegistrationEvents(options.events ?? [])], [options.events]);
18310
18411
  const scopedEvents = useMemo(() => {
18311
18412
  return resolveEventRegistrationScopedEvents(registrationEvents, {
@@ -18836,6 +18937,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18836
18937
  });
18837
18938
  return {
18838
18939
  api,
18940
+ nowIso,
18839
18941
  anchorId: options.anchorId,
18840
18942
  occurrenceContext: options.occurrenceContext,
18841
18943
  registrationTarget,
@@ -18964,6 +19066,7 @@ function useEventRegistrationControllerWithDeps(options, deps) {
18964
19066
  const currentStep = steps.find((step) => step.state === "active") ?? null;
18965
19067
  const directPaymentOptions = useMemo(() => resolveHeadlessDirectPaymentOptions(wizard), [
18966
19068
  wizard.eligibility,
19069
+ wizard.nowIso,
18967
19070
  wizard.occurrenceContext,
18968
19071
  wizard.preSelectedEvent,
18969
19072
  wizard.selectedEvent,
@@ -19241,7 +19344,8 @@ function resolveHeadlessDirectPaymentOptions(wizard) {
19241
19344
  paymentTerms: eligibility.paymentTerms,
19242
19345
  totalPriceCents: eligibility.price,
19243
19346
  currency: eligibility.currency,
19244
- startsAt: wizard.occurrenceContext?.startsAt ?? event?.startsAt
19347
+ startsAt: wizard.occurrenceContext?.startsAt ?? event?.startsAt,
19348
+ nowIso: wizard.nowIso
19245
19349
  }).options;
19246
19350
  }
19247
19351
  //#endregion
@@ -19294,7 +19398,7 @@ function bookingFormConfigReducer(state, action) {
19294
19398
  message: action.message,
19295
19399
  previous: toBookingFormConfigSnapshot(state)
19296
19400
  };
19297
- default: return assertNever(action);
19401
+ default: return assertNever$1(action);
19298
19402
  }
19299
19403
  }
19300
19404
  function selectBookingFormConfig(state) {
@@ -19317,7 +19421,7 @@ function toBookingFormConfigSnapshot(state) {
19317
19421
  formConfig: state.formConfig,
19318
19422
  services: state.services
19319
19423
  };
19320
- default: return assertNever(state);
19424
+ default: return assertNever$1(state);
19321
19425
  }
19322
19426
  }
19323
19427
  //#endregion