@riverbankcms/sdk 0.91.0 → 0.92.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 (104) hide show
  1. package/dist/{PreviewEditorSidebar-3TT47WCF.mjs → PreviewEditorSidebar-3CI5MKV3.mjs} +2 -2
  2. package/dist/{PreviewEditorUI-ORCLLUNZ.mjs → PreviewEditorUI-DKEP636I.mjs} +2 -2
  3. package/dist/SdkPreviewModeRuntime-BRGRDQFH.mjs +8 -0
  4. package/dist/_dts/api/src/bookingConfig.d.ts +13 -1
  5. package/dist/_dts/api/src/bookingOperations.d.ts +1 -0
  6. package/dist/_dts/api/src/bookingRefundOutcomes.d.ts +6 -6
  7. package/dist/_dts/api/src/customerMembershipOutcomes.d.ts +4 -4
  8. package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +6 -0
  9. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +32 -0
  10. package/dist/_dts/blocks/src/system/blocks/courses/shared/pricing.d.ts +12 -1
  11. package/dist/_dts/blocks/src/system/blocks/courses/shared/schemas.d.ts +12 -0
  12. package/dist/_dts/blocks/src/system/blocks/courses/shared/types.d.ts +4 -1
  13. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +44 -0
  14. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +7 -0
  15. package/dist/_dts/blocks/src/system/runtime/api/types.d.ts +8 -1
  16. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.d.ts +8 -1
  17. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.state.d.ts +1 -0
  18. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +4 -0
  19. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.interactive.d.ts +40 -0
  20. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.reserved-fields.d.ts +1 -1
  21. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.state.d.ts +29 -0
  22. package/dist/_dts/blocks/src/system/runtime/nodes/booking-runtime-sources.d.ts +1 -0
  23. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/components.d.ts +6 -0
  24. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationWizard.d.ts +8 -0
  25. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/TicketSelectionStep.d.ts +8 -0
  26. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.d.ts +1 -0
  27. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +1 -1
  28. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +1 -0
  29. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +9 -0
  30. package/dist/_dts/content-model/src/entry-slots/types.d.ts +110 -2
  31. package/dist/_dts/core/src/branded.d.ts +3 -0
  32. package/dist/_dts/core/src/event-pricing.d.ts +18 -1
  33. package/dist/_dts/core/src/money-input.d.ts +34 -4
  34. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +70 -0
  35. package/dist/_dts/media-core/src/fileAssetCompatibility.d.ts +1 -1
  36. package/dist/_dts/media-core/src/filePersistence.d.ts +5 -1
  37. package/dist/_dts/media-core/src/fileStorage.d.ts +1 -0
  38. package/dist/_dts/media-core/src/videoPrep.d.ts +15 -6
  39. package/dist/_dts/media-core/src/videoSlotPolicy.d.ts +5 -5
  40. package/dist/_dts/sdk/src/cli/commands/push/execute/diff.d.ts +2 -0
  41. package/dist/_dts/sdk/src/cli/commands/push/execute/localMediaReporting.d.ts +23 -0
  42. package/dist/_dts/sdk/src/cli/commands/push/scopes/commandBackedDatedOfferingScope.d.ts +54 -0
  43. package/dist/_dts/sdk/src/cli/commands/push/scopes/mediaPrep.d.ts +7 -2
  44. package/dist/_dts/sdk/src/cli/commands/push/scopes/types.d.ts +6 -0
  45. package/dist/_dts/sdk/src/cli/media/local-sync.d.ts +35 -0
  46. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +23 -1
  47. package/dist/_dts/sdk/src/version.d.ts +1 -1
  48. package/dist/{chunk-AFPMCLS7.mjs → chunk-6D7PLF4M.mjs} +1 -1
  49. package/dist/{chunk-RQUZYSES.mjs → chunk-I6EOKV6B.mjs} +520 -40
  50. package/dist/{chunk-S3YHJWEU.mjs → chunk-LERKJM3E.mjs} +5 -5
  51. package/dist/{chunk-GDT2QGIL.mjs → chunk-UOMTCHZD.mjs} +1 -1
  52. package/dist/cli/index.mjs +552 -80
  53. package/dist/client/{accordion-AFX37652.mjs → accordion-BUDH2G3S.mjs} +2 -2
  54. package/dist/client/{bookingForm-32V5QCOW.mjs → bookingForm-NQMCELVB.mjs} +89 -14
  55. package/dist/client/bookings.mjs +243 -17
  56. package/dist/client/{carousel-TJGQJ7ER.mjs → carousel-ONCEW6IJ.mjs} +3 -3
  57. package/dist/client/{cart-JUU2JEW4.mjs → cart-V2TCK2GI.mjs} +7 -7
  58. package/dist/client/{checkout-RD6BTFX4.mjs → checkout-ZI7SWNCS.mjs} +7 -7
  59. package/dist/client/{chunk-FMZZHAIR.mjs → chunk-AUMRQ242.mjs} +52 -5
  60. package/dist/client/{chunk-PMNAV6LO.mjs → chunk-B5UC2D6X.mjs} +7 -6
  61. package/dist/client/{chunk-6RN62XBV.mjs → chunk-ERQDHUS2.mjs} +1 -1
  62. package/dist/client/{chunk-RWYFG625.mjs → chunk-GH6IIOOE.mjs} +30 -2
  63. package/dist/client/{chunk-C4LP6BPG.mjs → chunk-HQWIJLYN.mjs} +1 -1
  64. package/dist/client/{chunk-RMOFBBNA.mjs → chunk-JXY6NHG6.mjs} +6 -6
  65. package/dist/client/{chunk-6QZIBNGV.mjs → chunk-KXYEKEV6.mjs} +154 -16
  66. package/dist/client/{chunk-E6VIWZUG.mjs → chunk-N2WJPTF7.mjs} +3 -3
  67. package/dist/client/{chunk-ISAUXU5R.mjs → chunk-QQNVQ62W.mjs} +1 -1
  68. package/dist/client/{chunk-MLBNVN4H.mjs → chunk-R3CZQLXF.mjs} +67 -4
  69. package/dist/client/{chunk-WHZQDPBZ.mjs → chunk-TNGL2WJF.mjs} +1 -0
  70. package/dist/client/{chunk-CKXEUWWA.mjs → chunk-ZJDBOLX7.mjs} +3 -3
  71. package/dist/client/client.mjs +515 -38
  72. package/dist/client/{courseRegistration-X63QAIVV.mjs → courseRegistration-JPWAQ6KM.mjs} +111 -11
  73. package/dist/client/{eventCalendar-5T24GCZL.mjs → eventCalendar-QDOCHBBV.mjs} +9 -9
  74. package/dist/client/{eventCombined-AZVTF22X.mjs → eventCombined-ZS2CXSIE.mjs} +9 -9
  75. package/dist/client/{eventDetails-7GPFNLGF.mjs → eventDetails-5LOBMPLN.mjs} +9 -9
  76. package/dist/client/{eventListing-QEUMTMUM.mjs → eventListing-SBGY4I3L.mjs} +9 -9
  77. package/dist/client/{eventRegistration-P2EDKCQZ.mjs → eventRegistration-XGPIU3Z2.mjs} +9 -9
  78. package/dist/client/{form-NUJ7H4IN.mjs → form-R7D4LZWW.mjs} +3 -3
  79. package/dist/client/{headerSection-JB7LECPL.mjs → headerSection-RRLYUCGC.mjs} +3 -3
  80. package/dist/client/hooks.mjs +22 -2
  81. package/dist/client/{locationMap-UEYWUCSW.mjs → locationMap-35ZJMRBZ.mjs} +3 -3
  82. package/dist/client/{newsletterForm-S2YZQ2X7.mjs → newsletterForm-MJ2VCFUT.mjs} +3 -3
  83. package/dist/client/{productDetail-H5MADGG7.mjs → productDetail-2O7YQNBX.mjs} +7 -7
  84. package/dist/client/{productList-DK7YON7H.mjs → productList-FDP5BH7W.mjs} +7 -7
  85. package/dist/client/rendering/client.mjs +495 -36
  86. package/dist/client/rendering/islands.mjs +19 -19
  87. package/dist/client/rendering.mjs +514 -37
  88. package/dist/client/{shop-6PA7RDRJ.mjs → shop-BGYJ3LDT.mjs} +7 -7
  89. package/dist/preview-next/client/runtime.mjs +3 -3
  90. package/dist/{sdk-runtime-JP5347OB.mjs → sdk-runtime-B3TFXRXZ.mjs} +4 -4
  91. package/dist/server/components.mjs +166 -7
  92. package/dist/server/config-validation.mjs +23 -2
  93. package/dist/server/config.mjs +23 -2
  94. package/dist/server/data.mjs +22 -2
  95. package/dist/server/index.mjs +1 -1
  96. package/dist/server/next.mjs +167 -8
  97. package/dist/server/page-converter.mjs +19 -2
  98. package/dist/server/prebuild.mjs +1 -1
  99. package/dist/server/rendering/server.mjs +166 -7
  100. package/dist/server/rendering.mjs +166 -7
  101. package/dist/server/routing.mjs +29 -5
  102. package/dist/server/server.mjs +23 -3
  103. package/package.json +1 -1
  104. package/dist/SdkPreviewModeRuntime-GMCDQPZZ.mjs +0 -8
@@ -129,6 +129,8 @@ function expectParsedBrandedId(result) {
129
129
  }
130
130
  var unsafeAsSiteId = (id) => id;
131
131
  var unsafeAsMediaAssetId = (id) => id;
132
+ var unsafeAsStoragePath = (value) => value;
133
+ var unsafeAsPositiveByteCount = (value) => value;
132
134
  var unsafeAsFormId = (id) => id;
133
135
  var unsafeAsPassId = (id) => id;
134
136
  var unsafeAsCustomerPassId = (id) => id;
@@ -207,6 +209,7 @@ function publicEventPricingType(pricing) {
207
209
  return "free";
208
210
  case "single_paid":
209
211
  case "ticket_types":
212
+ case "sliding_scale":
210
213
  case "course":
211
214
  return isFreePublicEventPriceDisplay(pricing.display) ? "free" : "paid";
212
215
  case "external":
@@ -219,6 +222,7 @@ function publicEventPricingCurrency(pricing) {
219
222
  case "free_registration":
220
223
  case "single_paid":
221
224
  case "ticket_types":
225
+ case "sliding_scale":
222
226
  return pricing.currency;
223
227
  case "course":
224
228
  return pricing.display.display.currency;
@@ -236,6 +240,8 @@ function publicEventPricingMode(pricing) {
236
240
  return "single";
237
241
  case "ticket_types":
238
242
  return "ticket_types";
243
+ case "sliding_scale":
244
+ return "sliding_scale";
239
245
  case "drop_in":
240
246
  case "course":
241
247
  case "external":
@@ -269,6 +275,8 @@ function formatCoursePriceDisplayLabel(display, options) {
269
275
  return `Course (${formatCurrencyAmount(display.amount, display.currency, options)})`;
270
276
  case "from":
271
277
  return `Course (From ${formatCurrencyAmount(display.amount, display.currency, options)})`;
278
+ case "range":
279
+ return `Course (${formatCurrencyAmount(display.minAmount, display.currency, options)} - ${formatCurrencyAmount(display.maxAmount, display.currency, options)})`;
272
280
  default:
273
281
  return assertNever(display);
274
282
  }
@@ -30396,6 +30404,18 @@ var SVG_MIME_TYPE = "image/svg+xml";
30396
30404
  function isSvgMimeType(mimeType) {
30397
30405
  return mimeType === SVG_MIME_TYPE;
30398
30406
  }
30407
+
30408
+ // ../media-core/src/fileSafety.ts
30409
+ var CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/u;
30410
+ function containsUnsafePathSegmentCharacter(value) {
30411
+ return value.includes("/") || value.includes("\\") || CONTROL_CHARACTER_PATTERN.test(value);
30412
+ }
30413
+ function isReservedPathSegment(value) {
30414
+ return value === "." || value === "..";
30415
+ }
30416
+ function isUnsafePathSegment(segment) {
30417
+ return segment.trim().length === 0 || segment !== segment.trim() || isReservedPathSegment(segment) || containsUnsafePathSegmentCharacter(segment);
30418
+ }
30399
30419
  function classifyKnownMimeType(mimeType) {
30400
30420
  const normalized = normalizeMimeType(mimeType);
30401
30421
  switch (normalized) {
@@ -30462,6 +30482,15 @@ function classifyKnownMimeType(mimeType) {
30462
30482
  function normalizeMimeType(mimeType) {
30463
30483
  return (mimeType ?? "").split(";", 1)[0]?.trim().toLowerCase() ?? "";
30464
30484
  }
30485
+ function parseStoragePath(value) {
30486
+ return joinStoragePathSegments(value.split("/"));
30487
+ }
30488
+ function joinStoragePathSegments(segments) {
30489
+ if (segments.some(isUnsafePathSegment)) {
30490
+ return err("unsafe-path-segment");
30491
+ }
30492
+ return ok(unsafeAsStoragePath(segments.join("/")));
30493
+ }
30465
30494
 
30466
30495
  // ../media-core/src/typeGuards.ts
30467
30496
  function isRecord(value) {
@@ -30473,11 +30502,20 @@ function asRecord(value) {
30473
30502
 
30474
30503
  // ../media-core/src/videoPrep.ts
30475
30504
  var VIDEO_PREP_LIMITS = {
30476
- maxRawByteCount: 500 * 1024 * 1024,
30477
- inlineContentMaxDurationSeconds: 60,
30478
- backgroundVideoMaxDurationSeconds: 30,
30505
+ maxRawByteCount: unsafeAsPositiveByteCount(500 * 1024 * 1024),
30506
+ inlineContentMaxDurationSeconds: unsafeAsPositiveVideoDurationSeconds(60),
30507
+ backgroundVideoMaxDurationSeconds: unsafeAsPositiveVideoDurationSeconds(30),
30479
30508
  targetMaxDimensionPixels: 1080
30480
30509
  };
30510
+ function unsafeAsPositiveVideoDurationSeconds(value) {
30511
+ return value;
30512
+ }
30513
+ function asPositiveVideoDurationSeconds(value) {
30514
+ if (!Number.isFinite(value) || value <= 0) {
30515
+ return err("not-positive-video-duration-seconds");
30516
+ }
30517
+ return ok(unsafeAsPositiveVideoDurationSeconds(value));
30518
+ }
30481
30519
  function deriveVideoPrepPolicy(intent) {
30482
30520
  switch (intent.tag) {
30483
30521
  case "files-and-media":
@@ -30528,14 +30566,16 @@ function evaluateVideoSlotAssetPolicy(asset, policy) {
30528
30566
  if (!isVideoMimeType(asset.mimeType)) {
30529
30567
  return { tag: "not-video" };
30530
30568
  }
30531
- const durationSeconds = asset.durationSeconds;
30532
- if (!Number.isFinite(durationSeconds) || durationSeconds == null || durationSeconds <= 0) {
30569
+ const durationSeconds = asPositiveVideoDurationSeconds(
30570
+ asset.durationSeconds ?? Number.NaN
30571
+ );
30572
+ if (!durationSeconds.ok) {
30533
30573
  return { tag: "duration-unknown", maxSeconds: policy.maxDurationSeconds };
30534
30574
  }
30535
- if (durationSeconds > policy.maxDurationSeconds) {
30575
+ if (durationSeconds.value > policy.maxDurationSeconds) {
30536
30576
  return {
30537
30577
  tag: "duration-too-long",
30538
- actualSeconds: durationSeconds,
30578
+ actualSeconds: durationSeconds.value,
30539
30579
  maxSeconds: policy.maxDurationSeconds
30540
30580
  };
30541
30581
  }
@@ -30591,10 +30631,10 @@ var RELATIVE_STORAGE_PATH_PREFIXES = [
30591
30631
  "imports/"
30592
30632
  ];
30593
30633
  function isRelativeDirectImageStoragePath(storagePath) {
30594
- return RELATIVE_STORAGE_PATH_PREFIXES.some((prefix) => storagePath.startsWith(prefix));
30634
+ return RELATIVE_STORAGE_PATH_PREFIXES.some((prefix) => storagePath.startsWith(prefix)) && parseStoragePath(storagePath).ok;
30595
30635
  }
30596
30636
  function isSiteScopedDirectImageStoragePath(storagePath) {
30597
- return storagePath.startsWith("sites/");
30637
+ return storagePath.startsWith("sites/") && parseStoragePath(storagePath).ok;
30598
30638
  }
30599
30639
  function encodeStoragePath(storagePath) {
30600
30640
  return storagePath.split("/").map((segment) => encodeURIComponent(segment)).join("/");
@@ -33403,6 +33443,21 @@ function fieldPlanToZod(plan, options = {}) {
33403
33443
  }
33404
33444
  });
33405
33445
  }
33446
+ function fieldPresenceForPlan(plan) {
33447
+ return plan.required ? { kind: "required" } : { kind: "optional" };
33448
+ }
33449
+ function fieldPlanToObjectPropertyZod(plan, options = {}) {
33450
+ const schema = fieldPlanToZod(plan, options);
33451
+ const presence = fieldPresenceForPlan(plan);
33452
+ switch (presence.kind) {
33453
+ case "required":
33454
+ return schema;
33455
+ case "optional":
33456
+ return schema.optional();
33457
+ default:
33458
+ return assertNever4(presence);
33459
+ }
33460
+ }
33406
33461
  function addFieldIssueToZodContext(zodCtx, validationIssue, rootPath) {
33407
33462
  const message2 = fieldIssueToMessage(validationIssue);
33408
33463
  const path = relativeZodIssuePath(validationIssue.path, rootPath);
@@ -33669,7 +33724,7 @@ function createManifestValidator(manifestOrFields, options = {}) {
33669
33724
  function deriveContentZodFromPlans(plans, options) {
33670
33725
  const shape = {};
33671
33726
  for (const plan of plans) {
33672
- shape[plan.fieldId] = fieldPlanToZod(plan, options);
33727
+ shape[plan.fieldId] = fieldPlanToObjectPropertyZod(plan, options);
33673
33728
  }
33674
33729
  return z.object(shape).catchall(z.unknown()).passthrough();
33675
33730
  }
@@ -60130,9 +60185,12 @@ var coursePricingOptionSchema = z.object({
60130
60185
  });
60131
60186
  var coursePricingSchema = z.object({
60132
60187
  bookingRequirement: z.enum(["none", "required"]),
60133
- pricingStrategy: z.enum(["free", "single", "tiered"]),
60188
+ pricingStrategy: z.enum(["free", "single", "tiered", "sliding_scale"]),
60134
60189
  currency: z.string(),
60135
60190
  singlePriceAmount: z.number().nullable(),
60191
+ slidingMinAmount: z.number().nullable().optional(),
60192
+ slidingMaxAmount: z.number().nullable().optional(),
60193
+ slidingSuggestedAmount: z.number().nullable().optional(),
60136
60194
  paymentTerms: blockBookingPaymentTermsSchema,
60137
60195
  options: z.array(coursePricingOptionSchema)
60138
60196
  });
@@ -60286,6 +60344,19 @@ var publicEventPricingSchema = z.discriminatedUnion("kind", [
60286
60344
  ticketTypes: z.array(publicEventTicketTypeSchema),
60287
60345
  display: publicEventTicketTypePriceDisplaySchema
60288
60346
  }),
60347
+ z.object({
60348
+ kind: z.literal("sliding_scale"),
60349
+ minAmount: z.number(),
60350
+ maxAmount: z.number(),
60351
+ suggestedAmount: z.number().nullable(),
60352
+ currency: z.string(),
60353
+ display: z.object({
60354
+ kind: z.literal("range"),
60355
+ minAmount: z.number(),
60356
+ maxAmount: z.number(),
60357
+ currency: z.string()
60358
+ })
60359
+ }),
60289
60360
  z.object({
60290
60361
  kind: z.literal("course"),
60291
60362
  display: z.object({ kind: z.literal("course"), display: publicCoursePriceDisplaySchema })
@@ -60694,7 +60765,7 @@ function isRecord7(value) {
60694
60765
  }
60695
60766
  function isPublicEventPricing(value) {
60696
60767
  if (!isRecord7(value) || typeof value.kind !== "string") return false;
60697
- return value.kind === "drop_in" || value.kind === "free_registration" || value.kind === "single_paid" || value.kind === "ticket_types" || value.kind === "course" || value.kind === "external";
60768
+ return value.kind === "drop_in" || value.kind === "free_registration" || value.kind === "single_paid" || value.kind === "sliding_scale" || value.kind === "ticket_types" || value.kind === "course" || value.kind === "external";
60698
60769
  }
60699
60770
  function isPublicEventTicketType(value) {
60700
60771
  return isRecord7(value) && typeof value.id === "string";
@@ -61335,7 +61406,9 @@ function getSelectableCoursePricingOptionsForNow(course, now) {
61335
61406
  return left.name.localeCompare(right.name);
61336
61407
  });
61337
61408
  }
61338
- function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {}) {
61409
+ function resolveCoursePricingState(course, selectedPricingOptionId, selectedSlidingAmountOrNowInput, nowInput = {}) {
61410
+ const selectedSlidingAmount = typeof selectedSlidingAmountOrNowInput === "number" || selectedSlidingAmountOrNowInput === null ? selectedSlidingAmountOrNowInput : null;
61411
+ const effectiveNowInput = typeof selectedSlidingAmountOrNowInput === "object" && selectedSlidingAmountOrNowInput !== null ? selectedSlidingAmountOrNowInput : nowInput;
61339
61412
  const currency = course.pricing?.currency ?? course.currency;
61340
61413
  if (!course.pricing) {
61341
61414
  const legacyAmount = course.priceCents ?? 0;
@@ -61345,6 +61418,8 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
61345
61418
  selectableOptions: [],
61346
61419
  requiresSelection: false,
61347
61420
  selectedOption: null,
61421
+ slidingScale: null,
61422
+ selectedSlidingAmount: null,
61348
61423
  selectedPriceAmount: legacyAmount,
61349
61424
  selectedRequiresPayment: legacyAmount > 0,
61350
61425
  hasPaidSelection: legacyAmount > 0,
@@ -61359,6 +61434,8 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
61359
61434
  selectableOptions: [],
61360
61435
  requiresSelection: false,
61361
61436
  selectedOption: null,
61437
+ slidingScale: null,
61438
+ selectedSlidingAmount: null,
61362
61439
  selectedPriceAmount: 0,
61363
61440
  selectedRequiresPayment: false,
61364
61441
  hasPaidSelection: false,
@@ -61372,6 +61449,8 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
61372
61449
  selectableOptions: [],
61373
61450
  requiresSelection: false,
61374
61451
  selectedOption: null,
61452
+ slidingScale: null,
61453
+ selectedSlidingAmount: null,
61375
61454
  selectedPriceAmount: amount,
61376
61455
  selectedRequiresPayment: amount > 0,
61377
61456
  hasPaidSelection: amount > 0,
@@ -61381,7 +61460,7 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
61381
61460
  case "tiered": {
61382
61461
  const selectableOptions = getSelectableCoursePricingOptionsForNow(
61383
61462
  course,
61384
- resolvePlanningDateInput(nowInput)
61463
+ resolvePlanningDateInput(effectiveNowInput)
61385
61464
  );
61386
61465
  const selectedOption = (selectedPricingOptionId ? selectableOptions.find((option) => option.id === selectedPricingOptionId) : null) ?? (selectableOptions.length === 1 ? selectableOptions[0] ?? null : null);
61387
61466
  const lowestAmount = selectableOptions.reduce((lowest, option) => {
@@ -61397,12 +61476,51 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
61397
61476
  selectableOptions,
61398
61477
  requiresSelection: selectableOptions.length > 1,
61399
61478
  selectedOption,
61479
+ slidingScale: null,
61480
+ selectedSlidingAmount: null,
61400
61481
  selectedPriceAmount: selectedOption?.priceAmount ?? null,
61401
61482
  selectedRequiresPayment: (selectedOption?.priceAmount ?? 0) > 0,
61402
61483
  hasPaidSelection: selectableOptions.some((option) => option.priceAmount > 0),
61403
61484
  hasFreeSelection: selectableOptions.some((option) => option.priceAmount === 0)
61404
61485
  };
61405
61486
  }
61487
+ case "sliding_scale": {
61488
+ const minAmount = course.pricing.slidingMinAmount ?? null;
61489
+ const maxAmount = course.pricing.slidingMaxAmount ?? null;
61490
+ if (minAmount === null || maxAmount === null || minAmount < 0 || maxAmount < minAmount) {
61491
+ return {
61492
+ currency,
61493
+ display: { kind: "unavailable", currency },
61494
+ selectableOptions: [],
61495
+ requiresSelection: true,
61496
+ selectedOption: null,
61497
+ slidingScale: null,
61498
+ selectedSlidingAmount: null,
61499
+ selectedPriceAmount: null,
61500
+ selectedRequiresPayment: false,
61501
+ hasPaidSelection: false,
61502
+ hasFreeSelection: false
61503
+ };
61504
+ }
61505
+ const normalizedSelectedAmount = typeof selectedSlidingAmount === "number" && Number.isFinite(selectedSlidingAmount) ? selectedSlidingAmount : null;
61506
+ return {
61507
+ currency,
61508
+ display: { kind: "range", minAmount, maxAmount, currency },
61509
+ selectableOptions: [],
61510
+ requiresSelection: normalizedSelectedAmount === null,
61511
+ selectedOption: null,
61512
+ slidingScale: {
61513
+ minAmount,
61514
+ maxAmount,
61515
+ suggestedAmount: course.pricing.slidingSuggestedAmount ?? null
61516
+ },
61517
+ selectedSlidingAmount: normalizedSelectedAmount,
61518
+ selectedPriceAmount: normalizedSelectedAmount,
61519
+ selectedRequiresPayment: (normalizedSelectedAmount ?? 0) > 0,
61520
+ hasPaidSelection: maxAmount > 0,
61521
+ hasFreeSelection: minAmount === 0
61522
+ };
61523
+ }
61406
61524
  }
61407
61525
  }
61408
61526
  function formatCoursePriceDisplay(display, locale) {
@@ -73711,6 +73829,7 @@ var BOOKING_FORM_DATA_RESERVED_KEY_VALUES = [
73711
73829
  "selectedDate",
73712
73830
  "selectedSlot",
73713
73831
  "discountCode",
73832
+ "selectedSlidingAmountInput",
73714
73833
  "selectedCollectionOptionKind",
73715
73834
  "selectedAppointmentPackageId"
73716
73835
  ];
@@ -73994,6 +74113,32 @@ function readOptionalString(value) {
73994
74113
  function readOptionalNumber(value) {
73995
74114
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
73996
74115
  }
74116
+ function getBookingServiceSlidingScale(service) {
74117
+ const pricing = service?.pricing;
74118
+ if (!pricing || pricing.pricingStrategy !== "sliding_scale" || pricing.slidingMinAmount === null || pricing.slidingMinAmount === void 0 || pricing.slidingMaxAmount === null || pricing.slidingMaxAmount === void 0) {
74119
+ return null;
74120
+ }
74121
+ return {
74122
+ minAmount: pricing.slidingMinAmount,
74123
+ maxAmount: pricing.slidingMaxAmount,
74124
+ suggestedAmount: pricing.slidingSuggestedAmount ?? null,
74125
+ currency: pricing.currency
74126
+ };
74127
+ }
74128
+ function parseBookingCurrencyInputToCents(value) {
74129
+ const trimmed = value?.trim() ?? "";
74130
+ if (!trimmed) return null;
74131
+ if (!/^(?:\d+(?:\.\d{0,2})?|\.\d{1,2})$/.test(trimmed)) return null;
74132
+ const parsed = Number(trimmed);
74133
+ if (!Number.isFinite(parsed) || parsed < 0) return null;
74134
+ return Math.round(parsed * 100);
74135
+ }
74136
+ function formatBookingCentsAsCurrencyInput(amount) {
74137
+ return amount % 100 === 0 ? String(amount / 100) : (amount / 100).toFixed(2);
74138
+ }
74139
+ function isBookingServiceSlidingAmountInRange(slidingScale, selectedAmount) {
74140
+ return selectedAmount !== null && selectedAmount >= slidingScale.minAmount && selectedAmount <= slidingScale.maxAmount;
74141
+ }
73997
74142
  function readStringArray(value) {
73998
74143
  if (!Array.isArray(value)) return void 0;
73999
74144
  const strings = value.filter((item) => typeof item === "string");
@@ -74182,6 +74327,20 @@ function prepareBookingSubmission(input) {
74182
74327
  };
74183
74328
  }
74184
74329
  const paymentSelectionMode = getBookingServicePaymentSelectionMode(selectedService);
74330
+ const slidingScale = getBookingServiceSlidingScale(selectedService);
74331
+ const selectedSlidingAmount = parseBookingCurrencyInputToCents(
74332
+ input.data.selectedSlidingAmountInput
74333
+ );
74334
+ if (slidingScale && !isBookingServiceSlidingAmountInRange(slidingScale, selectedSlidingAmount)) {
74335
+ return {
74336
+ ok: false,
74337
+ error: {
74338
+ tag: selectedSlidingAmount === null ? "sliding-amount-required" : "sliding-amount-out-of-range",
74339
+ serviceId,
74340
+ serviceTitle: selectedService.title || serviceId
74341
+ }
74342
+ };
74343
+ }
74185
74344
  if (paymentSelectionMode === "choice_required" && !toSelectedCollectionOptionKind(input.data.selectedCollectionOptionKind)) {
74186
74345
  return {
74187
74346
  ok: false,
@@ -74209,6 +74368,7 @@ function prepareBookingSubmission(input) {
74209
74368
  ...common,
74210
74369
  kind: "standard",
74211
74370
  ...discountCode ? { discountCode } : {},
74371
+ ...slidingScale && selectedSlidingAmount !== null ? { selectedSlidingAmount } : {},
74212
74372
  ...selectedCollectionOptionKind ? { selectedCollectionOptionKind } : {},
74213
74373
  altchaSolution: input.altchaSolution ?? null
74214
74374
  }
@@ -74222,6 +74382,10 @@ function formatBookingSubmissionPreparationError(error) {
74222
74382
  return `Service not found: ${error.serviceId}`;
74223
74383
  case "payment-option-required":
74224
74384
  return `Please choose how you want to pay for "${error.serviceTitle}".`;
74385
+ case "sliding-amount-required":
74386
+ return `Please choose an amount for "${error.serviceTitle}".`;
74387
+ case "sliding-amount-out-of-range":
74388
+ return `Please choose an amount within the sliding scale for "${error.serviceTitle}".`;
74225
74389
  case "payment-option-unsupported":
74226
74390
  return `Service "${error.serviceTitle}" has a payment option that is not supported yet.`;
74227
74391
  case "service-missing-duration":
@@ -74318,6 +74482,7 @@ var bookingServiceSchema = z.object({
74318
74482
  title: z.string(),
74319
74483
  description: z.string().nullable().optional().transform((value) => value ?? void 0),
74320
74484
  durationMinutes: z.number().optional(),
74485
+ pricing: z.custom().optional(),
74321
74486
  priceAmount: z.number().nullable().optional(),
74322
74487
  priceCurrency: z.string().nullable().optional(),
74323
74488
  paymentTerms: blockBookingPaymentTermsSchema.optional(),
@@ -126535,6 +126700,7 @@ function createBlockApi(config) {
126535
126700
  body: {
126536
126701
  courseId: data.courseId,
126537
126702
  ...data.pricingOptionId ? { pricingOptionId: data.pricingOptionId } : {},
126703
+ ...data.selectedSlidingAmount !== void 0 ? { selectedSlidingAmount: data.selectedSlidingAmount } : {},
126538
126704
  email: data.email,
126539
126705
  name: data.name,
126540
126706
  phone: data.phone,
@@ -127477,6 +127643,7 @@ function useBookingSubmission(_siteId) {
127477
127643
  customFields: data.customFields,
127478
127644
  timezone: data.timezone,
127479
127645
  discountCode: data.discountCode,
127646
+ selectedSlidingAmount: data.selectedSlidingAmount,
127480
127647
  selectedCollectionOptionKind: data.selectedCollectionOptionKind,
127481
127648
  altchaSolution: data.altchaSolution ?? null,
127482
127649
  successUrl: data.successUrl,
@@ -127956,6 +128123,9 @@ function createInitialBookingFlowReducerState(input) {
127956
128123
  fieldValues: collectInitialFieldValues(initialData),
127957
128124
  touchedFields: {},
127958
128125
  discountCode: toOptionalString(initialData.discountCode) ?? "",
128126
+ selectedSlidingAmountInput: toOptionalString(
128127
+ initialData.selectedSlidingAmountInput
128128
+ ) ?? "",
127959
128129
  selectedCollectionOptionKind: toSelectedCollectionOptionKind(
127960
128130
  initialData.selectedCollectionOptionKind
127961
128131
  ),
@@ -128008,6 +128178,7 @@ function bookingFlowReducer(state, event) {
128008
128178
  selectedDate: void 0,
128009
128179
  selectedSlot: null,
128010
128180
  selectedAppointmentPackageId: void 0,
128181
+ selectedSlidingAmountInput: "",
128011
128182
  selectedCollectionOptionKind: void 0,
128012
128183
  validationErrors: clearBookingFormError(state.validationErrors)
128013
128184
  };
@@ -128061,6 +128232,13 @@ function bookingFlowReducer(state, event) {
128061
128232
  selectedAppointmentPackageId: void 0,
128062
128233
  validationErrors: clearBookingFormError(state.validationErrors)
128063
128234
  };
128235
+ case "sliding-amount-changed":
128236
+ return {
128237
+ ...state,
128238
+ selectedSlidingAmountInput: event.value,
128239
+ selectedAppointmentPackageId: void 0,
128240
+ validationErrors: clearBookingFormError(state.validationErrors)
128241
+ };
128064
128242
  case "appointment-package-selected":
128065
128243
  return {
128066
128244
  ...state,
@@ -128163,6 +128341,7 @@ function toBookingFormData(state) {
128163
128341
  selectedDate: state.selectedDate,
128164
128342
  selectedSlot: state.selectedSlot?.startAt,
128165
128343
  discountCode: state.discountCode || void 0,
128344
+ selectedSlidingAmountInput: state.selectedSlidingAmountInput || void 0,
128166
128345
  selectedCollectionOptionKind: state.selectedCollectionOptionKind,
128167
128346
  selectedAppointmentPackageId: state.selectedAppointmentPackageId
128168
128347
  };
@@ -128180,7 +128359,8 @@ function buildBookingStepResolution(input) {
128180
128359
  input.form.settings?.serviceIds && input.form.settings.serviceIds.length > 1
128181
128360
  );
128182
128361
  const selectedService = paymentResolution.service;
128183
- const needsPayment = paymentResolution.mode !== "hidden" || Boolean(
128362
+ const selectedServiceSlidingScale = getBookingServiceSlidingScale(selectedService);
128363
+ const needsPayment = Boolean(selectedServiceSlidingScale) || paymentResolution.mode !== "hidden" || Boolean(
128184
128364
  input.enableAppointmentPackages && selectedService && (selectedService.priceAmount ?? 0) > 0
128185
128365
  );
128186
128366
  const hasFields = Boolean(input.form.schema?.fields.length);
@@ -128224,6 +128404,18 @@ function validateBookingStep(input) {
128224
128404
  services: input.services,
128225
128405
  defaultServiceId: input.defaultServiceId
128226
128406
  });
128407
+ const slidingScale = getBookingServiceSlidingScale(resolution.service);
128408
+ if (slidingScale && !isBookingServiceSlidingAmountInRange(
128409
+ slidingScale,
128410
+ parseBookingCurrencyInputToCents(input.data.selectedSlidingAmountInput)
128411
+ )) {
128412
+ return {
128413
+ ok: false,
128414
+ errors: createFormBookingValidationError(
128415
+ "Please choose an amount within the sliding scale"
128416
+ )
128417
+ };
128418
+ }
128227
128419
  if (resolution.mode === "hidden" || resolution.mode === "disclosure_only") {
128228
128420
  return { ok: true };
128229
128421
  }
@@ -128633,11 +128825,27 @@ function useHeadlessBookingFlow(options) {
128633
128825
  const selectedServiceId = state.selectedServiceId ?? defaultServiceId;
128634
128826
  const selectedResourceId = state.selectedResourceId ?? defaultResourceId;
128635
128827
  const selectedService = options.services.find((service) => service.id === selectedServiceId) ?? null;
128828
+ const lastSlidingServiceIdRef = useRef(null);
128829
+ useEffect(() => {
128830
+ const selectedId = selectedService?.id ?? null;
128831
+ if (lastSlidingServiceIdRef.current === selectedId) return;
128832
+ lastSlidingServiceIdRef.current = selectedId;
128833
+ const slidingScale = getBookingServiceSlidingScale(selectedService);
128834
+ dispatch({
128835
+ type: "sliding-amount-changed",
128836
+ value: slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatBookingCentsAsCurrencyInput(slidingScale.suggestedAmount) : ""
128837
+ });
128838
+ }, [selectedService]);
128636
128839
  const hasPortalBearerAuth = (api.config.authOverrides?.portal ?? api.config.auth).type === "bearer";
128840
+ const selectedServiceSlidingScale = getBookingServiceSlidingScale(selectedService);
128841
+ const selectedSlidingAmount = parseBookingCurrencyInputToCents(
128842
+ state.selectedSlidingAmountInput
128843
+ );
128844
+ const selectedAppointmentPriceAmount = selectedServiceSlidingScale && selectedSlidingAmount !== null ? selectedSlidingAmount : selectedService?.priceAmount ?? 0;
128637
128845
  const canLoadAppointmentPackages = Boolean(
128638
- options.enableAppointmentPackages && hasPortalBearerAuth && selectedService && (selectedService.priceAmount ?? 0) > 0
128846
+ options.enableAppointmentPackages && hasPortalBearerAuth && selectedService && !selectedServiceSlidingScale && (selectedService.priceAmount ?? 0) > 0
128639
128847
  );
128640
- const appointmentPackagesUnavailableReason = !options.enableAppointmentPackages ? "disabled" : !selectedService || (selectedService.priceAmount ?? 0) <= 0 ? "missing-priced-service" : !hasPortalBearerAuth ? "missing-portal-auth" : null;
128848
+ const appointmentPackagesUnavailableReason = !options.enableAppointmentPackages ? "disabled" : !selectedService || selectedServiceSlidingScale || (selectedService.priceAmount ?? 0) <= 0 ? "missing-priced-service" : !hasPortalBearerAuth ? "missing-portal-auth" : null;
128641
128849
  const data = useMemo(() => toBookingFormData(state), [state]);
128642
128850
  const availabilityDatesQuery = useMemo(
128643
128851
  () => buildBookingAvailabilityQuery({
@@ -128867,13 +129075,13 @@ function useHeadlessBookingFlow(options) {
128867
129075
  state.selectedSlot
128868
129076
  ]);
128869
129077
  const appointmentDiscountContext = useMemo(
128870
- () => selectedService && (selectedService.priceAmount ?? 0) > 0 ? { type: "appointment", serviceId: selectedService.id } : null,
128871
- [selectedService?.id, selectedService?.priceAmount]
129078
+ () => selectedService && selectedAppointmentPriceAmount > 0 ? { type: "appointment", serviceId: selectedService.id } : null,
129079
+ [selectedAppointmentPriceAmount, selectedService?.id]
128872
129080
  );
128873
129081
  const discountUi = useDiscountCodeUi({
128874
129082
  api,
128875
129083
  discountContext: appointmentDiscountContext,
128876
- subtotalCents: selectedService?.priceAmount ?? 0
129084
+ subtotalCents: selectedAppointmentPriceAmount
128877
129085
  });
128878
129086
  const { submit, clearFeedback } = useBookingSubmission(options.siteId);
128879
129087
  const submittingRef = useRef(false);
@@ -129016,6 +129224,7 @@ function useHeadlessBookingFlow(options) {
129016
129224
  type: "appointment-package-selected",
129017
129225
  packageId: packageId ? unsafeAsCustomerPassId(packageId) : null
129018
129226
  }),
129227
+ setSlidingAmountInput: (value) => dispatch({ type: "sliding-amount-changed", value }),
129019
129228
  setDiscountCode: (code) => {
129020
129229
  dispatch({ type: "discount-code-changed", code });
129021
129230
  latestRef.current.setDiscountCode(code);
@@ -129086,11 +129295,11 @@ function useHeadlessBookingFlow(options) {
129086
129295
  () => selectedService && paymentResolution.mode !== "unsupported" ? buildBookingPaymentSelectionViewModel({
129087
129296
  serviceTitle: selectedService.title,
129088
129297
  paymentTerms: selectedService.paymentTerms,
129089
- priceAmount: selectedService.priceAmount,
129298
+ priceAmount: selectedAppointmentPriceAmount,
129090
129299
  priceCurrency: selectedService.priceCurrency,
129091
129300
  bookingStartAt: state.selectedSlot?.startAt
129092
129301
  }) : null,
129093
- [paymentResolution.mode, selectedService, state.selectedSlot?.startAt]
129302
+ [paymentResolution.mode, selectedAppointmentPriceAmount, selectedService, state.selectedSlot?.startAt]
129094
129303
  );
129095
129304
  const appointmentPackageItems = appointmentPackages.tag === "loaded" ? appointmentPackages.value : [];
129096
129305
  const selectedAppointmentPackage = appointmentPackageItems.find(
@@ -129119,6 +129328,9 @@ function useHeadlessBookingFlow(options) {
129119
129328
  selection: null,
129120
129329
  selectedCollectionOptionKind: state.selectedCollectionOptionKind,
129121
129330
  selectedAppointmentPackageId: state.selectedAppointmentPackageId,
129331
+ selectedSlidingAmountInput: state.selectedSlidingAmountInput,
129332
+ selectedSlidingAmount,
129333
+ slidingScale: selectedServiceSlidingScale,
129122
129334
  appointmentPackages: appointmentPackagesModel,
129123
129335
  errorMessage: paymentResolution.errorMessage ?? "This service cannot be booked right now."
129124
129336
  } : {
@@ -129127,6 +129339,9 @@ function useHeadlessBookingFlow(options) {
129127
129339
  selection: paymentSelection,
129128
129340
  selectedCollectionOptionKind: state.selectedCollectionOptionKind,
129129
129341
  selectedAppointmentPackageId: state.selectedAppointmentPackageId,
129342
+ selectedSlidingAmountInput: state.selectedSlidingAmountInput,
129343
+ selectedSlidingAmount,
129344
+ slidingScale: selectedServiceSlidingScale,
129130
129345
  appointmentPackages: appointmentPackagesModel
129131
129346
  };
129132
129347
  return {
@@ -129667,6 +129882,9 @@ var paymentOptionLayoutStyle = {
129667
129882
  var summaryStackStyle = {
129668
129883
  gap: "0.125rem"
129669
129884
  };
129885
+ function formatBookingAmount(amount, currency) {
129886
+ return formatCurrencyAmount(amount, currency, { decimals: "auto" });
129887
+ }
129670
129888
  function HeadlessBookingDefaultForm({
129671
129889
  booking,
129672
129890
  onSubmit
@@ -129943,6 +130161,7 @@ function HeadlessBookingPaymentSelectionStep({
129943
130161
  }
129944
130162
  const packageOptions = booking.payment.appointmentPackages.items;
129945
130163
  const hasPackageOptions = packageOptions.length > 0;
130164
+ const slidingScale = booking.payment.slidingScale;
129946
130165
  return /* @__PURE__ */ jsxs("div", { className: "ab-stack", children: [
129947
130166
  /* @__PURE__ */ jsxs("div", { className: "ab-info-box", children: [
129948
130167
  /* @__PURE__ */ jsx("h3", { className: "ab-subtitle", children: viewModel.sectionTitle }),
@@ -129953,6 +130172,28 @@ function HeadlessBookingPaymentSelectionStep({
129953
130172
  booking.payment.appointmentPackages.state.message,
129954
130173
  " You can continue with the normal payment option."
129955
130174
  ] }) : null,
130175
+ slidingScale ? /* @__PURE__ */ jsxs("div", { className: "rb-space-y-2", children: [
130176
+ /* @__PURE__ */ jsx("label", { htmlFor: "appointment-sliding-amount", className: "form-label", children: "Choose your price" }),
130177
+ /* @__PURE__ */ jsxs("p", { className: "rb-caption status-muted", children: [
130178
+ formatBookingAmount(slidingScale.minAmount, slidingScale.currency),
130179
+ " to ",
130180
+ formatBookingAmount(slidingScale.maxAmount, slidingScale.currency),
130181
+ slidingScale.suggestedAmount !== null ? `, suggested ${formatBookingAmount(slidingScale.suggestedAmount, slidingScale.currency)}` : ""
130182
+ ] }),
130183
+ /* @__PURE__ */ jsx(
130184
+ "input",
130185
+ {
130186
+ id: "appointment-sliding-amount",
130187
+ type: "number",
130188
+ className: "form-input",
130189
+ min: slidingScale.minAmount / 100,
130190
+ max: slidingScale.maxAmount / 100,
130191
+ step: "0.01",
130192
+ value: booking.payment.selectedSlidingAmountInput,
130193
+ onChange: (event) => booking.actions.setSlidingAmountInput(event.target.value)
130194
+ }
130195
+ )
130196
+ ] }) : null,
129956
130197
  /* @__PURE__ */ jsxs("div", { className: "ab-stack", role: "list", "aria-label": "Payment options", children: [
129957
130198
  packageOptions.map((appointmentPackage) => {
129958
130199
  const isSelected = booking.payment.selectedAppointmentPackageId === appointmentPackage.customerPassId;
@@ -131590,6 +131831,7 @@ function useEligibility(params) {
131590
131831
  occurrenceId: params.occurrenceId,
131591
131832
  attendanceMode: params.attendanceMode ?? void 0,
131592
131833
  ticketTypeId: params.ticketTypeId ?? void 0,
131834
+ selectedSlidingAmount: params.selectedSlidingAmount ?? void 0,
131593
131835
  email: params.email.trim().toLowerCase(),
131594
131836
  ticketsCount: params.ticketsCount
131595
131837
  });
@@ -131610,7 +131852,7 @@ function useEligibility(params) {
131610
131852
  return () => {
131611
131853
  cancelled = true;
131612
131854
  };
131613
- }, [api, params.enabled, params.occurrenceId, params.attendanceMode, params.ticketTypeId, params.email, params.ticketsCount]);
131855
+ }, [api, params.enabled, params.occurrenceId, params.attendanceMode, params.ticketTypeId, params.selectedSlidingAmount, params.email, params.ticketsCount]);
131614
131856
  return {
131615
131857
  state,
131616
131858
  eligibility: state.eligibility,
@@ -131933,6 +132175,41 @@ function TicketCounterLimit(props2) {
131933
132175
  ] }) : null
131934
132176
  ] });
131935
132177
  }
132178
+ function formatCurrencyInputAmount(amount) {
132179
+ const major = amount / 100;
132180
+ return Number.isInteger(major) ? String(major) : major.toFixed(2);
132181
+ }
132182
+ function SlidingScaleAmountField(props2) {
132183
+ const minLabel = formatPrice(props2.slidingScale.minAmount, props2.currency);
132184
+ const maxLabel = formatPrice(props2.slidingScale.maxAmount, props2.currency);
132185
+ const suggestedLabel = props2.slidingScale.suggestedAmount !== null ? formatPrice(props2.slidingScale.suggestedAmount, props2.currency) : null;
132186
+ return /* @__PURE__ */ jsxs("div", { className: "er-field", children: [
132187
+ /* @__PURE__ */ jsx("label", { htmlFor: "er-sliding-amount", className: "er-label", children: "Amount" }),
132188
+ /* @__PURE__ */ jsx(
132189
+ "input",
132190
+ {
132191
+ id: "er-sliding-amount",
132192
+ type: "number",
132193
+ min: formatCurrencyInputAmount(props2.slidingScale.minAmount),
132194
+ max: formatCurrencyInputAmount(props2.slidingScale.maxAmount),
132195
+ step: "0.01",
132196
+ inputMode: "decimal",
132197
+ className: "er-input",
132198
+ value: props2.value,
132199
+ onChange: (event) => props2.onChange?.(event.target.value)
132200
+ }
132201
+ ),
132202
+ /* @__PURE__ */ jsxs("p", { className: "er-text er-text--muted", children: [
132203
+ "Choose between ",
132204
+ minLabel,
132205
+ " and ",
132206
+ maxLabel,
132207
+ suggestedLabel ? `; suggested ${suggestedLabel}` : "",
132208
+ "."
132209
+ ] }),
132210
+ props2.message ? /* @__PURE__ */ jsx("p", { className: "er-text er-text--muted", children: props2.message }) : null
132211
+ ] });
132212
+ }
131936
132213
  function getTicketTypeCounterAvailabilityLabel(input) {
131937
132214
  if (input.selectedRemainingCapacity !== null) {
131938
132215
  return `${input.selectedRemainingCapacity} remaining for this ticket type`;
@@ -131996,6 +132273,10 @@ var TicketSelectionStep = ({
131996
132273
  maxTickets,
131997
132274
  selectedTicketTypeId = null,
131998
132275
  onTicketTypeChange,
132276
+ slidingScale = null,
132277
+ selectedSlidingAmountInput = "",
132278
+ slidingScaleSelectionMessage = null,
132279
+ onSlidingAmountChange,
131999
132280
  onTicketsChange
132000
132281
  }) => {
132001
132282
  const deliveryMode = event?.deliveryMode ?? "in_person";
@@ -132111,6 +132392,16 @@ var TicketSelectionStep = ({
132111
132392
  ] })
132112
132393
  ] })
132113
132394
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
132395
+ slidingScale ? /* @__PURE__ */ jsx(
132396
+ SlidingScaleAmountField,
132397
+ {
132398
+ slidingScale,
132399
+ currency: eventPricingCurrency ?? DEFAULT_EVENT_CURRENCY2,
132400
+ value: selectedSlidingAmountInput,
132401
+ message: slidingScaleSelectionMessage,
132402
+ onChange: onSlidingAmountChange
132403
+ }
132404
+ ) : null,
132114
132405
  /* @__PURE__ */ jsx("h3", { className: "er-title", children: canJoinWaitlist ? "How many waitlist spots?" : "How many tickets?" }),
132115
132406
  /* @__PURE__ */ jsxs("div", { className: "er-ticket-counter-group", children: [
132116
132407
  /* @__PURE__ */ jsx(
@@ -132963,6 +133254,10 @@ function EventRegistrationWizardContent(props2) {
132963
133254
  maxTickets: wizard.maxTicketsNum,
132964
133255
  selectedTicketTypeId: wizard.selectedTicketTypeId,
132965
133256
  onTicketTypeChange: wizard.setSelectedTicketTypeId,
133257
+ slidingScale: wizard.selectedEventSlidingScale,
133258
+ selectedSlidingAmountInput: wizard.selectedSlidingAmountInput,
133259
+ slidingScaleSelectionMessage: wizard.slidingScaleSelectionMessage,
133260
+ onSlidingAmountChange: wizard.setSelectedSlidingAmountInput,
132966
133261
  onTicketsChange: wizard.setTicketsCount
132967
133262
  }
132968
133263
  )
@@ -133156,7 +133451,7 @@ function EventRegistrationSummaryBar(props2) {
133156
133451
  const summaryTimeZone = wizard.occurrenceContext?.timeZone ?? summaryEvent?.timeZone ?? null;
133157
133452
  const occurrenceOverrideTitle = wizard.occurrenceContext?.overrides?.title;
133158
133453
  const summaryTitle = occurrenceOverrideTitle ?? summaryEvent?.title ?? "";
133159
- const summaryPrice = wizard.selectedTicketType?.priceAmount ?? wizard.eligibility?.price ?? (summaryEvent ? publicEventScalarPrice(summaryEvent.pricing) : null) ?? 0;
133454
+ const summaryPrice = wizard.selectedTicketType?.priceAmount ?? wizard.eligibility?.price ?? (wizard.selectedEventSlidingScale ? wizard.selectedSlidingAmount : null) ?? (summaryEvent ? publicEventScalarPrice(summaryEvent.pricing) : null) ?? 0;
133160
133455
  const summaryCurrency = (summaryEvent ? publicEventPricingCurrency(summaryEvent.pricing) : null) ?? DEFAULT_EVENT_CURRENCY2;
133161
133456
  const teamMemberNames = (summaryEvent?.teamMembers ?? []).map((teamMember) => teamMember.name).filter(Boolean);
133162
133457
  const subtotalCents = Math.max(0, summaryPrice * wizard.ticketsCount);
@@ -133556,6 +133851,7 @@ function useEventRegistrationSubmit(options) {
133556
133851
  occurrenceId: submitOccurrenceId,
133557
133852
  attendanceMode: options.selectedAttendanceMode ?? void 0,
133558
133853
  ticketTypeId: options.selectedTicketTypeId ?? void 0,
133854
+ selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
133559
133855
  email: options.formData.email.trim().toLowerCase(),
133560
133856
  name: options.formData.name.trim(),
133561
133857
  ticketsCount: options.ticketsCount,
@@ -133657,6 +133953,35 @@ function useEventRegistrationSubmit(options) {
133657
133953
  }
133658
133954
 
133659
133955
  // ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
133956
+ function parseCurrencyInputToCents(value) {
133957
+ const trimmed = value.trim();
133958
+ if (!trimmed) return null;
133959
+ const amount = Number(trimmed);
133960
+ if (!Number.isFinite(amount) || amount < 0) return null;
133961
+ return Math.round(amount * 100);
133962
+ }
133963
+ function formatCentsAsCurrencyInput(amount) {
133964
+ const major = amount / 100;
133965
+ return Number.isInteger(major) ? String(major) : major.toFixed(2);
133966
+ }
133967
+ function getSlidingScaleForEvent(event) {
133968
+ const pricing = event ? resolveRuntimeEventPricing(event) : null;
133969
+ return pricing?.kind === "sliding_scale" ? {
133970
+ minAmount: pricing.minAmount,
133971
+ maxAmount: pricing.maxAmount,
133972
+ suggestedAmount: pricing.suggestedAmount
133973
+ } : null;
133974
+ }
133975
+ function getSlidingScaleSelectionMessage(input) {
133976
+ if (!input.slidingScale) return null;
133977
+ if (input.selectedAmount === null) {
133978
+ return "Choose an amount to continue.";
133979
+ }
133980
+ if (input.selectedAmount < input.slidingScale.minAmount || input.selectedAmount > input.slidingScale.maxAmount) {
133981
+ return "Choose an amount within the sliding scale.";
133982
+ }
133983
+ return null;
133984
+ }
133660
133985
  function useEventRegistrationWizard(options) {
133661
133986
  const api = useBlockApi();
133662
133987
  const registrationEvents = useMemo(
@@ -133701,6 +134026,10 @@ function useEventRegistrationWizard(options) {
133701
134026
  preSelectedEvent?.deliveryMode === "online" ? "online" : preSelectedEvent?.deliveryMode === "in_person" ? "in_person" : null
133702
134027
  );
133703
134028
  const [selectedTicketTypeId, setSelectedTicketTypeId] = useState(null);
134029
+ const [selectedSlidingAmountInput, setSelectedSlidingAmountInput] = useState(() => {
134030
+ const slidingScale = getSlidingScaleForEvent(preSelectedEvent ?? null);
134031
+ return slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(slidingScale.suggestedAmount) : "";
134032
+ });
133704
134033
  const [registrationResult, setRegistrationResult] = useState(null);
133705
134034
  const [errorMessage, setErrorMessage] = useState("");
133706
134035
  const [altchaSolution, setAltchaSolution] = useState(null);
@@ -133737,6 +134066,7 @@ function useEventRegistrationWizard(options) {
133737
134066
  occurrenceId,
133738
134067
  attendanceMode: selectedAttendanceMode,
133739
134068
  ticketTypeId: selectedTicketTypeId,
134069
+ selectedSlidingAmount: parseCurrencyInputToCents(selectedSlidingAmountInput),
133740
134070
  email: formData.email,
133741
134071
  ticketsCount
133742
134072
  });
@@ -133872,6 +134202,18 @@ function useEventRegistrationWizard(options) {
133872
134202
  }),
133873
134203
  [selectedAttendanceMode, selectedEvent, preSelectedEvent, eligibility, selectedTicketTypeId]
133874
134204
  );
134205
+ const selectedSlidingAmount = useMemo(
134206
+ () => parseCurrencyInputToCents(selectedSlidingAmountInput),
134207
+ [selectedSlidingAmountInput]
134208
+ );
134209
+ const selectedEventSlidingScale = useMemo(
134210
+ () => getSlidingScaleForEvent(selectedEvent ?? preSelectedEvent),
134211
+ [selectedEvent, preSelectedEvent]
134212
+ );
134213
+ const slidingScaleSelectionMessage = getSlidingScaleSelectionMessage({
134214
+ slidingScale: selectedEventSlidingScale,
134215
+ selectedAmount: selectedSlidingAmount
134216
+ });
133875
134217
  const ticketTypeSelectionRequired = useMemo(() => {
133876
134218
  const event = selectedEvent ?? preSelectedEvent;
133877
134219
  if (!event || publicEventPricingMode(resolveRuntimeEventPricing(event)) !== "ticket_types") {
@@ -133940,12 +134282,24 @@ function useEventRegistrationWizard(options) {
133940
134282
  setGuestSectionShake(false);
133941
134283
  };
133942
134284
  const eventRequiresPayment = useMemo(
133943
- () => resolveEventRequiresPayment({
134285
+ () => {
134286
+ if (selectedEventSlidingScale) {
134287
+ return (selectedSlidingAmount ?? 0) > 0;
134288
+ }
134289
+ return resolveEventRequiresPayment({
134290
+ eligibility,
134291
+ selectedTicketType,
134292
+ event: selectedEvent ?? preSelectedEvent
134293
+ });
134294
+ },
134295
+ [
133944
134296
  eligibility,
133945
134297
  selectedTicketType,
133946
- event: selectedEvent ?? preSelectedEvent
133947
- }),
133948
- [eligibility, selectedTicketType, selectedEvent, preSelectedEvent]
134298
+ selectedEvent,
134299
+ preSelectedEvent,
134300
+ selectedEventSlidingScale,
134301
+ selectedSlidingAmount
134302
+ ]
133949
134303
  );
133950
134304
  const handleDetailsComplete = async () => {
133951
134305
  if (ticketTypeSelectionRequired && !hasValidSelectedTicketType) {
@@ -133954,6 +134308,11 @@ function useEventRegistrationWizard(options) {
133954
134308
  setStep("error");
133955
134309
  return { ok: false, reason: "blocked", message: message2 };
133956
134310
  }
134311
+ if (slidingScaleSelectionMessage) {
134312
+ setErrorMessage(slidingScaleSelectionMessage);
134313
+ setStep("error");
134314
+ return { ok: false, reason: "blocked", message: slidingScaleSelectionMessage };
134315
+ }
133957
134316
  if (!validateForm()) {
133958
134317
  setGuestSectionShake(true);
133959
134318
  return {
@@ -134038,9 +134397,18 @@ function useEventRegistrationWizard(options) {
134038
134397
  const discountSubtotalCents = useMemo(() => {
134039
134398
  if (discountContext?.type !== "event") return void 0;
134040
134399
  const event = selectedEvent ?? preSelectedEvent;
134041
- const eventPriceCents = selectedTicketType?.priceAmount ?? eligibility?.price ?? (event ? publicEventScalarPrice(resolveRuntimeEventPricing(event)) : null) ?? 0;
134400
+ const eventPriceCents = selectedTicketType?.priceAmount ?? eligibility?.price ?? (selectedEventSlidingScale ? selectedSlidingAmount : null) ?? (event ? publicEventScalarPrice(resolveRuntimeEventPricing(event)) : null) ?? 0;
134042
134401
  return Math.max(0, eventPriceCents * ticketsCount);
134043
- }, [discountContext, selectedTicketType, eligibility, selectedEvent, preSelectedEvent, ticketsCount]);
134402
+ }, [
134403
+ discountContext,
134404
+ selectedTicketType,
134405
+ eligibility,
134406
+ selectedEvent,
134407
+ preSelectedEvent,
134408
+ selectedEventSlidingScale,
134409
+ selectedSlidingAmount,
134410
+ ticketsCount
134411
+ ]);
134044
134412
  const discountUi = useDiscountCodeUi({ api, discountContext, subtotalCents: discountSubtotalCents });
134045
134413
  const selectionMethod = paymentSelection.method;
134046
134414
  const shouldShowDiscountToggle = discountContext !== null && discountUi.manualCodeEntryAllowed && (selectionMethod === "stripe" || selectionMethod === "pass_bundle" || selectionMethod === "membership_bundle");
@@ -134049,6 +134417,7 @@ function useEventRegistrationWizard(options) {
134049
134417
  registrationTarget,
134050
134418
  selectedAttendanceMode,
134051
134419
  selectedTicketTypeId,
134420
+ selectedSlidingAmount,
134052
134421
  ticketsCount,
134053
134422
  formData,
134054
134423
  altchaSolution,
@@ -134063,6 +134432,10 @@ function useEventRegistrationWizard(options) {
134063
134432
  });
134064
134433
  const handleEventSelect = (event) => {
134065
134434
  setSelectedEvent(event);
134435
+ const slidingScale = getSlidingScaleForEvent(event);
134436
+ setSelectedSlidingAmountInput(
134437
+ slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(slidingScale.suggestedAmount) : ""
134438
+ );
134066
134439
  setSelectedAttendanceMode(
134067
134440
  (event.deliveryMode ?? "in_person") === "hybrid" ? null : (event.deliveryMode ?? "in_person") === "online" ? "online" : "in_person"
134068
134441
  );
@@ -134072,6 +134445,7 @@ function useEventRegistrationWizard(options) {
134072
134445
  const handleRetry = () => {
134073
134446
  dispatchFlow({ type: "reset", hasPreSelectedContext });
134074
134447
  setSelectedTicketTypeId(null);
134448
+ setSelectedSlidingAmountInput("");
134075
134449
  setSelectedAttendanceMode(
134076
134450
  preSelectedEvent?.deliveryMode === "online" ? "online" : preSelectedEvent?.deliveryMode === "in_person" ? "in_person" : null
134077
134451
  );
@@ -134108,6 +134482,11 @@ function useEventRegistrationWizard(options) {
134108
134482
  setSelectedAttendanceMode,
134109
134483
  selectedTicketTypeId,
134110
134484
  setSelectedTicketTypeId,
134485
+ selectedSlidingAmountInput,
134486
+ setSelectedSlidingAmountInput,
134487
+ selectedSlidingAmount,
134488
+ selectedEventSlidingScale,
134489
+ slidingScaleSelectionMessage,
134111
134490
  selectedTicketType,
134112
134491
  visibleTicketTypes,
134113
134492
  ticketTypeSelectionRequired,
@@ -135188,6 +135567,44 @@ function CoursePricingSelector({
135188
135567
  )
135189
135568
  ] });
135190
135569
  }
135570
+ function CourseSlidingScaleInput({
135571
+ pricing,
135572
+ value,
135573
+ onChange
135574
+ }) {
135575
+ const slidingScale = pricing.slidingScale;
135576
+ if (!slidingScale) {
135577
+ return null;
135578
+ }
135579
+ const minLabel = formatCoursePriceAmount(slidingScale.minAmount, pricing.currency);
135580
+ const maxLabel = formatCoursePriceAmount(slidingScale.maxAmount, pricing.currency);
135581
+ const suggestedLabel = slidingScale.suggestedAmount !== null ? formatCoursePriceAmount(slidingScale.suggestedAmount, pricing.currency) : null;
135582
+ return /* @__PURE__ */ jsxs("div", { className: "cr-form__field", children: [
135583
+ /* @__PURE__ */ jsx("label", { htmlFor: "cr-sliding-amount", className: "cr-form__label", children: "Amount" }),
135584
+ /* @__PURE__ */ jsx(
135585
+ "input",
135586
+ {
135587
+ id: "cr-sliding-amount",
135588
+ type: "number",
135589
+ min: slidingScale.minAmount / 100,
135590
+ max: slidingScale.maxAmount / 100,
135591
+ step: "0.01",
135592
+ inputMode: "decimal",
135593
+ className: "cr-form__input",
135594
+ value,
135595
+ onChange: (event) => onChange(event.target.value)
135596
+ }
135597
+ ),
135598
+ /* @__PURE__ */ jsxs("p", { className: "cr-text cr-text--muted", children: [
135599
+ "Choose between ",
135600
+ minLabel,
135601
+ " and ",
135602
+ maxLabel,
135603
+ suggestedLabel ? `; suggested ${suggestedLabel}` : "",
135604
+ "."
135605
+ ] })
135606
+ ] });
135607
+ }
135191
135608
  function EnrollmentForm({ formData, errors, onChange, isEmailLocked, isLoading, onLogout }) {
135192
135609
  const nameErrorId = "cr-name-error";
135193
135610
  const emailErrorId = "cr-email-error";
@@ -135270,6 +135687,17 @@ function EnrollmentForm({ formData, errors, onChange, isEmailLocked, isLoading,
135270
135687
  ] })
135271
135688
  ] });
135272
135689
  }
135690
+ function parseCurrencyInputToCents2(value) {
135691
+ const trimmed = value.trim();
135692
+ if (!trimmed) return null;
135693
+ const amount = Number(trimmed);
135694
+ if (!Number.isFinite(amount) || amount < 0) return null;
135695
+ return Math.round(amount * 100);
135696
+ }
135697
+ function formatCentsAsCurrencyInput2(amount) {
135698
+ const major = amount / 100;
135699
+ return Number.isInteger(major) ? String(major) : major.toFixed(2);
135700
+ }
135273
135701
  function shouldFetchCourseEligibility(course, hasPaidSelection, portalAuthState, hasWaitlistClaimToken) {
135274
135702
  if (!course || portalAuthState === "checking") return false;
135275
135703
  if (hasWaitlistClaimToken) return false;
@@ -135287,12 +135715,27 @@ function getSessionIdFromUrl() {
135287
135715
  }
135288
135716
  function getMissingCoursePricingSelectionMessage(pricing) {
135289
135717
  if (pricing?.requiresSelection && !pricing.selectedOption) {
135718
+ if (pricing.slidingScale) {
135719
+ return "Choose an amount to continue.";
135720
+ }
135290
135721
  return "Choose a pricing option to continue.";
135291
135722
  }
135723
+ if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null && pricing.selectedSlidingAmount < pricing.slidingScale.minAmount) {
135724
+ return "Choose an amount within the sliding scale.";
135725
+ }
135726
+ if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null && pricing.selectedSlidingAmount > pricing.slidingScale.maxAmount) {
135727
+ return "Choose an amount within the sliding scale.";
135728
+ }
135292
135729
  return null;
135293
135730
  }
135294
135731
  function buildCoursePricingOptionPayload(pricing) {
135295
- return pricing?.selectedOption ? { pricingOptionId: pricing.selectedOption.id } : {};
135732
+ if (pricing?.selectedOption) {
135733
+ return { pricingOptionId: pricing.selectedOption.id };
135734
+ }
135735
+ if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null) {
135736
+ return { selectedSlidingAmount: pricing.selectedSlidingAmount };
135737
+ }
135738
+ return {};
135296
135739
  }
135297
135740
  function resolveHasCoursePayment(pricing) {
135298
135741
  if (!pricing) {
@@ -135333,6 +135776,7 @@ function useCourseRegistrationWizard(props2) {
135333
135776
  scopedCourses.length === 1 ? scopedCourses[0] ?? null : null
135334
135777
  );
135335
135778
  const [selectedPricingOptionId, setSelectedPricingOptionId] = useState(null);
135779
+ const [selectedSlidingAmountInput, setSelectedSlidingAmountInput] = useState("");
135336
135780
  const [formData, setFormData] = useState({
135337
135781
  name: "",
135338
135782
  email: "",
@@ -135354,8 +135798,12 @@ function useCourseRegistrationWizard(props2) {
135354
135798
  const [bookingMode, setBookingMode] = useState(null);
135355
135799
  const waitlistClaim = useWaitlistClaim();
135356
135800
  const selectedCoursePricing = useMemo(
135357
- () => selectedCourse ? resolveCoursePricingState(selectedCourse, selectedPricingOptionId) : null,
135358
- [selectedCourse, selectedPricingOptionId]
135801
+ () => selectedCourse ? resolveCoursePricingState(
135802
+ selectedCourse,
135803
+ selectedPricingOptionId,
135804
+ parseCurrencyInputToCents2(selectedSlidingAmountInput)
135805
+ ) : null,
135806
+ [selectedCourse, selectedPricingOptionId, selectedSlidingAmountInput]
135359
135807
  );
135360
135808
  const missingPricingSelectionMessage = getMissingCoursePricingSelectionMessage(
135361
135809
  selectedCoursePricing
@@ -135428,9 +135876,13 @@ function useCourseRegistrationWizard(props2) {
135428
135876
  useEffect(() => {
135429
135877
  if (!selectedCourse) {
135430
135878
  setSelectedPricingOptionId(null);
135879
+ setSelectedSlidingAmountInput("");
135431
135880
  return;
135432
135881
  }
135433
135882
  const defaultPricing = resolveCoursePricingState(selectedCourse, null);
135883
+ setSelectedSlidingAmountInput(
135884
+ defaultPricing.slidingScale?.suggestedAmount !== null && defaultPricing.slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput2(defaultPricing.slidingScale.suggestedAmount) : ""
135885
+ );
135434
135886
  setSelectedPricingOptionId((previous) => {
135435
135887
  if (previous && defaultPricing.selectableOptions.some((option) => option.id === previous)) {
135436
135888
  return previous;
@@ -135805,6 +136257,8 @@ function useCourseRegistrationWizard(props2) {
135805
136257
  selectedCourse,
135806
136258
  selectedPricingOptionId,
135807
136259
  setSelectedPricingOptionId,
136260
+ selectedSlidingAmountInput,
136261
+ setSelectedSlidingAmountInput,
135808
136262
  selectedCoursePricing,
135809
136263
  setSelectedCourse,
135810
136264
  formData,
@@ -135852,6 +136306,19 @@ function useCourseRegistrationWizard(props2) {
135852
136306
  handleBookingModeChange
135853
136307
  };
135854
136308
  }
136309
+ function getCourseSlidingScaleMessage(pricing) {
136310
+ if (!pricing.slidingScale) {
136311
+ return null;
136312
+ }
136313
+ const selectedAmount = pricing.selectedSlidingAmount;
136314
+ if (selectedAmount === null) {
136315
+ return "Choose an amount to continue.";
136316
+ }
136317
+ if (selectedAmount < pricing.slidingScale.minAmount || selectedAmount > pricing.slidingScale.maxAmount) {
136318
+ return "Choose an amount within the sliding scale.";
136319
+ }
136320
+ return null;
136321
+ }
135855
136322
  function CourseRegistrationWizard(props2) {
135856
136323
  const {
135857
136324
  showSessions = true,
@@ -135873,6 +136340,8 @@ function CourseRegistrationWizard(props2) {
135873
136340
  selectedCourse,
135874
136341
  selectedPricingOptionId,
135875
136342
  setSelectedPricingOptionId,
136343
+ selectedSlidingAmountInput,
136344
+ setSelectedSlidingAmountInput,
135876
136345
  selectedCoursePricing,
135877
136346
  formData,
135878
136347
  setFormData,
@@ -135943,7 +136412,8 @@ function CourseRegistrationWizard(props2) {
135943
136412
  const canShowDiscountUi = !discountsAvailableLoading && paymentChoice === "checkout" && discountsAvailable && manualCodeEntryAllowed;
135944
136413
  const courseSoldOut = waitlistClaim.claim === null && courseEligibility?.isFull === true && courseEligibility.canJoinWaitlist !== true;
135945
136414
  const detailsSubmitLabel = courseEligibility?.canJoinWaitlist ? "Join waitlist" : buttonText;
135946
- const pricingSelectionMissing = selectedCoursePricing?.requiresSelection === true && !selectedCoursePricing.selectedOption;
136415
+ const pricingSelectionMissing = selectedCoursePricing?.requiresSelection === true && !selectedCoursePricing.selectedOption && !selectedCoursePricing.slidingScale;
136416
+ const slidingScaleMessage = selectedCoursePricing ? getCourseSlidingScaleMessage(selectedCoursePricing) : null;
135947
136417
  const pricingUnavailable = selectedCoursePricing?.display.kind === "unavailable";
135948
136418
  const selectedCourseWithPricing = selectedCourse && selectedCoursePricing ? {
135949
136419
  course: selectedCourse,
@@ -136036,6 +136506,14 @@ function CourseRegistrationWizard(props2) {
136036
136506
  onSelect: setSelectedPricingOptionId
136037
136507
  }
136038
136508
  ),
136509
+ /* @__PURE__ */ jsx(
136510
+ CourseSlidingScaleInput,
136511
+ {
136512
+ pricing: selectedCourseWithPricing.pricing,
136513
+ value: selectedSlidingAmountInput,
136514
+ onChange: setSelectedSlidingAmountInput
136515
+ }
136516
+ ),
136039
136517
  showSpamProtection && /* @__PURE__ */ jsx("div", { className: "cr-altcha", children: /* @__PURE__ */ jsx(
136040
136518
  AltchaWidget,
136041
136519
  {
@@ -136073,7 +136551,7 @@ function CourseRegistrationWizard(props2) {
136073
136551
  {
136074
136552
  type: "submit",
136075
136553
  className: buttonClass,
136076
- disabled: courseSoldOut || eligibilityLoading || pricingSelectionMissing || pricingUnavailable,
136554
+ disabled: courseSoldOut || eligibilityLoading || pricingSelectionMissing || slidingScaleMessage !== null || pricingUnavailable,
136077
136555
  children: eligibilityLoading ? "Checking availability\u2026" : courseSoldOut ? "Sold out" : detailsSubmitLabel
136078
136556
  }
136079
136557
  )
@@ -136083,6 +136561,7 @@ function CourseRegistrationWizard(props2) {
136083
136561
  ),
136084
136562
  courseSoldOut && /* @__PURE__ */ jsx("p", { className: "cr-text cr-text--muted", children: "This course is fully booked and there is no waitlist available right now." }),
136085
136563
  pricingSelectionMissing && /* @__PURE__ */ jsx("p", { className: "cr-text cr-text--muted", children: "Choose a pricing option to continue." }),
136564
+ slidingScaleMessage && /* @__PURE__ */ jsx("p", { className: "cr-text cr-text--muted", children: slidingScaleMessage }),
136086
136565
  pricingUnavailable && /* @__PURE__ */ jsx("p", { className: "cr-text cr-text--muted", children: "Pricing is not available for this course right now." }),
136087
136566
  eligibilityError && /* @__PURE__ */ jsx("p", { className: "cr-text cr-text--error", children: eligibilityError })
136088
136567
  ] })
@@ -137782,12 +138261,13 @@ var CarouselNodeClient = ({
137782
138261
  ]
137783
138262
  );
137784
138263
  const resolvedSlides = resolveSlidesToShowMobile(normalized.slidesToShow);
138264
+ const canAutoplay = normalized.autoplay && slides.length > 1;
137785
138265
  const cssVars = React61__default.useMemo(
137786
138266
  () => getCarouselSlidesToShowCssVars(normalized.slidesToShow),
137787
138267
  [normalized.slidesToShow]
137788
138268
  );
137789
138269
  const plugins = React61__default.useMemo(() => {
137790
- if (!normalized.autoplay) return void 0;
138270
+ if (!canAutoplay) return void 0;
137791
138271
  return [
137792
138272
  Autoplay({
137793
138273
  delay: normalized.autoplayDelay,
@@ -137797,7 +138277,7 @@ var CarouselNodeClient = ({
137797
138277
  // Continue after manual navigation
137798
138278
  })
137799
138279
  ];
137800
- }, [normalized.autoplay, normalized.autoplayDelay]);
138280
+ }, [canAutoplay, normalized.autoplayDelay]);
137801
138281
  const [viewportRef, api] = useEmblaCarousel(
137802
138282
  {
137803
138283
  align: "start",
@@ -137836,7 +138316,7 @@ var CarouselNodeClient = ({
137836
138316
  };
137837
138317
  }, [api]);
137838
138318
  React61__default.useEffect(() => {
137839
- if (!api || !normalized.autoplay) return;
138319
+ if (!api || !canAutoplay) return;
137840
138320
  const autoplayPlugin = api.plugins()?.autoplay;
137841
138321
  if (!autoplayPlugin) return;
137842
138322
  const handleVisibility = () => {
@@ -137845,7 +138325,7 @@ var CarouselNodeClient = ({
137845
138325
  };
137846
138326
  document.addEventListener("visibilitychange", handleVisibility);
137847
138327
  return () => document.removeEventListener("visibilitychange", handleVisibility);
137848
- }, [api, normalized.autoplay]);
138328
+ }, [api, canAutoplay]);
137849
138329
  const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
137850
138330
  /* @__PURE__ */ jsx("div", { className: "carousel-frame rb-overflow-hidden rb-w-full", children: /* @__PURE__ */ jsx(
137851
138331
  "div",
@@ -137896,7 +138376,7 @@ var CarouselNodeClient = ({
137896
138376
  "data-show-controls": normalized.showControls ? "true" : "false",
137897
138377
  "data-show-dots": normalized.showDots ? "true" : "false",
137898
138378
  "data-arrow-visibility": normalized.arrowVisibility,
137899
- "data-autoplay": normalized.autoplay ? "true" : "false",
138379
+ "data-autoplay": canAutoplay ? "true" : "false",
137900
138380
  "data-loop": normalized.loop ? "true" : "false",
137901
138381
  children: inner
137902
138382
  }