@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
@@ -826,6 +826,7 @@ function createBlockApi(config) {
826
826
  body: {
827
827
  courseId: data.courseId,
828
828
  ...data.pricingOptionId ? { pricingOptionId: data.pricingOptionId } : {},
829
+ ...data.selectedSlidingAmount !== void 0 ? { selectedSlidingAmount: data.selectedSlidingAmount } : {},
829
830
  email: data.email,
830
831
  name: data.name,
831
832
  phone: data.phone,
@@ -2986,12 +2987,13 @@ var init_result = __esm({
2986
2987
  });
2987
2988
 
2988
2989
  // ../core/src/branded.ts
2989
- var unsafeAsMediaAssetId, unsafeAsStorageBucketName, unsafeAsPositiveByteCount, unsafeAsPositiveSeconds, unsafeAsFormId, unsafeAsPassId, unsafeAsCustomerPassId, unsafeAsAppointmentServiceId, unsafeAsAppointmentResourceId;
2990
+ var unsafeAsMediaAssetId, unsafeAsStorageBucketName, unsafeAsStoragePath, unsafeAsPositiveByteCount, unsafeAsPositiveSeconds, unsafeAsFormId, unsafeAsPassId, unsafeAsCustomerPassId, unsafeAsAppointmentServiceId, unsafeAsAppointmentResourceId;
2990
2991
  var init_branded = __esm({
2991
2992
  "../core/src/branded.ts"() {
2992
2993
  "use strict";
2993
2994
  unsafeAsMediaAssetId = (id) => id;
2994
2995
  unsafeAsStorageBucketName = (value) => value;
2996
+ unsafeAsStoragePath = (value) => value;
2995
2997
  unsafeAsPositiveByteCount = (value) => value;
2996
2998
  unsafeAsPositiveSeconds = (value) => value;
2997
2999
  unsafeAsFormId = (id) => id;
@@ -3137,6 +3139,7 @@ function publicEventPricingType(pricing) {
3137
3139
  return "free";
3138
3140
  case "single_paid":
3139
3141
  case "ticket_types":
3142
+ case "sliding_scale":
3140
3143
  case "course":
3141
3144
  return isFreePublicEventPriceDisplay(pricing.display) ? "free" : "paid";
3142
3145
  case "external":
@@ -3149,6 +3152,7 @@ function publicEventPricingCurrency(pricing) {
3149
3152
  case "free_registration":
3150
3153
  case "single_paid":
3151
3154
  case "ticket_types":
3155
+ case "sliding_scale":
3152
3156
  return pricing.currency;
3153
3157
  case "course":
3154
3158
  return pricing.display.display.currency;
@@ -3166,6 +3170,8 @@ function publicEventPricingMode(pricing) {
3166
3170
  return "single";
3167
3171
  case "ticket_types":
3168
3172
  return "ticket_types";
3173
+ case "sliding_scale":
3174
+ return "sliding_scale";
3169
3175
  case "drop_in":
3170
3176
  case "course":
3171
3177
  case "external":
@@ -3199,6 +3205,8 @@ function formatCoursePriceDisplayLabel(display, options) {
3199
3205
  return `Course (${formatCurrencyAmount(display.amount, display.currency, options)})`;
3200
3206
  case "from":
3201
3207
  return `Course (From ${formatCurrencyAmount(display.amount, display.currency, options)})`;
3208
+ case "range":
3209
+ return `Course (${formatCurrencyAmount(display.minAmount, display.currency, options)} - ${formatCurrencyAmount(display.maxAmount, display.currency, options)})`;
3202
3210
  default:
3203
3211
  return assertNever2(display);
3204
3212
  }
@@ -3950,9 +3958,20 @@ var init_types5 = __esm({
3950
3958
  });
3951
3959
 
3952
3960
  // ../media-core/src/fileSafety.ts
3961
+ function containsUnsafePathSegmentCharacter(value) {
3962
+ return value.includes("/") || value.includes("\\") || CONTROL_CHARACTER_PATTERN.test(value);
3963
+ }
3964
+ function isReservedPathSegment(value) {
3965
+ return value === "." || value === "..";
3966
+ }
3967
+ function isUnsafePathSegment(segment) {
3968
+ return segment.trim().length === 0 || segment !== segment.trim() || isReservedPathSegment(segment) || containsUnsafePathSegmentCharacter(segment);
3969
+ }
3970
+ var CONTROL_CHARACTER_PATTERN;
3953
3971
  var init_fileSafety = __esm({
3954
3972
  "../media-core/src/fileSafety.ts"() {
3955
3973
  "use strict";
3974
+ CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/u;
3956
3975
  }
3957
3976
  });
3958
3977
 
@@ -3992,11 +4011,21 @@ var init_fileDomain = __esm({
3992
4011
  });
3993
4012
 
3994
4013
  // ../media-core/src/fileStorage.ts
4014
+ function parseStoragePath(value) {
4015
+ return joinStoragePathSegments(value.split("/"));
4016
+ }
4017
+ function joinStoragePathSegments(segments) {
4018
+ if (segments.some(isUnsafePathSegment)) {
4019
+ return err("unsafe-path-segment");
4020
+ }
4021
+ return ok(unsafeAsStoragePath(segments.join("/")));
4022
+ }
3995
4023
  var FILE_STORAGE_BUCKETS, PUBLIC_SITE_FILE_STORAGE_BUCKETS, PRIVATE_SITE_FILE_BUCKET_MIME_TYPES, TEMP_UPLOAD_BUCKET_MIME_TYPES;
3996
4024
  var init_fileStorage = __esm({
3997
4025
  "../media-core/src/fileStorage.ts"() {
3998
4026
  "use strict";
3999
4027
  init_src();
4028
+ init_fileSafety();
4000
4029
  FILE_STORAGE_BUCKETS = {
4001
4030
  publicSite: unsafeAsStorageBucketName("media"),
4002
4031
  privateSite: unsafeAsStorageBucketName("site-files-private"),
@@ -4182,14 +4211,18 @@ var init_uploadVerificationContract = __esm({
4182
4211
  });
4183
4212
 
4184
4213
  // ../media-core/src/videoPrep.ts
4214
+ function unsafeAsPositiveVideoDurationSeconds(value) {
4215
+ return value;
4216
+ }
4185
4217
  var VIDEO_PREP_LIMITS;
4186
4218
  var init_videoPrep = __esm({
4187
4219
  "../media-core/src/videoPrep.ts"() {
4188
4220
  "use strict";
4221
+ init_src();
4189
4222
  VIDEO_PREP_LIMITS = {
4190
- maxRawByteCount: 500 * 1024 * 1024,
4191
- inlineContentMaxDurationSeconds: 60,
4192
- backgroundVideoMaxDurationSeconds: 30,
4223
+ maxRawByteCount: unsafeAsPositiveByteCount(500 * 1024 * 1024),
4224
+ inlineContentMaxDurationSeconds: unsafeAsPositiveVideoDurationSeconds(60),
4225
+ backgroundVideoMaxDurationSeconds: unsafeAsPositiveVideoDurationSeconds(30),
4193
4226
  targetMaxDimensionPixels: 1080
4194
4227
  };
4195
4228
  }
@@ -4260,10 +4293,10 @@ var init_identifiers = __esm({
4260
4293
 
4261
4294
  // ../media-core/src/url.ts
4262
4295
  function isRelativeDirectImageStoragePath(storagePath) {
4263
- return RELATIVE_STORAGE_PATH_PREFIXES.some((prefix) => storagePath.startsWith(prefix));
4296
+ return RELATIVE_STORAGE_PATH_PREFIXES.some((prefix) => storagePath.startsWith(prefix)) && parseStoragePath(storagePath).ok;
4264
4297
  }
4265
4298
  function isSiteScopedDirectImageStoragePath(storagePath) {
4266
- return storagePath.startsWith("sites/");
4299
+ return storagePath.startsWith("sites/") && parseStoragePath(storagePath).ok;
4267
4300
  }
4268
4301
  function encodeStoragePath(storagePath) {
4269
4302
  return storagePath.split("/").map((segment) => encodeURIComponent(segment)).join("/");
@@ -4344,6 +4377,7 @@ var DEFAULT_BASE_PATH, RELATIVE_STORAGE_PATH_PREFIXES, formatNumber, ORDER, getI
4344
4377
  var init_url = __esm({
4345
4378
  "../media-core/src/url.ts"() {
4346
4379
  "use strict";
4380
+ init_fileStorage();
4347
4381
  DEFAULT_BASE_PATH = "/api/img";
4348
4382
  RELATIVE_STORAGE_PATH_PREFIXES = [
4349
4383
  "originals/",
@@ -7098,6 +7132,7 @@ var init_booking_form_reserved_fields = __esm({
7098
7132
  "selectedDate",
7099
7133
  "selectedSlot",
7100
7134
  "discountCode",
7135
+ "selectedSlidingAmountInput",
7101
7136
  "selectedCollectionOptionKind",
7102
7137
  "selectedAppointmentPackageId"
7103
7138
  ];
@@ -7383,6 +7418,32 @@ function readOptionalString(value) {
7383
7418
  function readOptionalNumber(value) {
7384
7419
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
7385
7420
  }
7421
+ function getBookingServiceSlidingScale(service) {
7422
+ const pricing = service?.pricing;
7423
+ if (!pricing || pricing.pricingStrategy !== "sliding_scale" || pricing.slidingMinAmount === null || pricing.slidingMinAmount === void 0 || pricing.slidingMaxAmount === null || pricing.slidingMaxAmount === void 0) {
7424
+ return null;
7425
+ }
7426
+ return {
7427
+ minAmount: pricing.slidingMinAmount,
7428
+ maxAmount: pricing.slidingMaxAmount,
7429
+ suggestedAmount: pricing.slidingSuggestedAmount ?? null,
7430
+ currency: pricing.currency
7431
+ };
7432
+ }
7433
+ function parseBookingCurrencyInputToCents(value) {
7434
+ const trimmed = value?.trim() ?? "";
7435
+ if (!trimmed) return null;
7436
+ if (!/^(?:\d+(?:\.\d{0,2})?|\.\d{1,2})$/.test(trimmed)) return null;
7437
+ const parsed = Number(trimmed);
7438
+ if (!Number.isFinite(parsed) || parsed < 0) return null;
7439
+ return Math.round(parsed * 100);
7440
+ }
7441
+ function formatBookingCentsAsCurrencyInput(amount) {
7442
+ return amount % 100 === 0 ? String(amount / 100) : (amount / 100).toFixed(2);
7443
+ }
7444
+ function isBookingServiceSlidingAmountInRange(slidingScale, selectedAmount) {
7445
+ return selectedAmount !== null && selectedAmount >= slidingScale.minAmount && selectedAmount <= slidingScale.maxAmount;
7446
+ }
7386
7447
  function readStringArray(value) {
7387
7448
  if (!Array.isArray(value)) return void 0;
7388
7449
  const strings = value.filter((item) => typeof item === "string");
@@ -7571,6 +7632,20 @@ function prepareBookingSubmission(input) {
7571
7632
  };
7572
7633
  }
7573
7634
  const paymentSelectionMode = getBookingServicePaymentSelectionMode(selectedService);
7635
+ const slidingScale = getBookingServiceSlidingScale(selectedService);
7636
+ const selectedSlidingAmount = parseBookingCurrencyInputToCents(
7637
+ input.data.selectedSlidingAmountInput
7638
+ );
7639
+ if (slidingScale && !isBookingServiceSlidingAmountInRange(slidingScale, selectedSlidingAmount)) {
7640
+ return {
7641
+ ok: false,
7642
+ error: {
7643
+ tag: selectedSlidingAmount === null ? "sliding-amount-required" : "sliding-amount-out-of-range",
7644
+ serviceId,
7645
+ serviceTitle: selectedService.title || serviceId
7646
+ }
7647
+ };
7648
+ }
7574
7649
  if (paymentSelectionMode === "choice_required" && !toSelectedCollectionOptionKind(input.data.selectedCollectionOptionKind)) {
7575
7650
  return {
7576
7651
  ok: false,
@@ -7598,6 +7673,7 @@ function prepareBookingSubmission(input) {
7598
7673
  ...common,
7599
7674
  kind: "standard",
7600
7675
  ...discountCode ? { discountCode } : {},
7676
+ ...slidingScale && selectedSlidingAmount !== null ? { selectedSlidingAmount } : {},
7601
7677
  ...selectedCollectionOptionKind ? { selectedCollectionOptionKind } : {},
7602
7678
  altchaSolution: input.altchaSolution ?? null
7603
7679
  }
@@ -7611,6 +7687,10 @@ function formatBookingSubmissionPreparationError(error) {
7611
7687
  return `Service not found: ${error.serviceId}`;
7612
7688
  case "payment-option-required":
7613
7689
  return `Please choose how you want to pay for "${error.serviceTitle}".`;
7690
+ case "sliding-amount-required":
7691
+ return `Please choose an amount for "${error.serviceTitle}".`;
7692
+ case "sliding-amount-out-of-range":
7693
+ return `Please choose an amount within the sliding scale for "${error.serviceTitle}".`;
7614
7694
  case "payment-option-unsupported":
7615
7695
  return `Service "${error.serviceTitle}" has a payment option that is not supported yet.`;
7616
7696
  case "service-missing-duration":
@@ -7831,6 +7911,7 @@ var init_booking_form_interactive = __esm({
7831
7911
  title: z10.string(),
7832
7912
  description: z10.string().nullable().optional().transform((value) => value ?? void 0),
7833
7913
  durationMinutes: z10.number().optional(),
7914
+ pricing: z10.custom().optional(),
7834
7915
  priceAmount: z10.number().nullable().optional(),
7835
7916
  priceCurrency: z10.string().nullable().optional(),
7836
7917
  paymentTerms: blockBookingPaymentTermsSchema.optional(),
@@ -8117,9 +8198,12 @@ var init_schemas = __esm({
8117
8198
  });
8118
8199
  coursePricingSchema = z11.object({
8119
8200
  bookingRequirement: z11.enum(["none", "required"]),
8120
- pricingStrategy: z11.enum(["free", "single", "tiered"]),
8201
+ pricingStrategy: z11.enum(["free", "single", "tiered", "sliding_scale"]),
8121
8202
  currency: z11.string(),
8122
8203
  singlePriceAmount: z11.number().nullable(),
8204
+ slidingMinAmount: z11.number().nullable().optional(),
8205
+ slidingMaxAmount: z11.number().nullable().optional(),
8206
+ slidingSuggestedAmount: z11.number().nullable().optional(),
8123
8207
  paymentTerms: blockBookingPaymentTermsSchema,
8124
8208
  options: z11.array(coursePricingOptionSchema)
8125
8209
  });
@@ -8181,7 +8265,9 @@ function getSelectableCoursePricingOptionsForNow(course, now) {
8181
8265
  return left.name.localeCompare(right.name);
8182
8266
  });
8183
8267
  }
8184
- function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {}) {
8268
+ function resolveCoursePricingState(course, selectedPricingOptionId, selectedSlidingAmountOrNowInput, nowInput = {}) {
8269
+ const selectedSlidingAmount = typeof selectedSlidingAmountOrNowInput === "number" || selectedSlidingAmountOrNowInput === null ? selectedSlidingAmountOrNowInput : null;
8270
+ const effectiveNowInput = typeof selectedSlidingAmountOrNowInput === "object" && selectedSlidingAmountOrNowInput !== null ? selectedSlidingAmountOrNowInput : nowInput;
8185
8271
  const currency = course.pricing?.currency ?? course.currency;
8186
8272
  if (!course.pricing) {
8187
8273
  const legacyAmount = course.priceCents ?? 0;
@@ -8191,6 +8277,8 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
8191
8277
  selectableOptions: [],
8192
8278
  requiresSelection: false,
8193
8279
  selectedOption: null,
8280
+ slidingScale: null,
8281
+ selectedSlidingAmount: null,
8194
8282
  selectedPriceAmount: legacyAmount,
8195
8283
  selectedRequiresPayment: legacyAmount > 0,
8196
8284
  hasPaidSelection: legacyAmount > 0,
@@ -8205,6 +8293,8 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
8205
8293
  selectableOptions: [],
8206
8294
  requiresSelection: false,
8207
8295
  selectedOption: null,
8296
+ slidingScale: null,
8297
+ selectedSlidingAmount: null,
8208
8298
  selectedPriceAmount: 0,
8209
8299
  selectedRequiresPayment: false,
8210
8300
  hasPaidSelection: false,
@@ -8218,6 +8308,8 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
8218
8308
  selectableOptions: [],
8219
8309
  requiresSelection: false,
8220
8310
  selectedOption: null,
8311
+ slidingScale: null,
8312
+ selectedSlidingAmount: null,
8221
8313
  selectedPriceAmount: amount,
8222
8314
  selectedRequiresPayment: amount > 0,
8223
8315
  hasPaidSelection: amount > 0,
@@ -8227,7 +8319,7 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
8227
8319
  case "tiered": {
8228
8320
  const selectableOptions = getSelectableCoursePricingOptionsForNow(
8229
8321
  course,
8230
- resolvePlanningDateInput(nowInput)
8322
+ resolvePlanningDateInput(effectiveNowInput)
8231
8323
  );
8232
8324
  const selectedOption = (selectedPricingOptionId ? selectableOptions.find((option) => option.id === selectedPricingOptionId) : null) ?? (selectableOptions.length === 1 ? selectableOptions[0] ?? null : null);
8233
8325
  const lowestAmount = selectableOptions.reduce((lowest, option) => {
@@ -8243,12 +8335,51 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
8243
8335
  selectableOptions,
8244
8336
  requiresSelection: selectableOptions.length > 1,
8245
8337
  selectedOption,
8338
+ slidingScale: null,
8339
+ selectedSlidingAmount: null,
8246
8340
  selectedPriceAmount: selectedOption?.priceAmount ?? null,
8247
8341
  selectedRequiresPayment: (selectedOption?.priceAmount ?? 0) > 0,
8248
8342
  hasPaidSelection: selectableOptions.some((option) => option.priceAmount > 0),
8249
8343
  hasFreeSelection: selectableOptions.some((option) => option.priceAmount === 0)
8250
8344
  };
8251
8345
  }
8346
+ case "sliding_scale": {
8347
+ const minAmount = course.pricing.slidingMinAmount ?? null;
8348
+ const maxAmount = course.pricing.slidingMaxAmount ?? null;
8349
+ if (minAmount === null || maxAmount === null || minAmount < 0 || maxAmount < minAmount) {
8350
+ return {
8351
+ currency,
8352
+ display: { kind: "unavailable", currency },
8353
+ selectableOptions: [],
8354
+ requiresSelection: true,
8355
+ selectedOption: null,
8356
+ slidingScale: null,
8357
+ selectedSlidingAmount: null,
8358
+ selectedPriceAmount: null,
8359
+ selectedRequiresPayment: false,
8360
+ hasPaidSelection: false,
8361
+ hasFreeSelection: false
8362
+ };
8363
+ }
8364
+ const normalizedSelectedAmount = typeof selectedSlidingAmount === "number" && Number.isFinite(selectedSlidingAmount) ? selectedSlidingAmount : null;
8365
+ return {
8366
+ currency,
8367
+ display: { kind: "range", minAmount, maxAmount, currency },
8368
+ selectableOptions: [],
8369
+ requiresSelection: normalizedSelectedAmount === null,
8370
+ selectedOption: null,
8371
+ slidingScale: {
8372
+ minAmount,
8373
+ maxAmount,
8374
+ suggestedAmount: course.pricing.slidingSuggestedAmount ?? null
8375
+ },
8376
+ selectedSlidingAmount: normalizedSelectedAmount,
8377
+ selectedPriceAmount: normalizedSelectedAmount,
8378
+ selectedRequiresPayment: (normalizedSelectedAmount ?? 0) > 0,
8379
+ hasPaidSelection: maxAmount > 0,
8380
+ hasFreeSelection: minAmount === 0
8381
+ };
8382
+ }
8252
8383
  }
8253
8384
  }
8254
8385
  function formatCoursePriceDisplay(display, locale) {
@@ -8357,7 +8488,7 @@ function isRecord7(value) {
8357
8488
  }
8358
8489
  function isPublicEventPricing(value) {
8359
8490
  if (!isRecord7(value) || typeof value.kind !== "string") return false;
8360
- return value.kind === "drop_in" || value.kind === "free_registration" || value.kind === "single_paid" || value.kind === "ticket_types" || value.kind === "course" || value.kind === "external";
8491
+ 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";
8361
8492
  }
8362
8493
  function isPublicEventTicketType(value) {
8363
8494
  return isRecord7(value) && typeof value.id === "string";
@@ -10388,6 +10519,19 @@ var init_schemas2 = __esm({
10388
10519
  ticketTypes: z14.array(publicEventTicketTypeSchema),
10389
10520
  display: publicEventTicketTypePriceDisplaySchema
10390
10521
  }),
10522
+ z14.object({
10523
+ kind: z14.literal("sliding_scale"),
10524
+ minAmount: z14.number(),
10525
+ maxAmount: z14.number(),
10526
+ suggestedAmount: z14.number().nullable(),
10527
+ currency: z14.string(),
10528
+ display: z14.object({
10529
+ kind: z14.literal("range"),
10530
+ minAmount: z14.number(),
10531
+ maxAmount: z14.number(),
10532
+ currency: z14.string()
10533
+ })
10534
+ }),
10391
10535
  z14.object({
10392
10536
  kind: z14.literal("course"),
10393
10537
  display: z14.object({ kind: z14.literal("course"), display: publicCoursePriceDisplaySchema })
@@ -28331,6 +28475,7 @@ function useBookingSubmission(_siteId) {
28331
28475
  customFields: data.customFields,
28332
28476
  timezone: data.timezone,
28333
28477
  discountCode: data.discountCode,
28478
+ selectedSlidingAmount: data.selectedSlidingAmount,
28334
28479
  selectedCollectionOptionKind: data.selectedCollectionOptionKind,
28335
28480
  altchaSolution: data.altchaSolution ?? null,
28336
28481
  successUrl: data.successUrl,
@@ -28859,6 +29004,9 @@ function createInitialBookingFlowReducerState(input) {
28859
29004
  fieldValues: collectInitialFieldValues(initialData),
28860
29005
  touchedFields: {},
28861
29006
  discountCode: toOptionalString(initialData.discountCode) ?? "",
29007
+ selectedSlidingAmountInput: toOptionalString(
29008
+ initialData.selectedSlidingAmountInput
29009
+ ) ?? "",
28862
29010
  selectedCollectionOptionKind: toSelectedCollectionOptionKind(
28863
29011
  initialData.selectedCollectionOptionKind
28864
29012
  ),
@@ -28911,6 +29059,7 @@ function bookingFlowReducer(state, event) {
28911
29059
  selectedDate: void 0,
28912
29060
  selectedSlot: null,
28913
29061
  selectedAppointmentPackageId: void 0,
29062
+ selectedSlidingAmountInput: "",
28914
29063
  selectedCollectionOptionKind: void 0,
28915
29064
  validationErrors: clearBookingFormError(state.validationErrors)
28916
29065
  };
@@ -28964,6 +29113,13 @@ function bookingFlowReducer(state, event) {
28964
29113
  selectedAppointmentPackageId: void 0,
28965
29114
  validationErrors: clearBookingFormError(state.validationErrors)
28966
29115
  };
29116
+ case "sliding-amount-changed":
29117
+ return {
29118
+ ...state,
29119
+ selectedSlidingAmountInput: event.value,
29120
+ selectedAppointmentPackageId: void 0,
29121
+ validationErrors: clearBookingFormError(state.validationErrors)
29122
+ };
28967
29123
  case "appointment-package-selected":
28968
29124
  return {
28969
29125
  ...state,
@@ -29066,6 +29222,7 @@ function toBookingFormData(state) {
29066
29222
  selectedDate: state.selectedDate,
29067
29223
  selectedSlot: state.selectedSlot?.startAt,
29068
29224
  discountCode: state.discountCode || void 0,
29225
+ selectedSlidingAmountInput: state.selectedSlidingAmountInput || void 0,
29069
29226
  selectedCollectionOptionKind: state.selectedCollectionOptionKind,
29070
29227
  selectedAppointmentPackageId: state.selectedAppointmentPackageId
29071
29228
  };
@@ -29083,7 +29240,8 @@ function buildBookingStepResolution(input) {
29083
29240
  input.form.settings?.serviceIds && input.form.settings.serviceIds.length > 1
29084
29241
  );
29085
29242
  const selectedService = paymentResolution.service;
29086
- const needsPayment = paymentResolution.mode !== "hidden" || Boolean(
29243
+ const selectedServiceSlidingScale = getBookingServiceSlidingScale(selectedService);
29244
+ const needsPayment = Boolean(selectedServiceSlidingScale) || paymentResolution.mode !== "hidden" || Boolean(
29087
29245
  input.enableAppointmentPackages && selectedService && (selectedService.priceAmount ?? 0) > 0
29088
29246
  );
29089
29247
  const hasFields = Boolean(input.form.schema?.fields.length);
@@ -29127,6 +29285,18 @@ function validateBookingStep(input) {
29127
29285
  services: input.services,
29128
29286
  defaultServiceId: input.defaultServiceId
29129
29287
  });
29288
+ const slidingScale = getBookingServiceSlidingScale(resolution.service);
29289
+ if (slidingScale && !isBookingServiceSlidingAmountInRange(
29290
+ slidingScale,
29291
+ parseBookingCurrencyInputToCents(input.data.selectedSlidingAmountInput)
29292
+ )) {
29293
+ return {
29294
+ ok: false,
29295
+ errors: createFormBookingValidationError(
29296
+ "Please choose an amount within the sliding scale"
29297
+ )
29298
+ };
29299
+ }
29130
29300
  if (resolution.mode === "hidden" || resolution.mode === "disclosure_only") {
29131
29301
  return { ok: true };
29132
29302
  }
@@ -29525,6 +29695,7 @@ var init_useHeadlessBookingFlow_state = __esm({
29525
29695
  "../blocks/src/system/runtime/hooks/useHeadlessBookingFlow.state.ts"() {
29526
29696
  "use strict";
29527
29697
  init_booking_form_headless_state();
29698
+ init_booking_form_state();
29528
29699
  }
29529
29700
  });
29530
29701
 
@@ -29564,11 +29735,27 @@ function useHeadlessBookingFlow(options) {
29564
29735
  const selectedServiceId = state.selectedServiceId ?? defaultServiceId;
29565
29736
  const selectedResourceId = state.selectedResourceId ?? defaultResourceId;
29566
29737
  const selectedService = options.services.find((service) => service.id === selectedServiceId) ?? null;
29738
+ const lastSlidingServiceIdRef = useRef6(null);
29739
+ useEffect6(() => {
29740
+ const selectedId = selectedService?.id ?? null;
29741
+ if (lastSlidingServiceIdRef.current === selectedId) return;
29742
+ lastSlidingServiceIdRef.current = selectedId;
29743
+ const slidingScale = getBookingServiceSlidingScale(selectedService);
29744
+ dispatch({
29745
+ type: "sliding-amount-changed",
29746
+ value: slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatBookingCentsAsCurrencyInput(slidingScale.suggestedAmount) : ""
29747
+ });
29748
+ }, [selectedService]);
29567
29749
  const hasPortalBearerAuth = (api.config.authOverrides?.portal ?? api.config.auth).type === "bearer";
29750
+ const selectedServiceSlidingScale = getBookingServiceSlidingScale(selectedService);
29751
+ const selectedSlidingAmount = parseBookingCurrencyInputToCents(
29752
+ state.selectedSlidingAmountInput
29753
+ );
29754
+ const selectedAppointmentPriceAmount = selectedServiceSlidingScale && selectedSlidingAmount !== null ? selectedSlidingAmount : selectedService?.priceAmount ?? 0;
29568
29755
  const canLoadAppointmentPackages = Boolean(
29569
- options.enableAppointmentPackages && hasPortalBearerAuth && selectedService && (selectedService.priceAmount ?? 0) > 0
29756
+ options.enableAppointmentPackages && hasPortalBearerAuth && selectedService && !selectedServiceSlidingScale && (selectedService.priceAmount ?? 0) > 0
29570
29757
  );
29571
- const appointmentPackagesUnavailableReason = !options.enableAppointmentPackages ? "disabled" : !selectedService || (selectedService.priceAmount ?? 0) <= 0 ? "missing-priced-service" : !hasPortalBearerAuth ? "missing-portal-auth" : null;
29758
+ const appointmentPackagesUnavailableReason = !options.enableAppointmentPackages ? "disabled" : !selectedService || selectedServiceSlidingScale || (selectedService.priceAmount ?? 0) <= 0 ? "missing-priced-service" : !hasPortalBearerAuth ? "missing-portal-auth" : null;
29572
29759
  const data = useMemo2(() => toBookingFormData(state), [state]);
29573
29760
  const availabilityDatesQuery = useMemo2(
29574
29761
  () => buildBookingAvailabilityQuery({
@@ -29798,13 +29985,13 @@ function useHeadlessBookingFlow(options) {
29798
29985
  state.selectedSlot
29799
29986
  ]);
29800
29987
  const appointmentDiscountContext = useMemo2(
29801
- () => selectedService && (selectedService.priceAmount ?? 0) > 0 ? { type: "appointment", serviceId: selectedService.id } : null,
29802
- [selectedService?.id, selectedService?.priceAmount]
29988
+ () => selectedService && selectedAppointmentPriceAmount > 0 ? { type: "appointment", serviceId: selectedService.id } : null,
29989
+ [selectedAppointmentPriceAmount, selectedService?.id]
29803
29990
  );
29804
29991
  const discountUi = useDiscountCodeUi({
29805
29992
  api,
29806
29993
  discountContext: appointmentDiscountContext,
29807
- subtotalCents: selectedService?.priceAmount ?? 0
29994
+ subtotalCents: selectedAppointmentPriceAmount
29808
29995
  });
29809
29996
  const { submit, clearFeedback } = useBookingSubmission(options.siteId);
29810
29997
  const submittingRef = useRef6(false);
@@ -29947,6 +30134,7 @@ function useHeadlessBookingFlow(options) {
29947
30134
  type: "appointment-package-selected",
29948
30135
  packageId: packageId ? unsafeAsCustomerPassId(packageId) : null
29949
30136
  }),
30137
+ setSlidingAmountInput: (value) => dispatch({ type: "sliding-amount-changed", value }),
29950
30138
  setDiscountCode: (code) => {
29951
30139
  dispatch({ type: "discount-code-changed", code });
29952
30140
  latestRef.current.setDiscountCode(code);
@@ -30017,11 +30205,11 @@ function useHeadlessBookingFlow(options) {
30017
30205
  () => selectedService && paymentResolution.mode !== "unsupported" ? buildBookingPaymentSelectionViewModel({
30018
30206
  serviceTitle: selectedService.title,
30019
30207
  paymentTerms: selectedService.paymentTerms,
30020
- priceAmount: selectedService.priceAmount,
30208
+ priceAmount: selectedAppointmentPriceAmount,
30021
30209
  priceCurrency: selectedService.priceCurrency,
30022
30210
  bookingStartAt: state.selectedSlot?.startAt
30023
30211
  }) : null,
30024
- [paymentResolution.mode, selectedService, state.selectedSlot?.startAt]
30212
+ [paymentResolution.mode, selectedAppointmentPriceAmount, selectedService, state.selectedSlot?.startAt]
30025
30213
  );
30026
30214
  const appointmentPackageItems = appointmentPackages.tag === "loaded" ? appointmentPackages.value : [];
30027
30215
  const selectedAppointmentPackage = appointmentPackageItems.find(
@@ -30050,6 +30238,9 @@ function useHeadlessBookingFlow(options) {
30050
30238
  selection: null,
30051
30239
  selectedCollectionOptionKind: state.selectedCollectionOptionKind,
30052
30240
  selectedAppointmentPackageId: state.selectedAppointmentPackageId,
30241
+ selectedSlidingAmountInput: state.selectedSlidingAmountInput,
30242
+ selectedSlidingAmount,
30243
+ slidingScale: selectedServiceSlidingScale,
30053
30244
  appointmentPackages: appointmentPackagesModel,
30054
30245
  errorMessage: paymentResolution.errorMessage ?? "This service cannot be booked right now."
30055
30246
  } : {
@@ -30058,6 +30249,9 @@ function useHeadlessBookingFlow(options) {
30058
30249
  selection: paymentSelection,
30059
30250
  selectedCollectionOptionKind: state.selectedCollectionOptionKind,
30060
30251
  selectedAppointmentPackageId: state.selectedAppointmentPackageId,
30252
+ selectedSlidingAmountInput: state.selectedSlidingAmountInput,
30253
+ selectedSlidingAmount,
30254
+ slidingScale: selectedServiceSlidingScale,
30061
30255
  appointmentPackages: appointmentPackagesModel
30062
30256
  };
30063
30257
  return {
@@ -30672,6 +30866,9 @@ var init_FieldValidationMessage = __esm({
30672
30866
 
30673
30867
  // ../blocks/src/system/runtime/nodes/booking-form.default-ui.tsx
30674
30868
  import { Fragment as Fragment9, jsx as jsx62, jsxs as jsxs46 } from "react/jsx-runtime";
30869
+ function formatBookingAmount(amount, currency) {
30870
+ return formatCurrencyAmount(amount, currency, { decimals: "auto" });
30871
+ }
30675
30872
  function HeadlessBookingDefaultForm({
30676
30873
  booking,
30677
30874
  onSubmit
@@ -30948,6 +31145,7 @@ function HeadlessBookingPaymentSelectionStep({
30948
31145
  }
30949
31146
  const packageOptions = booking.payment.appointmentPackages.items;
30950
31147
  const hasPackageOptions = packageOptions.length > 0;
31148
+ const slidingScale = booking.payment.slidingScale;
30951
31149
  return /* @__PURE__ */ jsxs46("div", { className: "ab-stack", children: [
30952
31150
  /* @__PURE__ */ jsxs46("div", { className: "ab-info-box", children: [
30953
31151
  /* @__PURE__ */ jsx62("h3", { className: "ab-subtitle", children: viewModel.sectionTitle }),
@@ -30958,6 +31156,28 @@ function HeadlessBookingPaymentSelectionStep({
30958
31156
  booking.payment.appointmentPackages.state.message,
30959
31157
  " You can continue with the normal payment option."
30960
31158
  ] }) : null,
31159
+ slidingScale ? /* @__PURE__ */ jsxs46("div", { className: "rb-space-y-2", children: [
31160
+ /* @__PURE__ */ jsx62("label", { htmlFor: "appointment-sliding-amount", className: "form-label", children: "Choose your price" }),
31161
+ /* @__PURE__ */ jsxs46("p", { className: "rb-caption status-muted", children: [
31162
+ formatBookingAmount(slidingScale.minAmount, slidingScale.currency),
31163
+ " to ",
31164
+ formatBookingAmount(slidingScale.maxAmount, slidingScale.currency),
31165
+ slidingScale.suggestedAmount !== null ? `, suggested ${formatBookingAmount(slidingScale.suggestedAmount, slidingScale.currency)}` : ""
31166
+ ] }),
31167
+ /* @__PURE__ */ jsx62(
31168
+ "input",
31169
+ {
31170
+ id: "appointment-sliding-amount",
31171
+ type: "number",
31172
+ className: "form-input",
31173
+ min: slidingScale.minAmount / 100,
31174
+ max: slidingScale.maxAmount / 100,
31175
+ step: "0.01",
31176
+ value: booking.payment.selectedSlidingAmountInput,
31177
+ onChange: (event) => booking.actions.setSlidingAmountInput(event.target.value)
31178
+ }
31179
+ )
31180
+ ] }) : null,
30961
31181
  /* @__PURE__ */ jsxs46("div", { className: "ab-stack", role: "list", "aria-label": "Payment options", children: [
30962
31182
  packageOptions.map((appointmentPackage) => {
30963
31183
  const isSelected = booking.payment.selectedAppointmentPackageId === appointmentPackage.customerPassId;
@@ -32893,6 +33113,7 @@ function useEligibility(params) {
32893
33113
  occurrenceId: params.occurrenceId,
32894
33114
  attendanceMode: params.attendanceMode ?? void 0,
32895
33115
  ticketTypeId: params.ticketTypeId ?? void 0,
33116
+ selectedSlidingAmount: params.selectedSlidingAmount ?? void 0,
32896
33117
  email: params.email.trim().toLowerCase(),
32897
33118
  ticketsCount: params.ticketsCount
32898
33119
  });
@@ -32913,7 +33134,7 @@ function useEligibility(params) {
32913
33134
  return () => {
32914
33135
  cancelled = true;
32915
33136
  };
32916
- }, [api, params.enabled, params.occurrenceId, params.attendanceMode, params.ticketTypeId, params.email, params.ticketsCount]);
33137
+ }, [api, params.enabled, params.occurrenceId, params.attendanceMode, params.ticketTypeId, params.selectedSlidingAmount, params.email, params.ticketsCount]);
32917
33138
  return {
32918
33139
  state,
32919
33140
  eligibility: state.eligibility,
@@ -33264,6 +33485,41 @@ function TicketCounterLimit(props2) {
33264
33485
  ] }) : null
33265
33486
  ] });
33266
33487
  }
33488
+ function formatCurrencyInputAmount(amount) {
33489
+ const major = amount / 100;
33490
+ return Number.isInteger(major) ? String(major) : major.toFixed(2);
33491
+ }
33492
+ function SlidingScaleAmountField(props2) {
33493
+ const minLabel = formatPrice(props2.slidingScale.minAmount, props2.currency);
33494
+ const maxLabel = formatPrice(props2.slidingScale.maxAmount, props2.currency);
33495
+ const suggestedLabel = props2.slidingScale.suggestedAmount !== null ? formatPrice(props2.slidingScale.suggestedAmount, props2.currency) : null;
33496
+ return /* @__PURE__ */ jsxs54("div", { className: "er-field", children: [
33497
+ /* @__PURE__ */ jsx77("label", { htmlFor: "er-sliding-amount", className: "er-label", children: "Amount" }),
33498
+ /* @__PURE__ */ jsx77(
33499
+ "input",
33500
+ {
33501
+ id: "er-sliding-amount",
33502
+ type: "number",
33503
+ min: formatCurrencyInputAmount(props2.slidingScale.minAmount),
33504
+ max: formatCurrencyInputAmount(props2.slidingScale.maxAmount),
33505
+ step: "0.01",
33506
+ inputMode: "decimal",
33507
+ className: "er-input",
33508
+ value: props2.value,
33509
+ onChange: (event) => props2.onChange?.(event.target.value)
33510
+ }
33511
+ ),
33512
+ /* @__PURE__ */ jsxs54("p", { className: "er-text er-text--muted", children: [
33513
+ "Choose between ",
33514
+ minLabel,
33515
+ " and ",
33516
+ maxLabel,
33517
+ suggestedLabel ? `; suggested ${suggestedLabel}` : "",
33518
+ "."
33519
+ ] }),
33520
+ props2.message ? /* @__PURE__ */ jsx77("p", { className: "er-text er-text--muted", children: props2.message }) : null
33521
+ ] });
33522
+ }
33267
33523
  function getTicketTypeCounterAvailabilityLabel(input) {
33268
33524
  if (input.selectedRemainingCapacity !== null) {
33269
33525
  return `${input.selectedRemainingCapacity} remaining for this ticket type`;
@@ -33335,6 +33591,10 @@ var init_TicketSelectionStep = __esm({
33335
33591
  maxTickets,
33336
33592
  selectedTicketTypeId = null,
33337
33593
  onTicketTypeChange,
33594
+ slidingScale = null,
33595
+ selectedSlidingAmountInput = "",
33596
+ slidingScaleSelectionMessage = null,
33597
+ onSlidingAmountChange,
33338
33598
  onTicketsChange
33339
33599
  }) => {
33340
33600
  const deliveryMode = event?.deliveryMode ?? "in_person";
@@ -33450,6 +33710,16 @@ var init_TicketSelectionStep = __esm({
33450
33710
  ] })
33451
33711
  ] })
33452
33712
  ] }) : /* @__PURE__ */ jsxs54(Fragment12, { children: [
33713
+ slidingScale ? /* @__PURE__ */ jsx77(
33714
+ SlidingScaleAmountField,
33715
+ {
33716
+ slidingScale,
33717
+ currency: eventPricingCurrency ?? DEFAULT_EVENT_CURRENCY2,
33718
+ value: selectedSlidingAmountInput,
33719
+ message: slidingScaleSelectionMessage,
33720
+ onChange: onSlidingAmountChange
33721
+ }
33722
+ ) : null,
33453
33723
  /* @__PURE__ */ jsx77("h3", { className: "er-title", children: canJoinWaitlist ? "How many waitlist spots?" : "How many tickets?" }),
33454
33724
  /* @__PURE__ */ jsxs54("div", { className: "er-ticket-counter-group", children: [
33455
33725
  /* @__PURE__ */ jsx77(
@@ -34826,6 +35096,10 @@ function EventRegistrationWizardContent(props2) {
34826
35096
  maxTickets: wizard.maxTicketsNum,
34827
35097
  selectedTicketTypeId: wizard.selectedTicketTypeId,
34828
35098
  onTicketTypeChange: wizard.setSelectedTicketTypeId,
35099
+ slidingScale: wizard.selectedEventSlidingScale,
35100
+ selectedSlidingAmountInput: wizard.selectedSlidingAmountInput,
35101
+ slidingScaleSelectionMessage: wizard.slidingScaleSelectionMessage,
35102
+ onSlidingAmountChange: wizard.setSelectedSlidingAmountInput,
34829
35103
  onTicketsChange: wizard.setTicketsCount
34830
35104
  }
34831
35105
  )
@@ -35042,7 +35316,7 @@ function EventRegistrationSummaryBar(props2) {
35042
35316
  const summaryTimeZone = wizard.occurrenceContext?.timeZone ?? summaryEvent?.timeZone ?? null;
35043
35317
  const occurrenceOverrideTitle = wizard.occurrenceContext?.overrides?.title;
35044
35318
  const summaryTitle = occurrenceOverrideTitle ?? summaryEvent?.title ?? "";
35045
- const summaryPrice = wizard.selectedTicketType?.priceAmount ?? wizard.eligibility?.price ?? (summaryEvent ? publicEventScalarPrice(summaryEvent.pricing) : null) ?? 0;
35319
+ const summaryPrice = wizard.selectedTicketType?.priceAmount ?? wizard.eligibility?.price ?? (wizard.selectedEventSlidingScale ? wizard.selectedSlidingAmount : null) ?? (summaryEvent ? publicEventScalarPrice(summaryEvent.pricing) : null) ?? 0;
35046
35320
  const summaryCurrency = (summaryEvent ? publicEventPricingCurrency(summaryEvent.pricing) : null) ?? DEFAULT_EVENT_CURRENCY2;
35047
35321
  const teamMemberNames = (summaryEvent?.teamMembers ?? []).map((teamMember) => teamMember.name).filter(Boolean);
35048
35322
  const subtotalCents = Math.max(0, summaryPrice * wizard.ticketsCount);
@@ -35493,6 +35767,7 @@ function useEventRegistrationSubmit(options) {
35493
35767
  occurrenceId: submitOccurrenceId,
35494
35768
  attendanceMode: options.selectedAttendanceMode ?? void 0,
35495
35769
  ticketTypeId: options.selectedTicketTypeId ?? void 0,
35770
+ selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
35496
35771
  email: options.formData.email.trim().toLowerCase(),
35497
35772
  name: options.formData.name.trim(),
35498
35773
  ticketsCount: options.ticketsCount,
@@ -35602,6 +35877,35 @@ var init_useEventRegistrationSubmit = __esm({
35602
35877
 
35603
35878
  // ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
35604
35879
  import { useCallback as useCallback7, useEffect as useEffect14, useMemo as useMemo7, useReducer as useReducer9, useState as useState4 } from "react";
35880
+ function parseCurrencyInputToCents(value) {
35881
+ const trimmed = value.trim();
35882
+ if (!trimmed) return null;
35883
+ const amount = Number(trimmed);
35884
+ if (!Number.isFinite(amount) || amount < 0) return null;
35885
+ return Math.round(amount * 100);
35886
+ }
35887
+ function formatCentsAsCurrencyInput(amount) {
35888
+ const major = amount / 100;
35889
+ return Number.isInteger(major) ? String(major) : major.toFixed(2);
35890
+ }
35891
+ function getSlidingScaleForEvent(event) {
35892
+ const pricing = event ? resolveRuntimeEventPricing(event) : null;
35893
+ return pricing?.kind === "sliding_scale" ? {
35894
+ minAmount: pricing.minAmount,
35895
+ maxAmount: pricing.maxAmount,
35896
+ suggestedAmount: pricing.suggestedAmount
35897
+ } : null;
35898
+ }
35899
+ function getSlidingScaleSelectionMessage(input) {
35900
+ if (!input.slidingScale) return null;
35901
+ if (input.selectedAmount === null) {
35902
+ return "Choose an amount to continue.";
35903
+ }
35904
+ if (input.selectedAmount < input.slidingScale.minAmount || input.selectedAmount > input.slidingScale.maxAmount) {
35905
+ return "Choose an amount within the sliding scale.";
35906
+ }
35907
+ return null;
35908
+ }
35605
35909
  function useEventRegistrationWizard(options) {
35606
35910
  const api = useBlockApi();
35607
35911
  const registrationEvents = useMemo7(
@@ -35646,6 +35950,10 @@ function useEventRegistrationWizard(options) {
35646
35950
  preSelectedEvent?.deliveryMode === "online" ? "online" : preSelectedEvent?.deliveryMode === "in_person" ? "in_person" : null
35647
35951
  );
35648
35952
  const [selectedTicketTypeId, setSelectedTicketTypeId] = useState4(null);
35953
+ const [selectedSlidingAmountInput, setSelectedSlidingAmountInput] = useState4(() => {
35954
+ const slidingScale = getSlidingScaleForEvent(preSelectedEvent ?? null);
35955
+ return slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(slidingScale.suggestedAmount) : "";
35956
+ });
35649
35957
  const [registrationResult, setRegistrationResult] = useState4(null);
35650
35958
  const [errorMessage, setErrorMessage] = useState4("");
35651
35959
  const [altchaSolution, setAltchaSolution] = useState4(null);
@@ -35682,6 +35990,7 @@ function useEventRegistrationWizard(options) {
35682
35990
  occurrenceId,
35683
35991
  attendanceMode: selectedAttendanceMode,
35684
35992
  ticketTypeId: selectedTicketTypeId,
35993
+ selectedSlidingAmount: parseCurrencyInputToCents(selectedSlidingAmountInput),
35685
35994
  email: formData.email,
35686
35995
  ticketsCount
35687
35996
  });
@@ -35817,6 +36126,18 @@ function useEventRegistrationWizard(options) {
35817
36126
  }),
35818
36127
  [selectedAttendanceMode, selectedEvent, preSelectedEvent, eligibility, selectedTicketTypeId]
35819
36128
  );
36129
+ const selectedSlidingAmount = useMemo7(
36130
+ () => parseCurrencyInputToCents(selectedSlidingAmountInput),
36131
+ [selectedSlidingAmountInput]
36132
+ );
36133
+ const selectedEventSlidingScale = useMemo7(
36134
+ () => getSlidingScaleForEvent(selectedEvent ?? preSelectedEvent),
36135
+ [selectedEvent, preSelectedEvent]
36136
+ );
36137
+ const slidingScaleSelectionMessage = getSlidingScaleSelectionMessage({
36138
+ slidingScale: selectedEventSlidingScale,
36139
+ selectedAmount: selectedSlidingAmount
36140
+ });
35820
36141
  const ticketTypeSelectionRequired = useMemo7(() => {
35821
36142
  const event = selectedEvent ?? preSelectedEvent;
35822
36143
  if (!event || publicEventPricingMode(resolveRuntimeEventPricing(event)) !== "ticket_types") {
@@ -35885,12 +36206,24 @@ function useEventRegistrationWizard(options) {
35885
36206
  setGuestSectionShake(false);
35886
36207
  };
35887
36208
  const eventRequiresPayment = useMemo7(
35888
- () => resolveEventRequiresPayment({
36209
+ () => {
36210
+ if (selectedEventSlidingScale) {
36211
+ return (selectedSlidingAmount ?? 0) > 0;
36212
+ }
36213
+ return resolveEventRequiresPayment({
36214
+ eligibility,
36215
+ selectedTicketType,
36216
+ event: selectedEvent ?? preSelectedEvent
36217
+ });
36218
+ },
36219
+ [
35889
36220
  eligibility,
35890
36221
  selectedTicketType,
35891
- event: selectedEvent ?? preSelectedEvent
35892
- }),
35893
- [eligibility, selectedTicketType, selectedEvent, preSelectedEvent]
36222
+ selectedEvent,
36223
+ preSelectedEvent,
36224
+ selectedEventSlidingScale,
36225
+ selectedSlidingAmount
36226
+ ]
35894
36227
  );
35895
36228
  const handleDetailsComplete = async () => {
35896
36229
  if (ticketTypeSelectionRequired && !hasValidSelectedTicketType) {
@@ -35899,6 +36232,11 @@ function useEventRegistrationWizard(options) {
35899
36232
  setStep("error");
35900
36233
  return { ok: false, reason: "blocked", message };
35901
36234
  }
36235
+ if (slidingScaleSelectionMessage) {
36236
+ setErrorMessage(slidingScaleSelectionMessage);
36237
+ setStep("error");
36238
+ return { ok: false, reason: "blocked", message: slidingScaleSelectionMessage };
36239
+ }
35902
36240
  if (!validateForm()) {
35903
36241
  setGuestSectionShake(true);
35904
36242
  return {
@@ -35983,9 +36321,18 @@ function useEventRegistrationWizard(options) {
35983
36321
  const discountSubtotalCents = useMemo7(() => {
35984
36322
  if (discountContext?.type !== "event") return void 0;
35985
36323
  const event = selectedEvent ?? preSelectedEvent;
35986
- const eventPriceCents = selectedTicketType?.priceAmount ?? eligibility?.price ?? (event ? publicEventScalarPrice(resolveRuntimeEventPricing(event)) : null) ?? 0;
36324
+ const eventPriceCents = selectedTicketType?.priceAmount ?? eligibility?.price ?? (selectedEventSlidingScale ? selectedSlidingAmount : null) ?? (event ? publicEventScalarPrice(resolveRuntimeEventPricing(event)) : null) ?? 0;
35987
36325
  return Math.max(0, eventPriceCents * ticketsCount);
35988
- }, [discountContext, selectedTicketType, eligibility, selectedEvent, preSelectedEvent, ticketsCount]);
36326
+ }, [
36327
+ discountContext,
36328
+ selectedTicketType,
36329
+ eligibility,
36330
+ selectedEvent,
36331
+ preSelectedEvent,
36332
+ selectedEventSlidingScale,
36333
+ selectedSlidingAmount,
36334
+ ticketsCount
36335
+ ]);
35989
36336
  const discountUi = useDiscountCodeUi({ api, discountContext, subtotalCents: discountSubtotalCents });
35990
36337
  const selectionMethod = paymentSelection.method;
35991
36338
  const shouldShowDiscountToggle = discountContext !== null && discountUi.manualCodeEntryAllowed && (selectionMethod === "stripe" || selectionMethod === "pass_bundle" || selectionMethod === "membership_bundle");
@@ -35994,6 +36341,7 @@ function useEventRegistrationWizard(options) {
35994
36341
  registrationTarget,
35995
36342
  selectedAttendanceMode,
35996
36343
  selectedTicketTypeId,
36344
+ selectedSlidingAmount,
35997
36345
  ticketsCount,
35998
36346
  formData,
35999
36347
  altchaSolution,
@@ -36008,6 +36356,10 @@ function useEventRegistrationWizard(options) {
36008
36356
  });
36009
36357
  const handleEventSelect = (event) => {
36010
36358
  setSelectedEvent(event);
36359
+ const slidingScale = getSlidingScaleForEvent(event);
36360
+ setSelectedSlidingAmountInput(
36361
+ slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(slidingScale.suggestedAmount) : ""
36362
+ );
36011
36363
  setSelectedAttendanceMode(
36012
36364
  (event.deliveryMode ?? "in_person") === "hybrid" ? null : (event.deliveryMode ?? "in_person") === "online" ? "online" : "in_person"
36013
36365
  );
@@ -36017,6 +36369,7 @@ function useEventRegistrationWizard(options) {
36017
36369
  const handleRetry = () => {
36018
36370
  dispatchFlow({ type: "reset", hasPreSelectedContext });
36019
36371
  setSelectedTicketTypeId(null);
36372
+ setSelectedSlidingAmountInput("");
36020
36373
  setSelectedAttendanceMode(
36021
36374
  preSelectedEvent?.deliveryMode === "online" ? "online" : preSelectedEvent?.deliveryMode === "in_person" ? "in_person" : null
36022
36375
  );
@@ -36053,6 +36406,11 @@ function useEventRegistrationWizard(options) {
36053
36406
  setSelectedAttendanceMode,
36054
36407
  selectedTicketTypeId,
36055
36408
  setSelectedTicketTypeId,
36409
+ selectedSlidingAmountInput,
36410
+ setSelectedSlidingAmountInput,
36411
+ selectedSlidingAmount,
36412
+ selectedEventSlidingScale,
36413
+ slidingScaleSelectionMessage,
36056
36414
  selectedTicketType,
36057
36415
  visibleTicketTypes,
36058
36416
  ticketTypeSelectionRequired,
@@ -37368,6 +37726,44 @@ function CoursePricingSelector({
37368
37726
  )
37369
37727
  ] });
37370
37728
  }
37729
+ function CourseSlidingScaleInput({
37730
+ pricing,
37731
+ value,
37732
+ onChange
37733
+ }) {
37734
+ const slidingScale = pricing.slidingScale;
37735
+ if (!slidingScale) {
37736
+ return null;
37737
+ }
37738
+ const minLabel = formatCoursePriceAmount(slidingScale.minAmount, pricing.currency);
37739
+ const maxLabel = formatCoursePriceAmount(slidingScale.maxAmount, pricing.currency);
37740
+ const suggestedLabel = slidingScale.suggestedAmount !== null ? formatCoursePriceAmount(slidingScale.suggestedAmount, pricing.currency) : null;
37741
+ return /* @__PURE__ */ jsxs75("div", { className: "cr-form__field", children: [
37742
+ /* @__PURE__ */ jsx105("label", { htmlFor: "cr-sliding-amount", className: "cr-form__label", children: "Amount" }),
37743
+ /* @__PURE__ */ jsx105(
37744
+ "input",
37745
+ {
37746
+ id: "cr-sliding-amount",
37747
+ type: "number",
37748
+ min: slidingScale.minAmount / 100,
37749
+ max: slidingScale.maxAmount / 100,
37750
+ step: "0.01",
37751
+ inputMode: "decimal",
37752
+ className: "cr-form__input",
37753
+ value,
37754
+ onChange: (event) => onChange(event.target.value)
37755
+ }
37756
+ ),
37757
+ /* @__PURE__ */ jsxs75("p", { className: "cr-text cr-text--muted", children: [
37758
+ "Choose between ",
37759
+ minLabel,
37760
+ " and ",
37761
+ maxLabel,
37762
+ suggestedLabel ? `; suggested ${suggestedLabel}` : "",
37763
+ "."
37764
+ ] })
37765
+ ] });
37766
+ }
37371
37767
  function EnrollmentForm({ formData, errors, onChange, isEmailLocked, isLoading, onLogout }) {
37372
37768
  const nameErrorId = "cr-name-error";
37373
37769
  const emailErrorId = "cr-email-error";
@@ -37463,6 +37859,17 @@ var init_components2 = __esm({
37463
37859
 
37464
37860
  // ../blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationWizard.ts
37465
37861
  import { useEffect as useEffect18, useMemo as useMemo9, useState as useState9 } from "react";
37862
+ function parseCurrencyInputToCents2(value) {
37863
+ const trimmed = value.trim();
37864
+ if (!trimmed) return null;
37865
+ const amount = Number(trimmed);
37866
+ if (!Number.isFinite(amount) || amount < 0) return null;
37867
+ return Math.round(amount * 100);
37868
+ }
37869
+ function formatCentsAsCurrencyInput2(amount) {
37870
+ const major = amount / 100;
37871
+ return Number.isInteger(major) ? String(major) : major.toFixed(2);
37872
+ }
37466
37873
  function shouldFetchCourseEligibility(course, hasPaidSelection, portalAuthState, hasWaitlistClaimToken) {
37467
37874
  if (!course || portalAuthState === "checking") return false;
37468
37875
  if (hasWaitlistClaimToken) return false;
@@ -37480,12 +37887,27 @@ function getSessionIdFromUrl() {
37480
37887
  }
37481
37888
  function getMissingCoursePricingSelectionMessage(pricing) {
37482
37889
  if (pricing?.requiresSelection && !pricing.selectedOption) {
37890
+ if (pricing.slidingScale) {
37891
+ return "Choose an amount to continue.";
37892
+ }
37483
37893
  return "Choose a pricing option to continue.";
37484
37894
  }
37895
+ if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null && pricing.selectedSlidingAmount < pricing.slidingScale.minAmount) {
37896
+ return "Choose an amount within the sliding scale.";
37897
+ }
37898
+ if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null && pricing.selectedSlidingAmount > pricing.slidingScale.maxAmount) {
37899
+ return "Choose an amount within the sliding scale.";
37900
+ }
37485
37901
  return null;
37486
37902
  }
37487
37903
  function buildCoursePricingOptionPayload(pricing) {
37488
- return pricing?.selectedOption ? { pricingOptionId: pricing.selectedOption.id } : {};
37904
+ if (pricing?.selectedOption) {
37905
+ return { pricingOptionId: pricing.selectedOption.id };
37906
+ }
37907
+ if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null) {
37908
+ return { selectedSlidingAmount: pricing.selectedSlidingAmount };
37909
+ }
37910
+ return {};
37489
37911
  }
37490
37912
  function resolveHasCoursePayment(pricing) {
37491
37913
  if (!pricing) {
@@ -37526,6 +37948,7 @@ function useCourseRegistrationWizard(props2) {
37526
37948
  scopedCourses.length === 1 ? scopedCourses[0] ?? null : null
37527
37949
  );
37528
37950
  const [selectedPricingOptionId, setSelectedPricingOptionId] = useState9(null);
37951
+ const [selectedSlidingAmountInput, setSelectedSlidingAmountInput] = useState9("");
37529
37952
  const [formData, setFormData] = useState9({
37530
37953
  name: "",
37531
37954
  email: "",
@@ -37547,8 +37970,12 @@ function useCourseRegistrationWizard(props2) {
37547
37970
  const [bookingMode, setBookingMode] = useState9(null);
37548
37971
  const waitlistClaim = useWaitlistClaim();
37549
37972
  const selectedCoursePricing = useMemo9(
37550
- () => selectedCourse ? resolveCoursePricingState(selectedCourse, selectedPricingOptionId) : null,
37551
- [selectedCourse, selectedPricingOptionId]
37973
+ () => selectedCourse ? resolveCoursePricingState(
37974
+ selectedCourse,
37975
+ selectedPricingOptionId,
37976
+ parseCurrencyInputToCents2(selectedSlidingAmountInput)
37977
+ ) : null,
37978
+ [selectedCourse, selectedPricingOptionId, selectedSlidingAmountInput]
37552
37979
  );
37553
37980
  const missingPricingSelectionMessage = getMissingCoursePricingSelectionMessage(
37554
37981
  selectedCoursePricing
@@ -37621,9 +38048,13 @@ function useCourseRegistrationWizard(props2) {
37621
38048
  useEffect18(() => {
37622
38049
  if (!selectedCourse) {
37623
38050
  setSelectedPricingOptionId(null);
38051
+ setSelectedSlidingAmountInput("");
37624
38052
  return;
37625
38053
  }
37626
38054
  const defaultPricing = resolveCoursePricingState(selectedCourse, null);
38055
+ setSelectedSlidingAmountInput(
38056
+ defaultPricing.slidingScale?.suggestedAmount !== null && defaultPricing.slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput2(defaultPricing.slidingScale.suggestedAmount) : ""
38057
+ );
37627
38058
  setSelectedPricingOptionId((previous) => {
37628
38059
  if (previous && defaultPricing.selectableOptions.some((option) => option.id === previous)) {
37629
38060
  return previous;
@@ -37998,6 +38429,8 @@ function useCourseRegistrationWizard(props2) {
37998
38429
  selectedCourse,
37999
38430
  selectedPricingOptionId,
38000
38431
  setSelectedPricingOptionId,
38432
+ selectedSlidingAmountInput,
38433
+ setSelectedSlidingAmountInput,
38001
38434
  selectedCoursePricing,
38002
38435
  setSelectedCourse,
38003
38436
  formData,
@@ -38063,6 +38496,19 @@ var init_useCourseRegistrationWizard = __esm({
38063
38496
 
38064
38497
  // ../blocks/src/system/runtime/nodes/course-registration/CourseRegistrationWizard.tsx
38065
38498
  import { Fragment as Fragment23, jsx as jsx106, jsxs as jsxs76 } from "react/jsx-runtime";
38499
+ function getCourseSlidingScaleMessage(pricing) {
38500
+ if (!pricing.slidingScale) {
38501
+ return null;
38502
+ }
38503
+ const selectedAmount = pricing.selectedSlidingAmount;
38504
+ if (selectedAmount === null) {
38505
+ return "Choose an amount to continue.";
38506
+ }
38507
+ if (selectedAmount < pricing.slidingScale.minAmount || selectedAmount > pricing.slidingScale.maxAmount) {
38508
+ return "Choose an amount within the sliding scale.";
38509
+ }
38510
+ return null;
38511
+ }
38066
38512
  function CourseRegistrationWizard(props2) {
38067
38513
  const {
38068
38514
  showSessions = true,
@@ -38084,6 +38530,8 @@ function CourseRegistrationWizard(props2) {
38084
38530
  selectedCourse,
38085
38531
  selectedPricingOptionId,
38086
38532
  setSelectedPricingOptionId,
38533
+ selectedSlidingAmountInput,
38534
+ setSelectedSlidingAmountInput,
38087
38535
  selectedCoursePricing,
38088
38536
  formData,
38089
38537
  setFormData,
@@ -38158,7 +38606,8 @@ function CourseRegistrationWizard(props2) {
38158
38606
  const canShowDiscountUi = !discountsAvailableLoading && paymentChoice === "checkout" && discountsAvailable && manualCodeEntryAllowed;
38159
38607
  const courseSoldOut = waitlistClaim.claim === null && courseEligibility?.isFull === true && courseEligibility.canJoinWaitlist !== true;
38160
38608
  const detailsSubmitLabel = courseEligibility?.canJoinWaitlist ? "Join waitlist" : buttonText;
38161
- const pricingSelectionMissing = selectedCoursePricing?.requiresSelection === true && !selectedCoursePricing.selectedOption;
38609
+ const pricingSelectionMissing = selectedCoursePricing?.requiresSelection === true && !selectedCoursePricing.selectedOption && !selectedCoursePricing.slidingScale;
38610
+ const slidingScaleMessage = selectedCoursePricing ? getCourseSlidingScaleMessage(selectedCoursePricing) : null;
38162
38611
  const pricingUnavailable = selectedCoursePricing?.display.kind === "unavailable";
38163
38612
  const selectedCourseWithPricing = selectedCourse && selectedCoursePricing ? {
38164
38613
  course: selectedCourse,
@@ -38251,6 +38700,14 @@ function CourseRegistrationWizard(props2) {
38251
38700
  onSelect: setSelectedPricingOptionId
38252
38701
  }
38253
38702
  ),
38703
+ /* @__PURE__ */ jsx106(
38704
+ CourseSlidingScaleInput,
38705
+ {
38706
+ pricing: selectedCourseWithPricing.pricing,
38707
+ value: selectedSlidingAmountInput,
38708
+ onChange: setSelectedSlidingAmountInput
38709
+ }
38710
+ ),
38254
38711
  showSpamProtection && /* @__PURE__ */ jsx106("div", { className: "cr-altcha", children: /* @__PURE__ */ jsx106(
38255
38712
  AltchaWidget,
38256
38713
  {
@@ -38288,7 +38745,7 @@ function CourseRegistrationWizard(props2) {
38288
38745
  {
38289
38746
  type: "submit",
38290
38747
  className: buttonClass,
38291
- disabled: courseSoldOut || eligibilityLoading || pricingSelectionMissing || pricingUnavailable,
38748
+ disabled: courseSoldOut || eligibilityLoading || pricingSelectionMissing || slidingScaleMessage !== null || pricingUnavailable,
38292
38749
  children: eligibilityLoading ? "Checking availability\u2026" : courseSoldOut ? "Sold out" : detailsSubmitLabel
38293
38750
  }
38294
38751
  )
@@ -38298,6 +38755,7 @@ function CourseRegistrationWizard(props2) {
38298
38755
  ),
38299
38756
  courseSoldOut && /* @__PURE__ */ jsx106("p", { className: "cr-text cr-text--muted", children: "This course is fully booked and there is no waitlist available right now." }),
38300
38757
  pricingSelectionMissing && /* @__PURE__ */ jsx106("p", { className: "cr-text cr-text--muted", children: "Choose a pricing option to continue." }),
38758
+ slidingScaleMessage && /* @__PURE__ */ jsx106("p", { className: "cr-text cr-text--muted", children: slidingScaleMessage }),
38301
38759
  pricingUnavailable && /* @__PURE__ */ jsx106("p", { className: "cr-text cr-text--muted", children: "Pricing is not available for this course right now." }),
38302
38760
  eligibilityError && /* @__PURE__ */ jsx106("p", { className: "cr-text cr-text--error", children: eligibilityError })
38303
38761
  ] })
@@ -41897,12 +42355,13 @@ var init_carousel_client = __esm({
41897
42355
  ]
41898
42356
  );
41899
42357
  const resolvedSlides = resolveSlidesToShowMobile(normalized.slidesToShow);
42358
+ const canAutoplay = normalized.autoplay && slides.length > 1;
41900
42359
  const cssVars = React20.useMemo(
41901
42360
  () => getCarouselSlidesToShowCssVars(normalized.slidesToShow),
41902
42361
  [normalized.slidesToShow]
41903
42362
  );
41904
42363
  const plugins = React20.useMemo(() => {
41905
- if (!normalized.autoplay) return void 0;
42364
+ if (!canAutoplay) return void 0;
41906
42365
  return [
41907
42366
  Autoplay({
41908
42367
  delay: normalized.autoplayDelay,
@@ -41912,7 +42371,7 @@ var init_carousel_client = __esm({
41912
42371
  // Continue after manual navigation
41913
42372
  })
41914
42373
  ];
41915
- }, [normalized.autoplay, normalized.autoplayDelay]);
42374
+ }, [canAutoplay, normalized.autoplayDelay]);
41916
42375
  const [viewportRef, api] = useEmblaCarousel(
41917
42376
  {
41918
42377
  align: "start",
@@ -41951,7 +42410,7 @@ var init_carousel_client = __esm({
41951
42410
  };
41952
42411
  }, [api]);
41953
42412
  React20.useEffect(() => {
41954
- if (!api || !normalized.autoplay) return;
42413
+ if (!api || !canAutoplay) return;
41955
42414
  const autoplayPlugin = api.plugins()?.autoplay;
41956
42415
  if (!autoplayPlugin) return;
41957
42416
  const handleVisibility = () => {
@@ -41960,7 +42419,7 @@ var init_carousel_client = __esm({
41960
42419
  };
41961
42420
  document.addEventListener("visibilitychange", handleVisibility);
41962
42421
  return () => document.removeEventListener("visibilitychange", handleVisibility);
41963
- }, [api, normalized.autoplay]);
42422
+ }, [api, canAutoplay]);
41964
42423
  const inner = /* @__PURE__ */ jsxs81(Fragment25, { children: [
41965
42424
  /* @__PURE__ */ jsx113("div", { className: "carousel-frame rb-overflow-hidden rb-w-full", children: /* @__PURE__ */ jsx113(
41966
42425
  "div",
@@ -42011,7 +42470,7 @@ var init_carousel_client = __esm({
42011
42470
  "data-show-controls": normalized.showControls ? "true" : "false",
42012
42471
  "data-show-dots": normalized.showDots ? "true" : "false",
42013
42472
  "data-arrow-visibility": normalized.arrowVisibility,
42014
- "data-autoplay": normalized.autoplay ? "true" : "false",
42473
+ "data-autoplay": canAutoplay ? "true" : "false",
42015
42474
  "data-loop": normalized.loop ? "true" : "false",
42016
42475
  children: inner
42017
42476
  }