@riverbankcms/sdk 0.89.1 → 0.90.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 (161) hide show
  1. package/README.md +27 -4
  2. package/dist/{PreviewEditorSidebar-JDR64FEC.mjs → PreviewEditorSidebar-KVXNF3VW.mjs} +3 -3
  3. package/dist/{PreviewEditorUI-67TMJMAF.mjs → PreviewEditorUI-J3JN5Z7T.mjs} +3 -3
  4. package/dist/SdkPreviewModeRuntime-UBL6MSNP.mjs +8 -0
  5. package/dist/_dts/ai/src/contracts/proposals.d.ts +216 -0
  6. package/dist/_dts/altcha/src/AltchaWidget.d.ts +1 -1
  7. package/dist/_dts/api/src/bookingOperations.d.ts +2 -0
  8. package/dist/_dts/api/src/bookingRecords.d.ts +4 -2
  9. package/dist/_dts/api/src/bookings.d.ts +3 -1
  10. package/dist/_dts/api/src/index.d.ts +6 -5
  11. package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +15 -5
  12. package/dist/_dts/api/src/request.d.ts +21 -0
  13. package/dist/_dts/api/src/sdk-event-upsert.d.ts +3 -1
  14. package/dist/_dts/api/src/sdkContracts.d.ts +2 -0
  15. package/dist/_dts/api/src/types.d.ts +3 -1
  16. package/dist/_dts/api/src/url.d.ts +6 -3
  17. package/dist/_dts/block-form/src/utils/visibleWhen.d.ts +1 -0
  18. package/dist/_dts/block-form/src/widgets/RepeaterField/components/RepeaterThumbnailCard.d.ts +5 -1
  19. package/dist/_dts/block-form/src/widgets/RepeaterField/components/RepeaterThumbnailGrid.d.ts +9 -1
  20. package/dist/_dts/block-form/src/widgets/RepeaterField/components/index.d.ts +1 -0
  21. package/dist/_dts/blocks/src/contracts/non-block-islands.d.ts +7 -11
  22. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +6 -0
  23. package/dist/_dts/blocks/src/index.d.ts +2 -1
  24. package/dist/_dts/blocks/src/system/blocks/events/event-calendar.d.ts +14 -6
  25. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +4 -4
  26. package/dist/_dts/blocks/src/system/blocks/hero.d.ts +0 -2
  27. package/dist/_dts/blocks/src/system/blocks/shop.d.ts +3 -3
  28. package/dist/_dts/blocks/src/system/blocks/shop.shared.d.ts +8 -0
  29. package/dist/_dts/blocks/src/system/constants/events.d.ts +4 -1
  30. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +3 -1
  31. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -0
  32. package/dist/_dts/blocks/src/system/runtime/api/types.d.ts +17 -5
  33. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +51 -6
  34. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +24 -0
  35. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationWizard.d.ts +2 -2
  36. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/logic.d.ts +1 -17
  37. package/dist/_dts/blocks/src/system/runtime/nodes/event-details.client.d.ts +5 -9
  38. package/dist/_dts/blocks/src/system/runtime/nodes/event-details.server.d.ts +5 -9
  39. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +2 -1
  40. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventPaymentOptions.d.ts +24 -0
  41. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +5 -0
  42. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useDiscountCodeUi.d.ts +4 -4
  43. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useDiscountCodeUi.state.d.ts +50 -0
  44. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +2 -2
  45. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +21 -0
  46. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.server.d.ts +1 -1
  47. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.interactive.d.ts +11 -1
  48. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +2 -1
  49. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +11 -1
  50. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/calendarViewOptions.d.ts +10 -0
  51. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventProductEligibility.d.ts +24 -0
  52. package/dist/_dts/blocks/src/system/runtime/nodes/shared/contract-schemas.d.ts +5 -2
  53. package/dist/_dts/blocks/src/system/runtime/nodes/shop-checkout-form.d.ts +2 -2
  54. package/dist/_dts/content-model/src/entry-slots/index.d.ts +1 -0
  55. package/dist/_dts/content-model/src/entry-slots/sdkBlocks.d.ts +21 -0
  56. package/dist/_dts/content-model/src/entry-slots/types.d.ts +7 -0
  57. package/dist/_dts/core/src/money-input.d.ts +18 -0
  58. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +50 -0
  59. package/dist/_dts/media-editor/src/MediaEditor.d.ts +2 -1
  60. package/dist/_dts/media-editor/src/fieldUi.d.ts +6 -0
  61. package/dist/_dts/media-editor/src/index.d.ts +1 -1
  62. package/dist/_dts/preview-next/src/client/index.d.ts +1 -0
  63. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +3 -2
  64. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +3 -2
  65. package/dist/_dts/preview-next/src/client/preview/PreviewThemedSiteDocument.d.ts +3 -2
  66. package/dist/_dts/preview-next/src/client/preview/SiteChromeEditableSurface.d.ts +2 -2
  67. package/dist/_dts/preview-next/src/client/preview/themeRuntime.d.ts +6 -0
  68. package/dist/_dts/preview-next/src/client/sdk/SdkPreviewMode.d.ts +2 -1
  69. package/dist/_dts/sdk/src/cli/commands/pull-dated-offering-scope.d.ts +10 -0
  70. package/dist/_dts/sdk/src/cli/content/reader.d.ts +12 -5
  71. package/dist/_dts/sdk/src/client/management/types.d.ts +6 -55
  72. package/dist/_dts/sdk/src/components.d.ts +1 -0
  73. package/dist/_dts/sdk/src/config/field-definitions.d.ts +3 -1
  74. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +3 -1
  75. package/dist/_dts/sdk/src/next/types.d.ts +8 -11
  76. package/dist/_dts/sdk/src/preview-next/client/index.d.ts +1 -1
  77. package/dist/_dts/sdk/src/rendering/blocks-theme-scope.d.ts +2 -1
  78. package/dist/_dts/sdk/src/rendering/components/Layout.d.ts +8 -7
  79. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +5 -6
  80. package/dist/_dts/sdk/src/rendering/index.d.ts +1 -0
  81. package/dist/_dts/sdk/src/rendering/server.d.ts +1 -0
  82. package/dist/_dts/sdk/src/rendering/themeRuntime.d.ts +26 -0
  83. package/dist/_dts/sdk/src/version.d.ts +1 -1
  84. package/dist/_dts/site-commands/src/commands.d.ts +18 -0
  85. package/dist/_dts/theme-core/src/ResponsiveScope.d.ts +12 -0
  86. package/dist/_dts/theme-core/src/accordions/types.d.ts +1 -1
  87. package/dist/_dts/theme-core/src/buttons/personalities/types.d.ts +2 -2
  88. package/dist/_dts/theme-core/src/buttons/types.d.ts +5 -5
  89. package/dist/_dts/theme-core/src/cards/types.d.ts +2 -2
  90. package/dist/_dts/theme-core/src/index.d.ts +2 -0
  91. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +21 -21
  92. package/dist/_dts/theme-core/src/schema.d.ts +18 -18
  93. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +2 -2
  94. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +2 -2
  95. package/dist/_dts/theme-core/src/site-styles/logoBranding.d.ts +4 -4
  96. package/dist/_dts/theme-core/src/themeRuntime.d.ts +11 -0
  97. package/dist/{chunk-HKJQERFR.mjs → chunk-AEOYWPE4.mjs} +91 -55
  98. package/dist/{chunk-F645A5UV.mjs → chunk-BOQXMCSP.mjs} +129 -101
  99. package/dist/{chunk-ZQRBLCW5.mjs → chunk-GSPFFUVB.mjs} +2 -2
  100. package/dist/{chunk-7YUAXONX.mjs → chunk-PMBB6MQ7.mjs} +1280 -774
  101. package/dist/{chunk-TGBJWKMP.mjs → chunk-RQ3XZ4SJ.mjs} +9 -1
  102. package/dist/{chunk-7N46MZHI.mjs → chunk-UG7I7S7W.mjs} +1 -1
  103. package/dist/cli/index.mjs +899 -531
  104. package/dist/cli/init-docs/content/cli-reference.md +6 -1
  105. package/dist/cli/init-docs/content/content-management.md +27 -0
  106. package/dist/client/{accordion-MUCVNGQ7.mjs → accordion-GXQNWQ6O.mjs} +1 -1
  107. package/dist/client/{bookingForm-PKD6EFIE.mjs → bookingForm-STLUJ36H.mjs} +25 -270
  108. package/dist/client/bookings.mjs +432 -269
  109. package/dist/client/{carousel-3TKQSNJC.mjs → carousel-CVRN6EPP.mjs} +1 -1
  110. package/dist/client/{cart-6XHSZK23.mjs → cart-IYIBA5CL.mjs} +5 -6
  111. package/dist/client/{checkout-FVSPM6FI.mjs → checkout-O3BGM4GS.mjs} +5 -6
  112. package/dist/client/chunk-4RTFGHZN.mjs +433 -0
  113. package/dist/client/{chunk-UQFY4AHX.mjs → chunk-6DPXDOIL.mjs} +65 -28
  114. package/dist/client/{chunk-ZT5XE7FK.mjs → chunk-D3ETC2SU.mjs} +1 -1
  115. package/dist/client/{chunk-CQKKFEQD.mjs → chunk-DAS5CIER.mjs} +274 -105
  116. package/dist/client/{chunk-SDIYSQAY.mjs → chunk-HIHOQGIP.mjs} +2 -3
  117. package/dist/client/{chunk-ZJZZA5EP.mjs → chunk-MFPKS6QS.mjs} +11 -14
  118. package/dist/client/{chunk-EY42X22F.mjs → chunk-NBFRJ5NB.mjs} +156 -4
  119. package/dist/client/{chunk-VGLXACVK.mjs → chunk-VFHZLZAC.mjs} +1 -1
  120. package/dist/client/{chunk-STJ2NCQM.mjs → chunk-WHZQDPBZ.mjs} +19 -1
  121. package/dist/client/{chunk-RSQWWUAD.mjs → chunk-Z62JYS5O.mjs} +3 -3
  122. package/dist/client/client.mjs +3292 -2827
  123. package/dist/client/{courseRegistration-ATZSYDHM.mjs → courseRegistration-2D3ACMJR.mjs} +18 -56
  124. package/dist/client/{eventCalendar-6T2UGKKP.mjs → eventCalendar-QY4UZUFF.mjs} +8 -9
  125. package/dist/client/{eventCombined-Q4VANXVF.mjs → eventCombined-RRCDKJC2.mjs} +8 -9
  126. package/dist/client/{eventDetails-DW37E7VW.mjs → eventDetails-YO335BUT.mjs} +8 -9
  127. package/dist/client/{eventListing-XURTSAUW.mjs → eventListing-PXA6GFQ3.mjs} +8 -9
  128. package/dist/client/{eventRegistration-MRKEVAXW.mjs → eventRegistration-2ZHEDDXO.mjs} +8 -9
  129. package/dist/client/{form-WZZFFGMU.mjs → form-ZS6KX4U2.mjs} +6 -6
  130. package/dist/client/{headerSection-EQYVQBLM.mjs → headerSection-QK5SLIIB.mjs} +2 -2
  131. package/dist/client/hooks.mjs +1084 -1029
  132. package/dist/client/{locationMap-MFF5VAZR.mjs → locationMap-GFNIUD2X.mjs} +2 -2
  133. package/dist/client/{newsletterForm-JQ77UYIE.mjs → newsletterForm-PGLTTCUG.mjs} +4 -4
  134. package/dist/client/{productDetail-25LMT3IZ.mjs → productDetail-OPBE5ZPI.mjs} +5 -6
  135. package/dist/client/{productList-5ABEMKUG.mjs → productList-NI72Q62Z.mjs} +5 -6
  136. package/dist/client/rendering/client.mjs +2692 -2285
  137. package/dist/client/rendering/islands.mjs +18 -18
  138. package/dist/client/rendering.mjs +2611 -2156
  139. package/dist/client/{shop-OMMQZ6YO.mjs → shop-3ZQPEWYI.mjs} +5 -6
  140. package/dist/client/spam-protection.mjs +4 -5
  141. package/dist/preview-next/before-render.mjs +2 -2
  142. package/dist/preview-next/client/runtime.mjs +5 -5
  143. package/dist/{sdk-runtime-WNLBZ3ZH.mjs → sdk-runtime-FSHXCWDS.mjs} +6 -6
  144. package/dist/server/components.mjs +1722 -1453
  145. package/dist/server/config-validation.mjs +1316 -1261
  146. package/dist/server/config.mjs +1316 -1261
  147. package/dist/server/data.mjs +1084 -1029
  148. package/dist/server/index.mjs +135 -100
  149. package/dist/server/navigation.mjs +20 -30
  150. package/dist/server/next.mjs +1782 -1500
  151. package/dist/server/page-converter.mjs +1009 -946
  152. package/dist/server/prebuild.mjs +1 -1
  153. package/dist/server/rendering/server.mjs +1722 -1453
  154. package/dist/server/rendering.mjs +1728 -1459
  155. package/dist/server/routing.mjs +1127 -1045
  156. package/dist/server/server.mjs +1219 -1129
  157. package/dist/server/theme-bridge.mjs +8 -5
  158. package/package.json +2 -2
  159. package/dist/SdkPreviewModeRuntime-ZBEMRV7N.mjs +0 -8
  160. package/dist/client/chunk-LQFDYWPJ.mjs +0 -184
  161. package/dist/client/chunk-ZFHRN6W2.mjs +0 -66
@@ -1,7 +1,7 @@
1
1
  import { normalizeCarouselProps, CarouselNodeClient } from './chunk-7DH35FGA.mjs';
2
2
  import './chunk-6N7YRNYU.mjs';
3
3
  import { mountReactIsland } from './chunk-N7PBWBWQ.mjs';
4
- import { defineIslandPropsDecoder } from './chunk-UQFY4AHX.mjs';
4
+ import { defineIslandPropsDecoder } from './chunk-6DPXDOIL.mjs';
5
5
  import './chunk-25W2EQUN.mjs';
6
6
  import { jsx } from 'react/jsx-runtime';
7
7
 
@@ -1,15 +1,14 @@
1
- import { mountShopBlockIsland, CartClient } from './chunk-ZJZZA5EP.mjs';
2
- import './chunk-VGLXACVK.mjs';
1
+ import { mountShopBlockIsland, CartClient } from './chunk-MFPKS6QS.mjs';
2
+ import './chunk-VFHZLZAC.mjs';
3
3
  import './chunk-7DH35FGA.mjs';
4
4
  import './chunk-6N7YRNYU.mjs';
5
- import './chunk-ZFHRN6W2.mjs';
6
5
  import './chunk-L4J5Y62O.mjs';
7
- import './chunk-EY42X22F.mjs';
6
+ import './chunk-NBFRJ5NB.mjs';
8
7
  import './chunk-3DCJ45Z2.mjs';
9
8
  import './chunk-WBQG7VJA.mjs';
10
- import './chunk-STJ2NCQM.mjs';
9
+ import './chunk-WHZQDPBZ.mjs';
11
10
  import './chunk-N7PBWBWQ.mjs';
12
- import { defineIslandPropsDecoder } from './chunk-UQFY4AHX.mjs';
11
+ import { defineIslandPropsDecoder } from './chunk-6DPXDOIL.mjs';
13
12
  import './chunk-25W2EQUN.mjs';
14
13
 
15
14
  // src/rendering/islands/enhancers/cart.tsx
@@ -1,15 +1,14 @@
1
- import { mountShopBlockIsland, CheckoutClient } from './chunk-ZJZZA5EP.mjs';
2
- import './chunk-VGLXACVK.mjs';
1
+ import { mountShopBlockIsland, CheckoutClient } from './chunk-MFPKS6QS.mjs';
2
+ import './chunk-VFHZLZAC.mjs';
3
3
  import './chunk-7DH35FGA.mjs';
4
4
  import './chunk-6N7YRNYU.mjs';
5
- import './chunk-ZFHRN6W2.mjs';
6
5
  import './chunk-L4J5Y62O.mjs';
7
- import './chunk-EY42X22F.mjs';
6
+ import './chunk-NBFRJ5NB.mjs';
8
7
  import './chunk-3DCJ45Z2.mjs';
9
8
  import './chunk-WBQG7VJA.mjs';
10
- import './chunk-STJ2NCQM.mjs';
9
+ import './chunk-WHZQDPBZ.mjs';
11
10
  import './chunk-N7PBWBWQ.mjs';
12
- import { defineIslandPropsDecoder } from './chunk-UQFY4AHX.mjs';
11
+ import { defineIslandPropsDecoder } from './chunk-6DPXDOIL.mjs';
13
12
  import './chunk-25W2EQUN.mjs';
14
13
 
15
14
  // src/rendering/islands/enhancers/checkout.tsx
@@ -0,0 +1,433 @@
1
+ "use client";
2
+ import { formatPrice } from './chunk-NBFRJ5NB.mjs';
3
+ import { assertNever } from './chunk-6DPXDOIL.mjs';
4
+ import { resolveFlexibleBalanceInitialPaymentCents, resolveFlexibleBalanceDueAt, getBookingInstalmentDepositRefundability, splitAmountWithRemainderInFirst, addIntervalPreservingMonthAnchor, clampConfiguredAmount, getBookingInstalmentPlanIntervalCount, omitZeroAmountFutureRows } from './chunk-25W2EQUN.mjs';
5
+ import { useReducer, useRef, useCallback, useEffect } from 'react';
6
+
7
+ // ../blocks/src/system/runtime/shared/bookingPaymentOptionCopy.ts
8
+ function buildUpfrontBookingPaymentOptionCopy(formattedTotal) {
9
+ return {
10
+ title: "Pay in full",
11
+ description: "Pay everything today and your booking is confirmed.",
12
+ ctaLabel: `Pay ${formattedTotal} now`
13
+ };
14
+ }
15
+ function buildDeferredManualBookingPaymentOptionCopy() {
16
+ return {
17
+ title: "Pay offline",
18
+ description: "Book now and pay the business later, outside the platform.",
19
+ helperText: "Nothing is due today.",
20
+ ctaLabel: "Book now"
21
+ };
22
+ }
23
+ function buildInstalmentBookingPaymentOptionCopy(input) {
24
+ return {
25
+ title: "Payment plan",
26
+ description: describeInstalmentPlanCopy(input),
27
+ helperText: "You can pay the rest early any time in your customer portal.",
28
+ ctaLabel: `Pay ${input.formattedDueToday} now`
29
+ };
30
+ }
31
+ function describeInstalmentPlanCopy(input) {
32
+ if (input.depositRefundability) {
33
+ return `Pay ${input.formattedDueToday} today, then continue with scheduled payments. Your deposit is ${formatDepositRefundabilityLabel(input.depositRefundability)}.`;
34
+ }
35
+ if (input.futurePaymentCount === 0) {
36
+ return `Pay ${input.formattedDueToday} today.`;
37
+ }
38
+ if (input.futurePaymentCount === 1) {
39
+ return `Pay ${input.formattedDueToday} today, then one more payment later.`;
40
+ }
41
+ const formattedFirstFuture = input.formattedFirstFuture ?? input.formattedDueToday;
42
+ return `Pay ${input.formattedDueToday} today, then ${input.futurePaymentCount} more ${input.cadenceLabel} payments from ${formattedFirstFuture}.`;
43
+ }
44
+ function buildFlexibleBalanceBookingPaymentOptionCopy(input) {
45
+ return {
46
+ title: "Deposit now, pay the rest later",
47
+ description: `Pay ${input.formattedDueToday} today, then pay the remaining balance any time before ${input.dueDateLabel}. Your deposit is ${formatDepositRefundabilityLabel(input.depositRefundability)}.`,
48
+ helperText: "You can return in your customer portal to pay the rest before the due date.",
49
+ ctaLabel: `Pay ${input.formattedDueToday} now`
50
+ };
51
+ }
52
+ function formatDepositRefundabilityLabel(depositRefundability) {
53
+ return depositRefundability === "non_refundable" ? "non-refundable" : "refundable";
54
+ }
55
+
56
+ // ../blocks/src/system/runtime/shared/bookingPaymentOptions.ts
57
+ function buildBookingPaymentSelectionViewModel(input) {
58
+ const currency = input.priceCurrency ?? "USD";
59
+ const totalCents = Math.max(0, input.priceAmount ?? 0);
60
+ const allowedOptions = input.paymentTerms?.allowedOptions ?? [{ kind: "upfront" }];
61
+ const mode = allowedOptions.length > 1 ? "choice_required" : "single_option";
62
+ return {
63
+ mode,
64
+ sectionTitle: mode === "choice_required" ? "Choose how you'd like to pay" : "Payment",
65
+ serviceTitle: input.serviceTitle,
66
+ options: allowedOptions.map((option) => buildBookingPaymentOptionViewModel({
67
+ option,
68
+ totalCents,
69
+ currency,
70
+ bookingStartAt: input.bookingStartAt,
71
+ locale: input.locale
72
+ }))
73
+ };
74
+ }
75
+ function buildBookingPaymentOptionViewModel(input) {
76
+ switch (input.option.kind) {
77
+ case "upfront": {
78
+ const formattedTotal = formatPrice(input.totalCents, input.currency, input.locale);
79
+ const copy = buildUpfrontBookingPaymentOptionCopy(formattedTotal);
80
+ return {
81
+ kind: "upfront",
82
+ title: copy.title,
83
+ description: copy.description,
84
+ summaryRows: [
85
+ { label: "Total", value: formattedTotal },
86
+ { label: "Due today", value: formattedTotal }
87
+ ],
88
+ ctaLabel: copy.ctaLabel
89
+ };
90
+ }
91
+ case "deferred_manual": {
92
+ const formattedTotal = formatPrice(input.totalCents, input.currency, input.locale);
93
+ const copy = buildDeferredManualBookingPaymentOptionCopy();
94
+ return {
95
+ kind: "deferred_manual",
96
+ title: copy.title,
97
+ description: copy.description,
98
+ summaryRows: [
99
+ { label: "Total", value: formattedTotal },
100
+ { label: "Due today", value: formatPrice(0, input.currency, input.locale) }
101
+ ],
102
+ helperText: copy.helperText,
103
+ ctaLabel: copy.ctaLabel
104
+ };
105
+ }
106
+ case "instalment_plan": {
107
+ const schedulePreview = buildInstalmentSchedulePreview({
108
+ totalCents: input.totalCents,
109
+ option: input.option,
110
+ bookingStartAt: input.bookingStartAt
111
+ });
112
+ const dueToday = schedulePreview[0]?.amountCents ?? input.totalCents;
113
+ const futureRows = schedulePreview.slice(1);
114
+ const formattedTotal = formatPrice(input.totalCents, input.currency, input.locale);
115
+ const formattedDueToday = formatPrice(dueToday, input.currency, input.locale);
116
+ const depositRefundability = getBookingInstalmentDepositRefundability(input.option.plan);
117
+ const copy = buildInstalmentBookingPaymentOptionCopy({
118
+ formattedDueToday,
119
+ futurePaymentCount: futureRows.length,
120
+ formattedFirstFuture: futureRows[0] ? formatPrice(futureRows[0].amountCents, input.currency, input.locale) : null,
121
+ cadenceLabel: getPaymentCadenceLabel(input.option.plan),
122
+ depositRefundability
123
+ });
124
+ return {
125
+ kind: "instalment_plan",
126
+ title: copy.title,
127
+ description: copy.description,
128
+ summaryRows: [
129
+ { label: "Total", value: formattedTotal },
130
+ { label: "Due today", value: formattedDueToday },
131
+ ...depositRefundability ? [{
132
+ label: "Deposit policy",
133
+ value: depositRefundability === "non_refundable" ? "Non-refundable" : "Refundable"
134
+ }] : [],
135
+ ...futureRows.map((row) => ({
136
+ label: formatScheduleDate(row.dueAt, input.locale),
137
+ value: formatPrice(row.amountCents, input.currency, input.locale)
138
+ }))
139
+ ],
140
+ helperText: copy.helperText,
141
+ ctaLabel: copy.ctaLabel
142
+ };
143
+ }
144
+ case "flexible_balance": {
145
+ const dueToday = resolveFlexibleBalanceInitialPaymentCents({
146
+ totalAmountCents: input.totalCents,
147
+ config: input.option.config
148
+ });
149
+ const formattedTotal = formatPrice(input.totalCents, input.currency, input.locale);
150
+ const formattedDueToday = formatPrice(dueToday, input.currency, input.locale);
151
+ const dueAt = resolveFlexibleBalanceDueAt({
152
+ bookingStartAt: input.bookingStartAt ?? (/* @__PURE__ */ new Date()).toISOString(),
153
+ dueDateRule: input.option.config.dueDateRule
154
+ });
155
+ const copy = buildFlexibleBalanceBookingPaymentOptionCopy({
156
+ formattedDueToday,
157
+ dueDateLabel: formatScheduleDate(dueAt, input.locale),
158
+ depositRefundability: input.option.config.depositRefundability
159
+ });
160
+ return {
161
+ kind: "flexible_balance",
162
+ title: copy.title,
163
+ description: copy.description,
164
+ summaryRows: [
165
+ { label: "Total", value: formattedTotal },
166
+ { label: "Due today", value: formattedDueToday },
167
+ { label: "Balance due by", value: formatScheduleDate(dueAt, input.locale) },
168
+ {
169
+ label: "Deposit policy",
170
+ value: input.option.config.depositRefundability === "non_refundable" ? "Non-refundable" : "Refundable"
171
+ }
172
+ ],
173
+ helperText: copy.helperText,
174
+ ctaLabel: copy.ctaLabel
175
+ };
176
+ }
177
+ default:
178
+ return assertNever(input.option);
179
+ }
180
+ }
181
+ function buildInstalmentSchedulePreview(input) {
182
+ const startAt = input.bookingStartAt ?? (/* @__PURE__ */ new Date()).toISOString();
183
+ switch (input.option.plan.kind) {
184
+ case "deposit_plus_one_remainder": {
185
+ const deposit = clampConfiguredAmount(input.option.plan.depositAmountCents, input.totalCents);
186
+ const remainder = Math.max(0, input.totalCents - deposit);
187
+ return compactSchedulePreview([
188
+ { dueAt: startAt, amountCents: deposit },
189
+ {
190
+ dueAt: addIntervalPreservingMonthAnchor(
191
+ startAt,
192
+ input.option.plan.remainderDueCount,
193
+ input.option.plan.intervalUnit
194
+ ),
195
+ amountCents: remainder
196
+ }
197
+ ]);
198
+ }
199
+ case "deposit_plus_scheduled_instalments": {
200
+ const plan = input.option.plan;
201
+ const deposit = clampConfiguredAmount(plan.depositAmountCents, input.totalCents);
202
+ const remaining = Math.max(0, input.totalCents - deposit);
203
+ const instalments = splitAmountWithRemainderInFirst(
204
+ remaining,
205
+ plan.instalmentCount
206
+ );
207
+ return compactSchedulePreview([
208
+ { dueAt: startAt, amountCents: deposit },
209
+ ...instalments.map((amountCents, index) => ({
210
+ dueAt: addIntervalPreservingMonthAnchor(
211
+ startAt,
212
+ plan.intervalCount * (index + 1),
213
+ plan.intervalUnit
214
+ ),
215
+ amountCents
216
+ }))
217
+ ]);
218
+ }
219
+ case "equal_scheduled_instalments": {
220
+ const plan = input.option.plan;
221
+ const instalments = splitAmountWithRemainderInFirst(
222
+ input.totalCents,
223
+ plan.instalmentCount
224
+ );
225
+ return compactSchedulePreview(instalments.map((amountCents, index) => ({
226
+ dueAt: index === 0 ? startAt : addIntervalPreservingMonthAnchor(
227
+ startAt,
228
+ plan.intervalCount * index,
229
+ plan.intervalUnit
230
+ ),
231
+ amountCents
232
+ })));
233
+ }
234
+ default:
235
+ return assertNever(input.option.plan);
236
+ }
237
+ }
238
+ function getPaymentCadenceLabel(plan) {
239
+ const intervalCount = getBookingInstalmentPlanIntervalCount(plan);
240
+ const unitLabel = intervalCount === 1 ? plan.intervalUnit : `${plan.intervalUnit}s`;
241
+ return intervalCount === 1 ? unitLabel : `every ${intervalCount} ${unitLabel}`;
242
+ }
243
+ function compactSchedulePreview(schedule) {
244
+ return omitZeroAmountFutureRows(schedule);
245
+ }
246
+ function formatScheduleDate(isoString, locale) {
247
+ const date = new Date(isoString);
248
+ if (!Number.isFinite(date.getTime())) {
249
+ return isoString;
250
+ }
251
+ return new Intl.DateTimeFormat(locale, { dateStyle: "medium" }).format(date);
252
+ }
253
+
254
+ // ../blocks/src/system/runtime/hooks/usePolling.state.ts
255
+ function createInitialPollingState() {
256
+ return {
257
+ tag: "idle",
258
+ result: null,
259
+ error: null
260
+ };
261
+ }
262
+ function pollingReducer(state, action) {
263
+ switch (action.type) {
264
+ case "polling-went-idle":
265
+ return createInitialPollingState();
266
+ case "polling-reset":
267
+ return {
268
+ tag: "polling",
269
+ result: null,
270
+ error: null
271
+ };
272
+ case "polling-progressed":
273
+ return {
274
+ tag: "polling",
275
+ result: action.result,
276
+ error: null
277
+ };
278
+ case "polling-completed":
279
+ return {
280
+ tag: "completed",
281
+ result: action.result,
282
+ error: null
283
+ };
284
+ case "polling-failed":
285
+ return {
286
+ tag: "failed",
287
+ result: action.result,
288
+ error: null
289
+ };
290
+ case "polling-request-failed":
291
+ switch (state.tag) {
292
+ case "idle":
293
+ return {
294
+ tag: "polling",
295
+ result: null,
296
+ error: action.error
297
+ };
298
+ case "polling":
299
+ return {
300
+ tag: "polling",
301
+ result: state.result,
302
+ error: action.error
303
+ };
304
+ case "completed":
305
+ case "failed":
306
+ case "timeout":
307
+ return state;
308
+ default:
309
+ return assertNever(state);
310
+ }
311
+ case "polling-timed-out":
312
+ return {
313
+ tag: "timeout",
314
+ result: state.result,
315
+ error: new Error("Polling timed out")
316
+ };
317
+ default:
318
+ return assertNever(action);
319
+ }
320
+ }
321
+
322
+ // ../blocks/src/system/runtime/hooks/usePolling.ts
323
+ var DEFAULT_MAX_ATTEMPTS = 10;
324
+ var DEFAULT_POLL_INTERVAL = 1e3;
325
+ function usePolling(config) {
326
+ const [state, dispatch] = useReducer(
327
+ pollingReducer,
328
+ void 0,
329
+ createInitialPollingState
330
+ );
331
+ const attemptsRef = useRef(0);
332
+ const timeoutRef = useRef(null);
333
+ const isPollingRef = useRef(false);
334
+ const isActiveRef = useRef(false);
335
+ const generationRef = useRef(0);
336
+ const configRef = useRef(config);
337
+ configRef.current = config;
338
+ const cleanup = useCallback(() => {
339
+ isActiveRef.current = false;
340
+ generationRef.current += 1;
341
+ if (timeoutRef.current) {
342
+ clearTimeout(timeoutRef.current);
343
+ timeoutRef.current = null;
344
+ }
345
+ isPollingRef.current = false;
346
+ }, []);
347
+ const resetState = useCallback(() => {
348
+ dispatch({ type: "polling-reset" });
349
+ attemptsRef.current = 0;
350
+ }, []);
351
+ const poll = useCallback(async () => {
352
+ const cfg = configRef.current;
353
+ if (!cfg) return true;
354
+ if (isPollingRef.current) return false;
355
+ const maxAttempts = cfg.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
356
+ if (attemptsRef.current >= maxAttempts) {
357
+ dispatch({ type: "polling-timed-out" });
358
+ cleanup();
359
+ return true;
360
+ }
361
+ isPollingRef.current = true;
362
+ attemptsRef.current += 1;
363
+ const generation = generationRef.current;
364
+ try {
365
+ const data = await cfg.pollFn();
366
+ if (generation !== generationRef.current || !isActiveRef.current) {
367
+ isPollingRef.current = false;
368
+ return true;
369
+ }
370
+ if (cfg.isFailed?.(data)) {
371
+ dispatch({ type: "polling-failed", result: data });
372
+ cleanup();
373
+ return true;
374
+ }
375
+ if (cfg.isComplete(data)) {
376
+ dispatch({ type: "polling-completed", result: data });
377
+ cleanup();
378
+ return true;
379
+ }
380
+ dispatch({ type: "polling-progressed", result: data });
381
+ isPollingRef.current = false;
382
+ return false;
383
+ } catch (err) {
384
+ if (generation !== generationRef.current || !isActiveRef.current) {
385
+ isPollingRef.current = false;
386
+ return true;
387
+ }
388
+ if (err instanceof Error) {
389
+ dispatch({ type: "polling-request-failed", error: err });
390
+ }
391
+ isPollingRef.current = false;
392
+ return false;
393
+ }
394
+ }, [cleanup]);
395
+ const schedulePoll = useCallback(() => {
396
+ if (!isActiveRef.current) return;
397
+ const cfg = configRef.current;
398
+ const pollInterval = cfg?.interval ?? DEFAULT_POLL_INTERVAL;
399
+ const doPoll = async () => {
400
+ const shouldStop = await poll();
401
+ if (!shouldStop && isActiveRef.current) {
402
+ timeoutRef.current = setTimeout(doPoll, pollInterval);
403
+ }
404
+ };
405
+ void doPoll();
406
+ }, [poll]);
407
+ useEffect(() => {
408
+ if (!config) {
409
+ cleanup();
410
+ dispatch({ type: "polling-went-idle" });
411
+ return;
412
+ }
413
+ resetState();
414
+ isActiveRef.current = true;
415
+ schedulePoll();
416
+ return cleanup;
417
+ }, [config, cleanup, resetState, schedulePoll]);
418
+ const retry = useCallback(() => {
419
+ if (!configRef.current) return;
420
+ cleanup();
421
+ resetState();
422
+ isActiveRef.current = true;
423
+ schedulePoll();
424
+ }, [cleanup, resetState, schedulePoll]);
425
+ return {
426
+ status: config ? state.tag : "idle",
427
+ result: config ? state.result : null,
428
+ error: config ? state.error : null,
429
+ retry
430
+ };
431
+ }
432
+
433
+ export { buildBookingPaymentSelectionViewModel, usePolling };