@flamingo-stack/openframe-frontend-core 0.0.594 → 0.0.595-snapshot.20260905173123

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/dist/{chunk-HQWZ4IXU.cjs → chunk-3CH6VRJX.cjs} +24 -24
  2. package/dist/{chunk-HQWZ4IXU.cjs.map → chunk-3CH6VRJX.cjs.map} +1 -1
  3. package/dist/{chunk-LKN2KKYZ.js → chunk-4K7TCJ35.js} +6 -59
  4. package/dist/{chunk-LKN2KKYZ.js.map → chunk-4K7TCJ35.js.map} +1 -1
  5. package/dist/{chunk-YLVPQNLO.cjs → chunk-5MSHWXJ5.cjs} +170 -223
  6. package/dist/chunk-5MSHWXJ5.cjs.map +1 -0
  7. package/dist/{chunk-CCLPJSY3.cjs → chunk-73BECFSU.cjs} +15 -15
  8. package/dist/{chunk-CCLPJSY3.cjs.map → chunk-73BECFSU.cjs.map} +1 -1
  9. package/dist/{chunk-F5Q3DTP5.js → chunk-7EUE3YTC.js} +8 -8
  10. package/dist/{chunk-GBIC3VNA.js → chunk-7KGN7DV6.js} +6 -6
  11. package/dist/{chunk-YZLUOZKR.js → chunk-7Q66A4CF.js} +2 -2
  12. package/dist/{chunk-DRZ224RU.js → chunk-ANSZVKI2.js} +8 -8
  13. package/dist/{chunk-N3RHX26N.js → chunk-AZZVSEP5.js} +3 -3
  14. package/dist/{chunk-66I2QUFE.cjs → chunk-B26UT36N.cjs} +6 -6
  15. package/dist/{chunk-66I2QUFE.cjs.map → chunk-B26UT36N.cjs.map} +1 -1
  16. package/dist/{chunk-UBRVIVY4.cjs → chunk-B2CSYMKW.cjs} +298 -285
  17. package/dist/chunk-B2CSYMKW.cjs.map +1 -0
  18. package/dist/{chunk-ZK3AZ5YF.cjs → chunk-BTOL222V.cjs} +11 -11
  19. package/dist/{chunk-ZK3AZ5YF.cjs.map → chunk-BTOL222V.cjs.map} +1 -1
  20. package/dist/{chunk-S7VW4HVL.cjs → chunk-DODE3PD4.cjs} +49 -49
  21. package/dist/{chunk-S7VW4HVL.cjs.map → chunk-DODE3PD4.cjs.map} +1 -1
  22. package/dist/{chunk-ZZHHKE2Q.js → chunk-ECXQX4EP.js} +2 -2
  23. package/dist/{chunk-NEFNARFF.cjs → chunk-EEV7SSBJ.cjs} +30 -30
  24. package/dist/{chunk-NEFNARFF.cjs.map → chunk-EEV7SSBJ.cjs.map} +1 -1
  25. package/dist/{chunk-3OQIZPUX.js → chunk-EO3NEGWB.js} +4 -4
  26. package/dist/{chunk-MOHSA65M.js → chunk-EZM5DNII.js} +2 -2
  27. package/dist/{chunk-IKQVXZB5.js → chunk-GSPS6Y5U.js} +6 -6
  28. package/dist/{chunk-CQ35OMPJ.cjs → chunk-I2BNLWC3.cjs} +3 -3
  29. package/dist/{chunk-CQ35OMPJ.cjs.map → chunk-I2BNLWC3.cjs.map} +1 -1
  30. package/dist/{chunk-HOLK4ZMT.js → chunk-II2GBWNW.js} +4 -4
  31. package/dist/{chunk-PETYVGEQ.cjs → chunk-JKGVXLTT.cjs} +5 -5
  32. package/dist/{chunk-PETYVGEQ.cjs.map → chunk-JKGVXLTT.cjs.map} +1 -1
  33. package/dist/{chunk-5EM6NGBK.cjs → chunk-KOQCA5X5.cjs} +17 -27
  34. package/dist/chunk-KOQCA5X5.cjs.map +1 -0
  35. package/dist/{chunk-ACU7J5BL.cjs → chunk-KPE7OQF6.cjs} +84 -84
  36. package/dist/{chunk-ACU7J5BL.cjs.map → chunk-KPE7OQF6.cjs.map} +1 -1
  37. package/dist/{chunk-C4YJC5X7.cjs → chunk-KRKW63LG.cjs} +9 -9
  38. package/dist/{chunk-C4YJC5X7.cjs.map → chunk-KRKW63LG.cjs.map} +1 -1
  39. package/dist/{chunk-ZEG3ZJPY.cjs → chunk-LE5SZPMN.cjs} +33 -33
  40. package/dist/{chunk-ZEG3ZJPY.cjs.map → chunk-LE5SZPMN.cjs.map} +1 -1
  41. package/dist/{chunk-A5AKGC4S.js → chunk-LPMDCQLL.js} +17 -27
  42. package/dist/chunk-LPMDCQLL.js.map +1 -0
  43. package/dist/{chunk-EWOFXJGH.cjs → chunk-M3OQLL7D.cjs} +63 -63
  44. package/dist/{chunk-EWOFXJGH.cjs.map → chunk-M3OQLL7D.cjs.map} +1 -1
  45. package/dist/{chunk-FKXDDJEQ.cjs → chunk-M4YQUHOR.cjs} +5 -5
  46. package/dist/{chunk-FKXDDJEQ.cjs.map → chunk-M4YQUHOR.cjs.map} +1 -1
  47. package/dist/{chunk-5XQMEDGE.cjs → chunk-OHJ4QOWN.cjs} +12 -12
  48. package/dist/{chunk-5XQMEDGE.cjs.map → chunk-OHJ4QOWN.cjs.map} +1 -1
  49. package/dist/{chunk-Y6I2DGKC.cjs → chunk-OMKI5T2G.cjs} +1 -1
  50. package/dist/chunk-OMKI5T2G.cjs.map +1 -0
  51. package/dist/{chunk-M5HGULIY.js → chunk-OQODJ26H.js} +5 -5
  52. package/dist/{chunk-MEWAFY6X.js → chunk-OT5IQMSI.js} +4 -4
  53. package/dist/{chunk-Y22VQDVW.js → chunk-QB244ZDI.js} +4 -4
  54. package/dist/{chunk-3T7ZP3TL.js → chunk-QL6ECU6Y.js} +3 -3
  55. package/dist/{chunk-3XDPXOMS.js → chunk-R2SZYRB2.js} +7 -7
  56. package/dist/{chunk-QAVT6P5F.cjs → chunk-RFA5T5MW.cjs} +28 -28
  57. package/dist/{chunk-QAVT6P5F.cjs.map → chunk-RFA5T5MW.cjs.map} +1 -1
  58. package/dist/{chunk-BTF3CNDP.js → chunk-ROQO355A.js} +1 -1
  59. package/dist/chunk-ROQO355A.js.map +1 -0
  60. package/dist/{chunk-43ADGEWL.cjs → chunk-UJAMXLA3.cjs} +40 -40
  61. package/dist/{chunk-43ADGEWL.cjs.map → chunk-UJAMXLA3.cjs.map} +1 -1
  62. package/dist/{chunk-KVNA3HU2.js → chunk-XANQTIHS.js} +3 -3
  63. package/dist/{chunk-PMN7WDXI.js → chunk-YUHOKPKS.js} +26 -13
  64. package/dist/chunk-YUHOKPKS.js.map +1 -0
  65. package/dist/components/case-studies/index.cjs +16 -16
  66. package/dist/components/case-studies/index.js +6 -6
  67. package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
  68. package/dist/components/chat/index.cjs +4 -4
  69. package/dist/components/chat/index.js +3 -3
  70. package/dist/components/contact/index.cjs +7 -7
  71. package/dist/components/contact/index.js +6 -6
  72. package/dist/components/docs/index.cjs +10 -10
  73. package/dist/components/docs/index.js +9 -9
  74. package/dist/components/embeds/index.cjs +7 -7
  75. package/dist/components/embeds/index.js +6 -6
  76. package/dist/components/faq/index.cjs +7 -7
  77. package/dist/components/faq/index.js +6 -6
  78. package/dist/components/features/index.cjs +6 -6
  79. package/dist/components/features/index.js +5 -5
  80. package/dist/components/help-center-pages/index.cjs +26 -26
  81. package/dist/components/help-center-pages/index.js +17 -17
  82. package/dist/components/icons/index.cjs +2 -2
  83. package/dist/components/icons/index.js +1 -1
  84. package/dist/components/icons/mlg-logo.d.ts.map +1 -1
  85. package/dist/components/index.cjs +56 -56
  86. package/dist/components/index.js +17 -17
  87. package/dist/components/meeting-scheduler/booking-form.d.ts +70 -6
  88. package/dist/components/meeting-scheduler/booking-form.d.ts.map +1 -1
  89. package/dist/components/meeting-scheduler/context-panel.d.ts +9 -1
  90. package/dist/components/meeting-scheduler/context-panel.d.ts.map +1 -1
  91. package/dist/components/meeting-scheduler/index.cjs +395 -188
  92. package/dist/components/meeting-scheduler/index.cjs.map +1 -1
  93. package/dist/components/meeting-scheduler/index.d.ts +55 -1
  94. package/dist/components/meeting-scheduler/index.d.ts.map +1 -1
  95. package/dist/components/meeting-scheduler/index.js +381 -174
  96. package/dist/components/meeting-scheduler/index.js.map +1 -1
  97. package/dist/components/meeting-scheduler/slot-picker.d.ts +8 -1
  98. package/dist/components/meeting-scheduler/slot-picker.d.ts.map +1 -1
  99. package/dist/components/navigation/index.cjs +9 -9
  100. package/dist/components/navigation/index.js +8 -8
  101. package/dist/components/onboarding-guides/index.cjs +9 -9
  102. package/dist/components/onboarding-guides/index.js +8 -8
  103. package/dist/components/related-content/index.cjs +3 -3
  104. package/dist/components/related-content/index.js +2 -2
  105. package/dist/components/tickets/index.cjs +10 -10
  106. package/dist/components/tickets/index.js +9 -9
  107. package/dist/components/ui/benefit-card.d.ts.map +1 -1
  108. package/dist/components/ui/index.cjs +6 -6
  109. package/dist/components/ui/index.js +5 -5
  110. package/dist/hooks/index.cjs +3 -3
  111. package/dist/hooks/index.js +2 -2
  112. package/dist/index.cjs +10 -10
  113. package/dist/index.js +9 -9
  114. package/dist/schemas/meeting-booking-schema.cjs +19 -4
  115. package/dist/schemas/meeting-booking-schema.cjs.map +1 -1
  116. package/dist/schemas/meeting-booking-schema.d.ts +41 -16
  117. package/dist/schemas/meeting-booking-schema.d.ts.map +1 -1
  118. package/dist/schemas/meeting-booking-schema.js +19 -5
  119. package/dist/schemas/meeting-booking-schema.js.map +1 -1
  120. package/dist/types/index.cjs.map +1 -1
  121. package/dist/types/index.js.map +1 -1
  122. package/dist/utils/index.cjs +18 -40
  123. package/dist/utils/index.cjs.map +1 -1
  124. package/dist/utils/index.js +18 -40
  125. package/dist/utils/index.js.map +1 -1
  126. package/dist/utils/source-icons.d.ts.map +1 -1
  127. package/package.json +1 -1
  128. package/src/components/chat/entity-cards/dispatch.tsx +0 -57
  129. package/src/components/icons/mlg-logo.tsx +1 -7
  130. package/src/components/meeting-scheduler/booking-form.tsx +425 -154
  131. package/src/components/meeting-scheduler/context-panel.tsx +13 -3
  132. package/src/components/meeting-scheduler/index.tsx +317 -69
  133. package/src/components/meeting-scheduler/slot-picker.tsx +17 -1
  134. package/src/components/ui/benefit-card.tsx +30 -9
  135. package/src/schemas/meeting-booking-schema.ts +58 -4
  136. package/src/types/tmcg.ts +0 -2
  137. package/src/utils/format.ts +1 -1
  138. package/src/utils/source-icons.ts +0 -24
  139. package/dist/chunk-5EM6NGBK.cjs.map +0 -1
  140. package/dist/chunk-A5AKGC4S.js.map +0 -1
  141. package/dist/chunk-BTF3CNDP.js.map +0 -1
  142. package/dist/chunk-PMN7WDXI.js.map +0 -1
  143. package/dist/chunk-UBRVIVY4.cjs.map +0 -1
  144. package/dist/chunk-Y6I2DGKC.cjs.map +0 -1
  145. package/dist/chunk-YLVPQNLO.cjs.map +0 -1
  146. /package/dist/{chunk-F5Q3DTP5.js.map → chunk-7EUE3YTC.js.map} +0 -0
  147. /package/dist/{chunk-GBIC3VNA.js.map → chunk-7KGN7DV6.js.map} +0 -0
  148. /package/dist/{chunk-YZLUOZKR.js.map → chunk-7Q66A4CF.js.map} +0 -0
  149. /package/dist/{chunk-DRZ224RU.js.map → chunk-ANSZVKI2.js.map} +0 -0
  150. /package/dist/{chunk-N3RHX26N.js.map → chunk-AZZVSEP5.js.map} +0 -0
  151. /package/dist/{chunk-ZZHHKE2Q.js.map → chunk-ECXQX4EP.js.map} +0 -0
  152. /package/dist/{chunk-3OQIZPUX.js.map → chunk-EO3NEGWB.js.map} +0 -0
  153. /package/dist/{chunk-MOHSA65M.js.map → chunk-EZM5DNII.js.map} +0 -0
  154. /package/dist/{chunk-IKQVXZB5.js.map → chunk-GSPS6Y5U.js.map} +0 -0
  155. /package/dist/{chunk-HOLK4ZMT.js.map → chunk-II2GBWNW.js.map} +0 -0
  156. /package/dist/{chunk-M5HGULIY.js.map → chunk-OQODJ26H.js.map} +0 -0
  157. /package/dist/{chunk-MEWAFY6X.js.map → chunk-OT5IQMSI.js.map} +0 -0
  158. /package/dist/{chunk-Y22VQDVW.js.map → chunk-QB244ZDI.js.map} +0 -0
  159. /package/dist/{chunk-3T7ZP3TL.js.map → chunk-QL6ECU6Y.js.map} +0 -0
  160. /package/dist/{chunk-3XDPXOMS.js.map → chunk-R2SZYRB2.js.map} +0 -0
  161. /package/dist/{chunk-KVNA3HU2.js.map → chunk-XANQTIHS.js.map} +0 -0
@@ -22,13 +22,14 @@ var _chunkO4VZOA2Qcjs = require('../../chunk-O4VZOA2Q.cjs');
22
22
 
23
23
 
24
24
 
25
- var _chunkUBRVIVY4cjs = require('../../chunk-UBRVIVY4.cjs');
25
+
26
+ var _chunkB2CSYMKWcjs = require('../../chunk-B2CSYMKW.cjs');
26
27
  require('../../chunk-GQWM3ECA.cjs');
27
28
  require('../../chunk-TON3YCCW.cjs');
28
29
 
29
30
 
30
31
 
31
- var _chunkFKXDDJEQcjs = require('../../chunk-FKXDDJEQ.cjs');
32
+ var _chunkM4YQUHORcjs = require('../../chunk-M4YQUHOR.cjs');
32
33
  require('../../chunk-D55IENZJ.cjs');
33
34
  require('../../chunk-N6CULJYR.cjs');
34
35
 
@@ -42,10 +43,10 @@ var _chunkH64ZHSYRcjs = require('../../chunk-H64ZHSYR.cjs');
42
43
  var _chunkY7ITKISQcjs = require('../../chunk-Y7ITKISQ.cjs');
43
44
 
44
45
 
45
- var _chunkYLVPQNLOcjs = require('../../chunk-YLVPQNLO.cjs');
46
+ var _chunk5MSHWXJ5cjs = require('../../chunk-5MSHWXJ5.cjs');
46
47
  require('../../chunk-YXWGSDK4.cjs');
47
48
  require('../../chunk-SADRZ4YI.cjs');
48
- require('../../chunk-5EM6NGBK.cjs');
49
+ require('../../chunk-KOQCA5X5.cjs');
49
50
  require('../../chunk-GSQM4PDR.cjs');
50
51
  require('../../chunk-XQFFGR6U.cjs');
51
52
 
@@ -53,7 +54,7 @@ require('../../chunk-XQFFGR6U.cjs');
53
54
 
54
55
 
55
56
 
56
- var _chunkY6I2DGKCcjs = require('../../chunk-Y6I2DGKC.cjs');
57
+ var _chunkOMKI5T2Gcjs = require('../../chunk-OMKI5T2G.cjs');
57
58
  require('../../chunk-WLSFBRT5.cjs');
58
59
  require('../../chunk-YH6IQTPI.cjs');
59
60
  require('../../chunk-63QUMV72.cjs');
@@ -113,7 +114,7 @@ function isValidBcp47Locale(locale) {
113
114
  return false;
114
115
  }
115
116
  }
116
- function makeBookingSchema(formFields, legalConsent) {
117
+ function buildBookingSchema(formFields, legalConsent, slot) {
117
118
  const answers = {};
118
119
  for (const field of formFields) {
119
120
  if (!isSupportedFormField(field)) continue;
@@ -150,12 +151,12 @@ function makeBookingSchema(formFields, legalConsent) {
150
151
  const answersObject = _zod.z.object(answers);
151
152
  return _zod.z.object({
152
153
  meetingId: _zod.z.string().min(1),
153
- startTimeMs: _zod.z.number().int().positive(),
154
- durationMs: _zod.z.number().int().positive(),
154
+ startTimeMs: slot.startTimeMs,
155
+ durationMs: slot.durationMs,
155
156
  firstName: _zod.z.string().min(1, { message: "First name is required" }).max(255),
156
157
  lastName: _zod.z.string().min(1, { message: "Last name is required" }).max(255),
157
158
  email: _zod.z.string().email({ message: "Please enter a valid email address" }).max(255),
158
- timezone: _zod.z.string().refine(isValidIanaTimezone, { message: "Invalid timezone" }),
159
+ timezone: slot.timezone,
159
160
  locale: _zod.z.string().refine(isValidBcp47Locale, { message: "Invalid locale" }).optional(),
160
161
  // Plain `.optional()` (no `.default()`) so zod's input and output types
161
162
  // match — react-hook-form's zodResolver needs them identical, and the
@@ -177,6 +178,13 @@ function makeBookingSchema(formFields, legalConsent) {
177
178
  }
178
179
  });
179
180
  }
181
+ function makeDeferredBookingSchema(formFields, legalConsent) {
182
+ return buildBookingSchema(formFields, legalConsent, {
183
+ startTimeMs: _zod.z.number().int().positive().nullish(),
184
+ durationMs: _zod.z.number().int().positive().nullish(),
185
+ timezone: _zod.z.string().refine(isValidIanaTimezone, { message: "Invalid timezone" }).nullish()
186
+ });
187
+ }
180
188
 
181
189
  // src/hooks/use-meeting-booking.ts
182
190
  var AVAILABILITY_STALE_MS = 0;
@@ -189,7 +197,7 @@ function useMeetingBooking(options) {
189
197
  const seededOffset = _optionalChain([initialAvailability, 'optionalAccess', _3 => _3.meetingId]) === meetingId ? initialAvailability.monthOffset : void 0;
190
198
  const [monthOffset, setMonthOffsetState] = _react.useState.call(void 0, _nullishCoalesce(seededOffset, () => ( 0)));
191
199
  const setMonthOffset = _react.useCallback.call(void 0, (offset) => {
192
- setMonthOffsetState(Math.max(0, Math.min(_chunkUBRVIVY4cjs.MAX_MONTH_OFFSET, offset)));
200
+ setMonthOffsetState(Math.max(0, Math.min(_chunkB2CSYMKWcjs.MAX_MONTH_OFFSET, offset)));
193
201
  }, []);
194
202
  const prevMeetingIdRef = _react.useRef.call(void 0, meetingId);
195
203
  _react.useLayoutEffect.call(void 0, () => {
@@ -271,12 +279,25 @@ var _zod3 = require('@hookform/resolvers/zod');
271
279
 
272
280
  var _reacthookform = require('react-hook-form');
273
281
  var _jsxruntime = require('react/jsx-runtime');
282
+ var SPAN_CLASS = {
283
+ 1: "md:col-span-1",
284
+ 2: "md:col-span-2",
285
+ 3: "md:col-span-3",
286
+ 4: "md:col-span-4"
287
+ };
288
+ var evenSpan = (count) => Math.min(4, Math.max(1, Math.floor(4 / Math.max(1, count))));
274
289
  function BookingForm({
275
290
  availability,
276
291
  meetingId,
277
292
  startTimeMs,
278
293
  durationMs,
279
294
  timezone,
295
+ deferSlot = false,
296
+ initialValues,
297
+ submitLabel,
298
+ footerNote,
299
+ fieldRows,
300
+ consent,
280
301
  isSubmitting,
281
302
  onSubmit,
282
303
  honeypotInputProps,
@@ -284,42 +305,75 @@ function BookingForm({
284
305
  }) {
285
306
  const { formFields, legalConsent } = availability;
286
307
  const supportedFields = _react.useMemo.call(void 0, () => formFields.filter(isSupportedFormField), [formFields]);
287
- const schema = _react.useMemo.call(void 0, () => makeBookingSchema(supportedFields, legalConsent), [supportedFields, legalConsent]);
308
+ const schema = _react.useMemo.call(void 0,
309
+ () => makeDeferredBookingSchema(supportedFields, legalConsent),
310
+ [supportedFields, legalConsent]
311
+ );
312
+ const consentDefaults = _react.useMemo.call(void 0,
313
+ () => (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _5 => _5.communicationConsentCheckboxes]), () => ( []))).map((c) => ({
314
+ communicationTypeId: c.communicationTypeId,
315
+ consented: false
316
+ })),
317
+ [legalConsent]
318
+ );
288
319
  const {
289
320
  register,
290
321
  control,
291
322
  handleSubmit,
323
+ setValue,
292
324
  formState: { errors }
293
325
  } = _reacthookform.useForm.call(void 0, {
294
326
  resolver: _zod3.zodResolver.call(void 0, schema),
295
327
  defaultValues: {
296
328
  meetingId,
297
- startTimeMs,
298
- durationMs,
329
+ // Genuinely OMITTED, not present-as-undefined, when the slot is deferred.
330
+ ...deferSlot ? {} : { startTimeMs, durationMs },
299
331
  timezone,
300
332
  locale: typeof navigator !== "undefined" ? navigator.language : void 0,
301
333
  firstName: "",
302
334
  lastName: "",
303
335
  email: "",
304
336
  formFields: {},
305
- legalConsentResponses: (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _5 => _5.communicationConsentCheckboxes]), () => ( []))).map((c) => ({
306
- communicationTypeId: c.communicationTypeId,
307
- consented: false
308
- }))
337
+ legalConsentResponses: consentDefaults,
338
+ // A remount (back edge, or an error return) would otherwise lose every
339
+ // answer — `defaultValues` is snapshotted once and never re-read.
340
+ ..._nullishCoalesce(initialValues, () => ( {}))
309
341
  }
310
342
  });
311
- const submit = handleSubmit(async (data) => {
312
- await onSubmit({ ...data, meetingId, startTimeMs, durationMs, timezone, ...getSignals() });
343
+ const priorConsents = _optionalChain([initialValues, 'optionalAccess', _6 => _6.legalConsentResponses]);
344
+ const [consented, setConsented] = _react.useState.call(void 0, _optionalChain([initialValues, 'optionalAccess', _7 => _7.hostConsent]) === true);
345
+ const [consentError, setConsentError] = _react.useState.call(void 0, null);
346
+ const consentMissing = Boolean(consent) && !consented;
347
+ _react.useEffect.call(void 0, () => {
348
+ setValue(
349
+ "legalConsentResponses",
350
+ consentDefaults.map((next) => ({
351
+ ...next,
352
+ consented: _nullishCoalesce(_optionalChain([priorConsents, 'optionalAccess', _8 => _8.find, 'call', _9 => _9((r) => r.communicationTypeId === next.communicationTypeId), 'optionalAccess', _10 => _10.consented]), () => ( false))
353
+ })),
354
+ { shouldDirty: false }
355
+ );
356
+ }, [consentDefaults, priorConsents, setValue]);
357
+ const submitValid = handleSubmit(async (data) => {
358
+ if (consentMissing) return;
359
+ if (deferSlot) {
360
+ await onSubmit({ ...data, meetingId, hostConsent: consented });
361
+ return;
362
+ }
363
+ await onSubmit({ ...data, meetingId, hostConsent: consented, startTimeMs, durationMs, timezone, ...getSignals() });
313
364
  });
365
+ const submit = (event) => {
366
+ if (consentMissing) setConsentError(_nullishCoalesce(_optionalChain([consent, 'optionalAccess', _11 => _11.errorMessage]), () => ( "Please agree to continue.")));
367
+ return submitValid(event);
368
+ };
314
369
  const fieldError = (name) => {
315
- const err = _optionalChain([errors, 'access', _6 => _6.formFields, 'optionalAccess', _7 => _7[name]]);
316
- return _optionalChain([err, 'optionalAccess', _8 => _8.message]);
370
+ const err = _optionalChain([errors, 'access', _12 => _12.formFields, 'optionalAccess', _13 => _13[name]]);
371
+ return _optionalChain([err, 'optionalAccess', _14 => _14.message]);
317
372
  };
318
373
  const inputClass = "bg-ods-card border-ods-border text-ods-text-primary placeholder-ods-text-secondary px-3 h-11 md:h-12";
319
374
  const FORM_STACK = "flex flex-col gap-[var(--spacing-system-l)]";
320
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: submit, className: FORM_STACK, noValidate: true, children: [
321
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.HoneypotField, { ...honeypotInputProps }),
322
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: "Email", htmlFor: "ms-email", error: _optionalChain([errors, 'access', _9 => _9.email, 'optionalAccess', _10 => _10.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
375
+ const builtInFields = {
376
+ email: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: "Email", htmlFor: "ms-email", error: _optionalChain([errors, 'access', _15 => _15.email, 'optionalAccess', _16 => _16.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
323
377
  _chunkY7ITKISQcjs.Input,
324
378
  {
325
379
  id: "ms-email",
@@ -332,129 +386,210 @@ function BookingForm({
332
386
  ...register("email")
333
387
  }
334
388
  ) }),
335
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-2 gap-[var(--spacing-system-m)]", children: [
336
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: "First Name", htmlFor: "ms-first-name", error: _optionalChain([errors, 'access', _11 => _11.firstName, 'optionalAccess', _12 => _12.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
337
- _chunkY7ITKISQcjs.Input,
338
- {
339
- id: "ms-first-name",
340
- required: true,
341
- autoComplete: "given-name",
342
- placeholder: "Jane",
343
- "aria-invalid": !!errors.firstName,
344
- className: inputClass,
345
- ...register("firstName")
346
- }
347
- ) }),
348
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: "Last Name", htmlFor: "ms-last-name", error: _optionalChain([errors, 'access', _13 => _13.lastName, 'optionalAccess', _14 => _14.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
349
- _chunkY7ITKISQcjs.Input,
350
- {
351
- id: "ms-last-name",
352
- required: true,
353
- autoComplete: "family-name",
354
- placeholder: "Doe",
355
- "aria-invalid": !!errors.lastName,
356
- className: inputClass,
357
- ...register("lastName")
358
- }
359
- ) })
360
- ] }),
361
- supportedFields.map((field) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
362
- _chunkY7ITKISQcjs.FieldWrapper,
389
+ firstName: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: "First Name", htmlFor: "ms-first-name", error: _optionalChain([errors, 'access', _17 => _17.firstName, 'optionalAccess', _18 => _18.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
390
+ _chunkY7ITKISQcjs.Input,
363
391
  {
364
- label: field.label,
365
- htmlFor: `ms-q-${field.name}`,
366
- error: fieldError(field.name),
367
- children: [
368
- field.type === "textarea" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
369
- _chunkUBRVIVY4cjs.Textarea,
370
- {
371
- id: `ms-q-${field.name}`,
372
- className: "border-ods-border bg-ods-card px-3 text-ods-text-primary placeholder-ods-text-secondary",
373
- ...register(`formFields.${field.name}`)
374
- }
375
- ),
376
- field.type === "text" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
377
- _chunkY7ITKISQcjs.Input,
392
+ id: "ms-first-name",
393
+ required: true,
394
+ autoComplete: "given-name",
395
+ placeholder: "Jane",
396
+ "aria-invalid": !!errors.firstName,
397
+ className: inputClass,
398
+ ...register("firstName")
399
+ }
400
+ ) }),
401
+ lastName: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: "Last Name", htmlFor: "ms-last-name", error: _optionalChain([errors, 'access', _19 => _19.lastName, 'optionalAccess', _20 => _20.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
402
+ _chunkY7ITKISQcjs.Input,
403
+ {
404
+ id: "ms-last-name",
405
+ required: true,
406
+ autoComplete: "family-name",
407
+ placeholder: "Doe",
408
+ "aria-invalid": !!errors.lastName,
409
+ className: inputClass,
410
+ ...register("lastName")
411
+ }
412
+ ) })
413
+ };
414
+ const renderDeclaredField = (field) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: field.label, htmlFor: `ms-q-${field.name}`, error: fieldError(field.name), children: [
415
+ field.type === "textarea" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
416
+ _chunkB2CSYMKWcjs.Textarea,
417
+ {
418
+ id: `ms-q-${field.name}`,
419
+ className: "border-ods-border bg-ods-card px-3 text-ods-text-primary placeholder-ods-text-secondary",
420
+ ...register(`formFields.${field.name}`)
421
+ }
422
+ ),
423
+ field.type === "text" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
424
+ _chunkY7ITKISQcjs.Input,
425
+ {
426
+ id: `ms-q-${field.name}`,
427
+ className: "h-11 border-ods-border bg-ods-card px-3 text-ods-text-primary placeholder-ods-text-secondary md:h-12",
428
+ ...register(`formFields.${field.name}`)
429
+ }
430
+ ),
431
+ (field.type === "select" || field.type === "radio") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
432
+ _reacthookform.Controller,
433
+ {
434
+ control,
435
+ name: `formFields.${field.name}`,
436
+ render: ({ field: rhf }) => field.type === "select" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkB2CSYMKWcjs.Select, { value: _nullishCoalesce(rhf.value, () => ( "")), onValueChange: rhf.onChange, children: [
437
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.SelectTrigger, { id: `ms-q-${field.name}`, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.SelectValue, { placeholder: "Select\u2026" }) }),
438
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.SelectContent, { children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.SelectItem, { value: opt, children: opt }, opt)) })
439
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.RadioGroup, { value: _nullishCoalesce(rhf.value, () => ( "")), onValueChange: rhf.onChange, children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
440
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.RadioGroupItem, { id: `ms-q-${field.name}-${opt}`, value: opt }),
441
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Label, { htmlFor: `ms-q-${field.name}-${opt}`, children: opt })
442
+ ] }, opt)) })
443
+ }
444
+ ),
445
+ field.type === "checkbox" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
446
+ _reacthookform.Controller,
447
+ {
448
+ control,
449
+ name: `formFields.${field.name}`,
450
+ render: ({ field: rhf }) => (
451
+ // The question's Label above already carries the text and
452
+ // binds to this id — a second inline label would double the
453
+ // visible text AND the accessible name.
454
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
455
+ _chunkY7ITKISQcjs.Checkbox,
378
456
  {
379
457
  id: `ms-q-${field.name}`,
380
- className: "h-11 border-ods-border bg-ods-card px-3 text-ods-text-primary placeholder-ods-text-secondary md:h-12",
381
- ...register(`formFields.${field.name}`)
458
+ checked: Boolean(rhf.value),
459
+ onCheckedChange: (v) => rhf.onChange(v === true)
382
460
  }
383
- ),
384
- (field.type === "select" || field.type === "radio") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
385
- _reacthookform.Controller,
386
- {
387
- control,
388
- name: `formFields.${field.name}`,
389
- render: ({ field: rhf }) => field.type === "select" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkUBRVIVY4cjs.Select, { value: _nullishCoalesce(rhf.value, () => ( "")), onValueChange: rhf.onChange, children: [
390
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.SelectTrigger, { id: `ms-q-${field.name}`, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.SelectValue, { placeholder: "Select\u2026" }) }),
391
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.SelectContent, { children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.SelectItem, { value: opt, children: opt }, opt)) })
392
- ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.RadioGroup, { value: _nullishCoalesce(rhf.value, () => ( "")), onValueChange: rhf.onChange, children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
393
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.RadioGroupItem, { id: `ms-q-${field.name}-${opt}`, value: opt }),
394
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Label, { htmlFor: `ms-q-${field.name}-${opt}`, children: opt })
395
- ] }, opt)) })
396
- }
397
- ),
398
- field.type === "checkbox" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
399
- _reacthookform.Controller,
461
+ ) })
462
+ )
463
+ }
464
+ )
465
+ ] }, field.name);
466
+ const declaredByName = new Map(supportedFields.map((f) => [f.name, f]));
467
+ const slotResolves = (name) => Boolean(builtInFields[name] || declaredByName.has(name));
468
+ const slotNode = (name) => {
469
+ const builtIn = builtInFields[name];
470
+ if (builtIn) return builtIn;
471
+ const declared = declaredByName.get(name);
472
+ return declared ? renderDeclaredField(declared) : null;
473
+ };
474
+ const unplacedFields = fieldRows ? supportedFields.filter((f) => !fieldRows.some((row) => row.some((slot) => slot.name === f.name))) : [];
475
+ const placedRows = (_nullishCoalesce(fieldRows, () => ( []))).map((row) => row.filter((slot) => slotResolves(slot.name))).filter((row) => row.length > 0);
476
+ const submitButton = /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
477
+ _chunkCJBSU3XBcjs.Button,
478
+ {
479
+ type: "submit",
480
+ loading: isSubmitting,
481
+ disabled: isSubmitting,
482
+ className: footerNote ? "md:w-60" : void 0,
483
+ children: _nullishCoalesce(submitLabel, () => ( "Confirm Booking"))
484
+ }
485
+ );
486
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: submit, className: FORM_STACK, noValidate: true, children: [
487
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.HoneypotField, { ...honeypotInputProps }),
488
+ fieldRows ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
489
+ placedRows.map((row, rowIndex) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
490
+ "div",
491
+ {
492
+ className: "grid grid-cols-2 gap-[var(--spacing-system-m)] md:grid-cols-4",
493
+ children: row.map((slot) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
494
+ "div",
400
495
  {
401
- control,
402
- name: `formFields.${field.name}`,
403
- render: ({ field: rhf }) => (
404
- // The question's Label above already carries the text and
405
- // binds to this id — a second inline label would double the
406
- // visible text AND the accessible name.
407
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
408
- _chunkY7ITKISQcjs.Checkbox,
409
- {
410
- id: `ms-q-${field.name}`,
411
- checked: Boolean(rhf.value),
412
- onCheckedChange: (v) => rhf.onChange(v === true)
413
- }
414
- ) })
415
- )
416
- }
417
- )
418
- ]
419
- },
420
- field.name
421
- )),
496
+ className: _chunk23V5BSHDcjs.cn.call(void 0,
497
+ // A two-field row stays side by side on a phone — the rule
498
+ // the built-in name pair has always followed: two short
499
+ // fields cost one line instead of two on the layout that can
500
+ // least afford them.
501
+ row.length === 2 ? "col-span-1" : "col-span-2",
502
+ SPAN_CLASS[_nullishCoalesce(slot.span, () => ( evenSpan(row.length)))]
503
+ ),
504
+ children: slotNode(slot.name)
505
+ },
506
+ slot.name
507
+ ))
508
+ },
509
+ row.map((s) => s.name).join("|") || rowIndex
510
+ )),
511
+ unplacedFields.map((field) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _react.Fragment, { children: renderDeclaredField(field) }, field.name))
512
+ ] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
513
+ builtInFields.email,
514
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-2 gap-[var(--spacing-system-m)]", children: [
515
+ builtInFields.firstName,
516
+ builtInFields.lastName
517
+ ] }),
518
+ supportedFields.map((field) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _react.Fragment, { children: renderDeclaredField(field) }, field.name))
519
+ ] }),
520
+ consent && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
521
+ _chunkB2CSYMKWcjs.CheckboxBlock,
522
+ {
523
+ id: "ms-host-consent",
524
+ checked: consented,
525
+ onCheckedChange: (v) => {
526
+ setConsented(v);
527
+ if (v) setConsentError(null);
528
+ },
529
+ disabled: isSubmitting,
530
+ error: _nullishCoalesce(consentError, () => ( void 0)),
531
+ label: consent.label,
532
+ description: consent.description
533
+ }
534
+ ),
422
535
  legalConsent && // Same out-of-flow message as the fields above, so a missed consent
423
536
  // box doesn't shove the submit button down the card. With no error the
424
537
  // wrapper is `display:contents` and the panel below is the flex item,
425
538
  // exactly as it was.
426
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { error: _optionalChain([errors, 'access', _15 => _15.legalConsentResponses, 'optionalAccess', _16 => _16.message]), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)] rounded-md border border-ods-border p-[var(--spacing-system-m)]", children: [
427
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: legalConsent.processingConsentText }),
428
- legalConsent.communicationConsentText && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: legalConsent.communicationConsentText }),
539
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { error: _optionalChain([errors, 'access', _21 => _21.legalConsentResponses, 'optionalAccess', _22 => _22.message]), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)]", children: [
429
540
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
430
541
  _reacthookform.Controller,
431
542
  {
432
543
  control,
433
544
  name: "legalConsentResponses",
434
- render: ({ field: rhf }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: legalConsent.communicationConsentCheckboxes.map((box) => {
545
+ render: ({ field: rhf }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: legalConsent.communicationConsentCheckboxes.map((box, index) => {
435
546
  const responses = _nullishCoalesce(rhf.value, () => ( []));
436
547
  const current = responses.find((r) => r.communicationTypeId === box.communicationTypeId);
437
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
548
+ return (
549
+ // The design system's consent row (`checkbox-block`, the
550
+ // same block the waitlist form uses): box, label, caption
551
+ // in one bordered row. GDPR surface — HubSpot's copy is
552
+ // rendered VERBATIM, never edited. The processing statement
553
+ // rides as the caption of the FIRST row, once: it describes
554
+ // the consent as a whole, not each channel.
438
555
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
439
- _chunkY7ITKISQcjs.Checkbox,
556
+ _chunkB2CSYMKWcjs.CheckboxBlock,
440
557
  {
441
558
  id: `ms-consent-${box.communicationTypeId}`,
442
- checked: _nullishCoalesce(_optionalChain([current, 'optionalAccess', _17 => _17.consented]), () => ( false)),
559
+ checked: _nullishCoalesce(_optionalChain([current, 'optionalAccess', _23 => _23.consented]), () => ( false)),
443
560
  onCheckedChange: (v) => rhf.onChange(
444
561
  responses.map(
445
- (r) => r.communicationTypeId === box.communicationTypeId ? { ...r, consented: v === true } : r
562
+ (r) => r.communicationTypeId === box.communicationTypeId ? { ...r, consented: v } : r
446
563
  )
447
- )
448
- }
449
- ),
450
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Label, { htmlFor: `ms-consent-${box.communicationTypeId}`, children: box.label })
451
- ] }, box.communicationTypeId);
564
+ ),
565
+ label: box.label,
566
+ description: index === 0 ? legalConsent.processingConsentText : void 0
567
+ },
568
+ box.communicationTypeId
569
+ )
570
+ );
452
571
  }) })
453
572
  }
454
573
  ),
574
+ legalConsent.communicationConsentText && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: legalConsent.communicationConsentText }),
455
575
  legalConsent.privacyPolicyText && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: legalConsent.privacyPolicyText })
456
576
  ] }) }),
457
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCJBSU3XBcjs.Button, { type: "submit", loading: isSubmitting, disabled: isSubmitting, children: "Confirm Booking" }) })
577
+ footerNote ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center justify-between gap-[var(--spacing-system-m)]", children: [
578
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: footerNote }),
579
+ submitButton
580
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex", children: submitButton })
581
+ ] });
582
+ }
583
+ function BookingFormSkeleton() {
584
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-1 flex-col gap-[var(--spacing-system-l)] p-[var(--spacing-system-l)] lg:p-0", children: [
585
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-1 gap-[var(--spacing-system-m)] md:grid-cols-2", children: [
586
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Skeleton, { className: "h-[4.75rem] w-full" }),
587
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Skeleton, { className: "h-[4.75rem] w-full" })
588
+ ] }),
589
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Skeleton, { className: "h-[4.75rem] w-full" }),
590
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Skeleton, { className: "h-[7.75rem] w-full" }),
591
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Skeleton, { className: "h-[4.25rem] w-full" }),
592
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex justify-end", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Skeleton, { className: "h-12 w-40" }) })
458
593
  ] });
459
594
  }
460
595
 
@@ -477,7 +612,7 @@ function Confirmation({ confirmation, timezone }) {
477
612
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: [
478
613
  when,
479
614
  " \xB7 ",
480
- _chunkY6I2DGKCcjs.formatDurationCompact.call(void 0, confirmation.durationMs / 1e3)
615
+ _chunkOMKI5T2Gcjs.formatDurationCompact.call(void 0, confirmation.durationMs / 1e3)
481
616
  ] }),
482
617
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: "A calendar invite is on its way to your email." })
483
618
  ] });
@@ -499,7 +634,7 @@ function zoneLabel(tz) {
499
634
  timeZone: tz,
500
635
  timeZoneName: "shortOffset"
501
636
  }).formatToParts(/* @__PURE__ */ new Date());
502
- const offset = _nullishCoalesce(_optionalChain([parts, 'access', _18 => _18.find, 'call', _19 => _19((p) => p.type === "timeZoneName"), 'optionalAccess', _20 => _20.value]), () => ( ""));
637
+ const offset = _nullishCoalesce(_optionalChain([parts, 'access', _24 => _24.find, 'call', _25 => _25((p) => p.type === "timeZoneName"), 'optionalAccess', _26 => _26.value]), () => ( ""));
503
638
  return offset ? `${tz.replace(/_/g, " ")} (${offset})` : tz.replace(/_/g, " ");
504
639
  } catch (e4) {
505
640
  return tz.replace(/_/g, " ");
@@ -511,7 +646,7 @@ function ContextPanelSkeleton({
511
646
  backLabel = "Back"
512
647
  }) {
513
648
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, PANEL_STACK, className), children: [
514
- onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.BackButton, { label: backLabel, onClick: onBack, className: BACK_BUTTON_CLASS }),
649
+ onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.BackButton, { label: backLabel, onClick: onBack, className: BACK_BUTTON_CLASS }),
515
650
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: STRIP_BODY, children: [
516
651
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: STRIP_MAIN, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: IDENTITY_ROW, children: [
517
652
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex min-w-0 flex-1 items-center gap-[var(--spacing-system-xs)] lg:flex-none", children: [
@@ -542,6 +677,7 @@ function SchedulerContextPanel({
542
677
  onBack,
543
678
  backLabel = "Back",
544
679
  locked = false,
680
+ fixedDuration = false,
545
681
  showTimezone = true,
546
682
  className
547
683
  }) {
@@ -558,13 +694,13 @@ function SchedulerContextPanel({
558
694
  return zones.map((tz) => ({ value: tz, label: zoneLabel(tz) }));
559
695
  }, [timezone]);
560
696
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, PANEL_STACK, className), children: [
561
- onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.BackButton, { label: backLabel, onClick: onBack, className: BACK_BUTTON_CLASS }),
697
+ onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.BackButton, { label: backLabel, onClick: onBack, className: BACK_BUTTON_CLASS }),
562
698
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: STRIP_BODY, children: [
563
699
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: STRIP_MAIN, children: [
564
700
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: IDENTITY_ROW, children: [
565
701
  hosts.length > 0 && hosts.length <= 3 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-s)]", children: hosts.map((host) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
566
702
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
567
- _chunkY6I2DGKCcjs.SquareAvatar,
703
+ _chunkOMKI5T2Gcjs.SquareAvatar,
568
704
  {
569
705
  variant: "round",
570
706
  size: "sm",
@@ -579,24 +715,25 @@ function SchedulerContextPanel({
579
715
  ] })
580
716
  ] }, host.name)) }),
581
717
  hosts.length > 3 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)]", children: [
582
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY6I2DGKCcjs.AvatarStack, { people: hosts, max: 4, size: "lg" }),
718
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkOMKI5T2Gcjs.AvatarStack, { people: hosts, max: 4, size: "lg" }),
583
719
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: [
584
720
  hosts.length,
585
721
  " hosts on this calendar"
586
722
  ] })
587
723
  ] }),
588
- locked || durationsMs.length <= 1 ? (
589
- // Post-selection, or a link that offers one length: a static line,
724
+ locked || fixedDuration || durationsMs.length <= 1 ? (
725
+ // Post-selection, a fixed-length flow, or a link that offers one
726
+ // length: a static line,
590
727
  // which is what sits beside the host on the header-strip layouts.
591
728
  selectedDurationMs != null && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "shrink-0 text-ods-text-secondary text-h6", children: [
592
- _chunkY6I2DGKCcjs.formatDurationCompact.call(void 0, selectedDurationMs / 1e3),
729
+ _chunkOMKI5T2Gcjs.formatDurationCompact.call(void 0, selectedDurationMs / 1e3),
593
730
  " call"
594
731
  ] })
595
732
  ) : null
596
733
  ] }),
597
734
  title && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-primary text-h3", children: title }),
598
735
  description && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: description }),
599
- !locked && durationsMs.length > 1 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xxs)]", children: [
736
+ !locked && !fixedDuration && durationsMs.length > 1 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xxs)]", children: [
600
737
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: FIELD_LABEL_CLASS, children: "Duration" }),
601
738
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-wrap gap-[var(--spacing-system-xs)]", children: durationsMs.map((ms) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
602
739
  _chunkCJBSU3XBcjs.Button,
@@ -604,7 +741,7 @@ function SchedulerContextPanel({
604
741
  variant: selectedDurationMs === ms ? void 0 : "outline",
605
742
  size: "small-legacy",
606
743
  onClick: () => onSelectDuration(ms),
607
- children: _chunkY6I2DGKCcjs.formatDurationCompact.call(void 0, ms / 1e3)
744
+ children: _chunkOMKI5T2Gcjs.formatDurationCompact.call(void 0, ms / 1e3)
608
745
  },
609
746
  ms
610
747
  )) })
@@ -619,11 +756,11 @@ function SchedulerContextPanel({
619
756
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, STRIP_ASIDE, locked && "max-lg:hidden"), children: [
620
757
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: FIELD_LABEL_CLASS, children: "Timezone" }),
621
758
  timezone ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
622
- _chunkUBRVIVY4cjs.Autocomplete,
759
+ _chunkB2CSYMKWcjs.Autocomplete,
623
760
  {
624
761
  value: timezone,
625
762
  onChange: (tz) => {
626
- if (tz) _optionalChain([onTimezoneChange, 'optionalCall', _21 => _21(tz)]);
763
+ if (tz) _optionalChain([onTimezoneChange, 'optionalCall', _27 => _27(tz)]);
627
764
  },
628
765
  options: zoneOptions,
629
766
  placeholder: "Search timezone\u2026",
@@ -705,18 +842,18 @@ var NOOP = () => void 0;
705
842
  function DayCalendar({ monthOffset, onMonthOffsetChange, selectedDay, onSelectDay, slotsByDay }) {
706
843
  const now = /* @__PURE__ */ new Date();
707
844
  const startMonth = new Date(now.getFullYear(), now.getMonth(), 1);
708
- const endMonth = new Date(now.getFullYear(), now.getMonth() + _chunkUBRVIVY4cjs.MAX_MONTH_OFFSET + 1, 0);
845
+ const endMonth = new Date(now.getFullYear(), now.getMonth() + _chunkB2CSYMKWcjs.MAX_MONTH_OFFSET + 1, 0);
709
846
  const visibleMonth = new Date(now.getFullYear(), now.getMonth() + monthOffset, 1);
710
- const dayHasNoSlots = _react.useCallback.call(void 0, (day) => !_optionalChain([slotsByDay, 'optionalAccess', _22 => _22.has, 'call', _23 => _23(calendarDayKey(day))]), [slotsByDay]);
847
+ const dayHasNoSlots = _react.useCallback.call(void 0, (day) => !_optionalChain([slotsByDay, 'optionalAccess', _28 => _28.has, 'call', _29 => _29(calendarDayKey(day))]), [slotsByDay]);
711
848
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex min-h-0 flex-1 flex-col", "aria-busy": slotsByDay === null, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
712
- _chunkUBRVIVY4cjs.DatePickerCalendar,
849
+ _chunkB2CSYMKWcjs.DatePickerCalendar,
713
850
  {
714
851
  mode: "single",
715
852
  bare: true,
716
853
  month: visibleMonth,
717
854
  onMonthChange: (month) => {
718
855
  const offset = (month.getFullYear() - now.getFullYear()) * 12 + (month.getMonth() - now.getMonth());
719
- onMonthOffsetChange(Math.max(0, Math.min(_chunkUBRVIVY4cjs.MAX_MONTH_OFFSET, offset)));
856
+ onMonthOffsetChange(Math.max(0, Math.min(_chunkB2CSYMKWcjs.MAX_MONTH_OFFSET, offset)));
720
857
  },
721
858
  fromDate: startMonth,
722
859
  toDate: endMonth,
@@ -725,7 +862,7 @@ function DayCalendar({ monthOffset, onMonthOffsetChange, selectedDay, onSelectDa
725
862
  const day = value;
726
863
  if (!day) return;
727
864
  const key = calendarDayKey(day);
728
- if (_optionalChain([slotsByDay, 'optionalAccess', _24 => _24.has, 'call', _25 => _25(key)])) onSelectDay(key);
865
+ if (_optionalChain([slotsByDay, 'optionalAccess', _30 => _30.has, 'call', _31 => _31(key)])) onSelectDay(key);
729
866
  },
730
867
  disabledDays: slotsByDay === null ? DISABLE_EVERY_DAY : dayHasNoSlots
731
868
  }
@@ -767,7 +904,8 @@ function SlotPicker({
767
904
  onSelectSlot,
768
905
  selectedDay,
769
906
  onSelectDay,
770
- isLoading = false
907
+ isLoading = false,
908
+ isSubmitting = false
771
909
  }) {
772
910
  const slotsByDay = _react.useMemo.call(void 0, () => {
773
911
  const map = /* @__PURE__ */ new Map();
@@ -813,7 +951,12 @@ function SlotPicker({
813
951
  _chunkCJBSU3XBcjs.Button,
814
952
  {
815
953
  variant: isSelected ? void 0 : "outline",
816
- onClick: () => onSelectSlot(ms),
954
+ disabled: isSubmitting,
955
+ loading: isSubmitting && isSelected,
956
+ onClick: () => {
957
+ if (isSubmitting) return;
958
+ onSelectSlot(ms);
959
+ },
817
960
  className: CHIP_CLASS,
818
961
  children: timeLabelInZone(ms, timezone)
819
962
  },
@@ -830,7 +973,7 @@ function SlotPicker({
830
973
  monthLabelFor(monthOffset),
831
974
  "."
832
975
  ] }),
833
- monthOffset < _chunkUBRVIVY4cjs.MAX_MONTH_OFFSET && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
976
+ monthOffset < _chunkB2CSYMKWcjs.MAX_MONTH_OFFSET && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
834
977
  _chunkCJBSU3XBcjs.Button,
835
978
  {
836
979
  variant: "outline",
@@ -852,7 +995,7 @@ function SlotPicker({
852
995
 
853
996
 
854
997
  function useNextAvailableLabel(ms) {
855
- const hydrated = _chunkYLVPQNLOcjs.useIsHydrated.call(void 0, );
998
+ const hydrated = _chunk5MSHWXJ5cjs.useIsHydrated.call(void 0, );
856
999
  return _react.useMemo.call(void 0, () => {
857
1000
  if (!hydrated || ms == null) return null;
858
1001
  try {
@@ -876,7 +1019,7 @@ function DirectoryRow({
876
1019
  const nextLabel = useNextAvailableLabel(link.nextAvailableMs);
877
1020
  const subtitle = [
878
1021
  link.description,
879
- link.durationsMinutes.length > 0 ? link.durationsMinutes.map((m) => _chunkY6I2DGKCcjs.formatDurationCompact.call(void 0, m * 60)).join(" / ") : null,
1022
+ link.durationsMinutes.length > 0 ? link.durationsMinutes.map((m) => _chunkOMKI5T2Gcjs.formatDurationCompact.call(void 0, m * 60)).join(" / ") : null,
880
1023
  link.kind === "team" ? "Team" : null
881
1024
  ].filter(Boolean).join(" \u2022 ");
882
1025
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -890,8 +1033,8 @@ function DirectoryRow({
890
1033
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "truncate text-ods-text-primary text-h3", children: link.title }),
891
1034
  subtitle && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "truncate text-ods-text-secondary text-h6", children: subtitle })
892
1035
  ] }),
893
- audienceLabel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY6I2DGKCcjs.StatusBadge, { text: `For ${audienceLabel}`, singleLine: true, className: "hidden shrink-0 sm:inline-flex" }),
894
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY6I2DGKCcjs.AvatarStack, { people: link.hosts, max: 3, size: "md", className: "flex shrink-0" }),
1036
+ audienceLabel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkOMKI5T2Gcjs.StatusBadge, { text: `For ${audienceLabel}`, singleLine: true, className: "hidden shrink-0 sm:inline-flex" }),
1037
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkOMKI5T2Gcjs.AvatarStack, { people: link.hosts, max: 3, size: "md", className: "flex shrink-0" }),
895
1038
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "hidden w-44 shrink-0 flex-col items-end justify-center md:flex", children: [
896
1039
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: "Next available" }),
897
1040
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "min-h-5 text-ods-text-primary text-h6", children: link.nextAvailableMs == null ? "No times published" : _nullishCoalesce(nextLabel, () => ( " ")) })
@@ -957,7 +1100,7 @@ function MeetingSchedulerDirectory({
957
1100
  };
958
1101
  }, [initialData, includeAll, apiBaseUrl]);
959
1102
  const rows = _react.useMemo.call(void 0, () => {
960
- const purposes = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _26 => _26.purposes]), () => ( []));
1103
+ const purposes = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _32 => _32.purposes]), () => ( []));
961
1104
  return purposes.flatMap((p) => p.links.map((link) => ({ link, audienceLabel: p.label })));
962
1105
  }, [data]);
963
1106
  const totalPages = _chunkH64ZHSYRcjs.pageCount.call(void 0, rows.length, pageSize);
@@ -1019,16 +1162,18 @@ var CONTEXT_PANEL_CLASS = "p-[var(--spacing-system-l)] shrink-0 lg:w-[280px] bor
1019
1162
  var ACTION_PANEL_CLASS = "flex-1 min-w-0 flex flex-col md:min-h-0 lg:p-[var(--spacing-system-l)]";
1020
1163
  var PANEL_STEP_CLASS = "p-[var(--spacing-system-l)] md:min-h-0 md:overflow-y-auto lg:p-0";
1021
1164
  var MEETING_SCHEDULER_H = "md:h-[34.375rem] lg:h-[23.75rem]";
1165
+ var MEETING_SCHEDULER_DETAILS_FIRST_H = "md:h-[39.875rem]";
1022
1166
  var CARD_CLASS = _chunk23V5BSHDcjs.cn.call(void 0,
1023
1167
  "overflow-hidden rounded-md border border-ods-border bg-ods-card",
1024
- "md:flex md:flex-col",
1025
- MEETING_SCHEDULER_H
1168
+ "md:flex md:flex-col"
1169
+ // The height is NOT baked in any more: it is chosen per flow at each render
1170
+ // site (`flowHeight`), because details-first needs a taller box and both
1171
+ // constants are module scope.
1026
1172
  );
1027
1173
  var CARD_INNER_CLASS = "flex flex-col md:min-h-0 md:flex-1 lg:h-full lg:flex-row";
1028
1174
  var CARD_DEGRADED_CLASS = _chunk23V5BSHDcjs.cn.call(void 0,
1029
1175
  "flex flex-col items-start gap-[var(--spacing-system-m)] rounded-md border border-ods-border bg-ods-card p-[var(--spacing-system-lf)]",
1030
- "md:justify-center md:overflow-y-auto",
1031
- MEETING_SCHEDULER_H
1176
+ "md:justify-center md:overflow-y-auto"
1032
1177
  );
1033
1178
  function isNativelyBookable(availability) {
1034
1179
  if (!availability.formFields.every(isSupportedFormField)) return false;
@@ -1050,7 +1195,9 @@ function HubSpotMeetingScheduler({
1050
1195
  fallbackUrl,
1051
1196
  onBack,
1052
1197
  onBooked,
1053
- className
1198
+ className,
1199
+ flow = "slot-first",
1200
+ detailsForm: DetailsForm = BookingForm
1054
1201
  }) {
1055
1202
  const {
1056
1203
  availability,
@@ -1063,7 +1210,8 @@ function HubSpotMeetingScheduler({
1063
1210
  book,
1064
1211
  isSubmitting
1065
1212
  } = useMeetingBooking({ meetingId, apiBaseUrl, initialAvailability });
1066
- const hydrated = _chunkYLVPQNLOcjs.useIsHydrated.call(void 0, );
1213
+ const detailsFirst = flow === "details-first";
1214
+ const hydrated = _chunk5MSHWXJ5cjs.useIsHydrated.call(void 0, );
1067
1215
  const [pickedTimezone, setTimezone] = _react.useState.call(void 0, null);
1068
1216
  const resolvedLocalTimezone = _react.useMemo.call(void 0, () => {
1069
1217
  if (!hydrated) return null;
@@ -1074,30 +1222,33 @@ function HubSpotMeetingScheduler({
1074
1222
  }
1075
1223
  }, [hydrated]);
1076
1224
  const timezone = _nullishCoalesce(_nullishCoalesce(pickedTimezone, () => ( displayTimezone)), () => ( resolvedLocalTimezone));
1077
- const [step, setStep] = _react.useState.call(void 0, "slot");
1225
+ const [step, setStep] = _react.useState.call(void 0, detailsFirst ? "details" : "slot");
1226
+ const [stash, setStash] = _react.useState.call(void 0, null);
1227
+ const formOnly = detailsFirst && step === "details";
1078
1228
  const [pickedDurationMs, setDurationMs] = _react.useState.call(void 0, null);
1079
1229
  const [pickedDay, setSelectedDay] = _react.useState.call(void 0, null);
1080
1230
  const [selectedSlot, setSelectedSlot] = _react.useState.call(void 0, null);
1081
1231
  const [confirmation, setConfirmation] = _react.useState.call(void 0, null);
1082
1232
  const [bookingError, setBookingError] = _react.useState.call(void 0, null);
1083
- const { honeypotInputProps, getSignals, resetSignals } = _chunkFKXDDJEQcjs.useHumanitySignals.call(void 0, );
1084
- const { toast } = _chunkFKXDDJEQcjs.useToast.call(void 0, );
1233
+ const { honeypotInputProps, getSignals, resetSignals } = _chunkM4YQUHORcjs.useHumanitySignals.call(void 0, );
1234
+ const { toast } = _chunkM4YQUHORcjs.useToast.call(void 0, );
1085
1235
  const autoAdvanceCount = _react.useRef.call(void 0, 0);
1086
1236
  const [machineFor, setMachineFor] = _react.useState.call(void 0, meetingId);
1087
1237
  if (machineFor !== meetingId) {
1088
1238
  setMachineFor(meetingId);
1089
- setStep("slot");
1239
+ setStep(detailsFirst ? "details" : "slot");
1090
1240
  setDurationMs(null);
1091
1241
  setSelectedDay(null);
1092
1242
  setSelectedSlot(null);
1093
1243
  setConfirmation(null);
1094
1244
  setBookingError(null);
1245
+ setStash(null);
1095
1246
  }
1096
1247
  _react.useEffect.call(void 0, () => {
1097
1248
  autoAdvanceCount.current = 0;
1098
1249
  }, [meetingId]);
1099
- const durations = _react.useMemo.call(void 0, () => _nullishCoalesce(_optionalChain([availability, 'optionalAccess', _27 => _27.durationsMs]), () => ( [])), [_optionalChain([availability, 'optionalAccess', _28 => _28.durationsMs])]);
1100
- const shownHosts = _nullishCoalesce(_nullishCoalesce(hosts, () => ( _optionalChain([availability, 'optionalAccess', _29 => _29.hosts]))), () => ( []));
1250
+ const durations = _react.useMemo.call(void 0, () => _nullishCoalesce(_optionalChain([availability, 'optionalAccess', _33 => _33.durationsMs]), () => ( [])), [_optionalChain([availability, 'optionalAccess', _34 => _34.durationsMs])]);
1251
+ const shownHosts = _nullishCoalesce(_nullishCoalesce(hosts, () => ( _optionalChain([availability, 'optionalAccess', _35 => _35.hosts]))), () => ( []));
1101
1252
  const durationMs = _nullishCoalesce(_nullishCoalesce(pickedDurationMs, () => ( durations[0])), () => ( null));
1102
1253
  const slots = _react.useMemo.call(void 0, () => {
1103
1254
  if (!availability || durationMs == null) return [];
@@ -1126,14 +1277,34 @@ function HubSpotMeetingScheduler({
1126
1277
  setStep("slot");
1127
1278
  setBookingError(null);
1128
1279
  }, []);
1280
+ const backToDetails = _react.useCallback.call(void 0, () => {
1281
+ setStep("details");
1282
+ setBookingError(null);
1283
+ }, []);
1284
+ const stashDetails = _react.useCallback.call(void 0,
1285
+ (payload) => {
1286
+ setBookingError(null);
1287
+ setStash({ payload, signals: getSignals() });
1288
+ setStep("slot");
1289
+ autoAdvanceCount.current = 0;
1290
+ void refetchAvailability();
1291
+ return Promise.resolve();
1292
+ },
1293
+ [getSignals, refetchAvailability]
1294
+ );
1129
1295
  const handleSubmit = _react.useCallback.call(void 0,
1130
1296
  async (payload) => {
1297
+ const priorError = bookingError;
1131
1298
  setBookingError(null);
1132
1299
  const result = await book(payload);
1300
+ if (!result.ok && result.message === "Already submitting") {
1301
+ setBookingError(priorError);
1302
+ return;
1303
+ }
1133
1304
  if (result.ok && result.confirmation) {
1134
1305
  setConfirmation(result.confirmation);
1135
1306
  setStep("confirmed");
1136
- _optionalChain([onBooked, 'optionalCall', _30 => _30(result.confirmation)]);
1307
+ _optionalChain([onBooked, 'optionalCall', _36 => _36(result.confirmation)]);
1137
1308
  return;
1138
1309
  }
1139
1310
  const code = _nullishCoalesce(result.code, () => ( "TEMPORARILY_UNAVAILABLE"));
@@ -1141,8 +1312,10 @@ function HubSpotMeetingScheduler({
1141
1312
  if (code === "SLOT_TAKEN") {
1142
1313
  setSelectedSlot(null);
1143
1314
  setStep("slot");
1144
- resetSignals();
1315
+ if (!detailsFirst) resetSignals();
1145
1316
  void refetchAvailability();
1317
+ } else if (detailsFirst && (code === "VALIDATION" || code === "INVALID_EMAIL")) {
1318
+ setStep("details");
1146
1319
  } else {
1147
1320
  toast({
1148
1321
  variant: "error",
@@ -1151,29 +1324,31 @@ function HubSpotMeetingScheduler({
1151
1324
  });
1152
1325
  }
1153
1326
  },
1154
- [book, onBooked, refetchAvailability, resetSignals, toast]
1327
+ [book, bookingError, detailsFirst, onBooked, refetchAvailability, resetSignals, toast]
1155
1328
  );
1156
1329
  const escapeHatch = fallbackUrl ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCJBSU3XBcjs.Button, { variant: "outline", size: "small-legacy", href: fallbackUrl, openInNewTab: true, children: "Open in HubSpot" }) : null;
1330
+ const flowHeight = detailsFirst ? MEETING_SCHEDULER_DETAILS_FIRST_H : MEETING_SCHEDULER_H;
1331
+ const unseededDetailsFirstFailure = detailsFirst && step === "details" && !availability && !initialAvailability && !hydrated;
1332
+ const degradedCard = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_DEGRADED_CLASS, flowHeight, className), children: [
1333
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: "We couldn't load available call times. Please try again shortly." }),
1334
+ escapeHatch
1335
+ ] });
1336
+ if (unseededDetailsFirstFailure) return degradedCard;
1157
1337
  if (isLoadingAvailability && !availability) {
1158
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_CLASS, className), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: CARD_INNER_CLASS, children: [
1159
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ContextPanelSkeleton, { onBack, className: CONTEXT_PANEL_CLASS }),
1160
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: ACTION_PANEL_CLASS, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SlotPickerSkeleton, { monthOffset }) })
1338
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_CLASS, flowHeight, formOnly && "bg-ods-bg", className), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: CARD_INNER_CLASS, children: [
1339
+ !formOnly && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ContextPanelSkeleton, { onBack, className: CONTEXT_PANEL_CLASS }),
1340
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: ACTION_PANEL_CLASS, children: detailsFirst && step === "details" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BookingFormSkeleton, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SlotPickerSkeleton, { monthOffset }) })
1161
1341
  ] }) });
1162
1342
  }
1163
- if (availabilityError || !availability) {
1164
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_DEGRADED_CLASS, className), children: [
1165
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: "We couldn't load available call times. Please try again shortly." }),
1166
- escapeHatch
1167
- ] });
1168
- }
1343
+ if (availabilityError || !availability) return degradedCard;
1169
1344
  if (!isNativelyBookable(availability)) {
1170
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_DEGRADED_CLASS, className), children: [
1345
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_DEGRADED_CLASS, flowHeight, className), children: [
1171
1346
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: "This meeting type is booked directly on HubSpot." }),
1172
1347
  escapeHatch
1173
1348
  ] });
1174
1349
  }
1175
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_CLASS, className), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: CARD_INNER_CLASS, children: [
1176
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1350
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_CLASS, flowHeight, formOnly && "bg-ods-bg", className), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: CARD_INNER_CLASS, children: [
1351
+ !formOnly && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1177
1352
  SchedulerContextPanel,
1178
1353
  {
1179
1354
  hosts: shownHosts,
@@ -1185,18 +1360,24 @@ function HubSpotMeetingScheduler({
1185
1360
  setDurationMs(ms);
1186
1361
  setSelectedDay(null);
1187
1362
  setSelectedSlot(null);
1188
- if (step === "details") setStep("slot");
1363
+ if (!detailsFirst && step === "details") setStep("slot");
1189
1364
  },
1190
1365
  timezone,
1191
1366
  onTimezoneChange: setTimezone,
1192
- onBack: step === "details" ? backToSlot : onBack,
1193
- locked: step !== "slot",
1367
+ onBack: detailsFirst ? step === "slot" ? backToDetails : onBack : step === "details" ? backToSlot : onBack,
1368
+ locked: detailsFirst ? step === "confirmed" || isSubmitting : step !== "slot",
1194
1369
  showTimezone: step !== "confirmed",
1370
+ fixedDuration: detailsFirst,
1195
1371
  className: CONTEXT_PANEL_CLASS
1196
1372
  }
1197
1373
  ),
1198
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: ACTION_PANEL_CLASS, children: step === "confirmed" && confirmation && timezone ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, "flex flex-1 flex-col", PANEL_STEP_CLASS), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Confirmation, { confirmation, timezone }) }) : step === "details" && durationMs != null && selectedSlot != null && timezone ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, "flex flex-1 flex-col gap-[var(--spacing-system-m)]", PANEL_STEP_CLASS), children: [
1199
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-ods-text-primary text-h4", children: [
1374
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: ACTION_PANEL_CLASS, children: step === "confirmed" && confirmation && timezone ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, "flex flex-1 flex-col", PANEL_STEP_CLASS), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Confirmation, { confirmation, timezone }) }) : step === "details" && (detailsFirst ? (
1375
+ // The form is step ONE here: no slot yet, and `timezone` is null
1376
+ // on the server render, so neither may gate the PANEL. A link
1377
+ // publishing no durations has no form worth showing.
1378
+ durations.length > 0
1379
+ ) : durationMs != null && selectedSlot != null && timezone) ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, "flex flex-1 flex-col gap-[var(--spacing-system-m)]", PANEL_STEP_CLASS), children: [
1380
+ selectedSlot != null && durationMs != null && timezone != null && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-ods-text-primary text-h4", children: [
1200
1381
  new Intl.DateTimeFormat(void 0, {
1201
1382
  timeZone: timezone,
1202
1383
  weekday: "long",
@@ -1208,29 +1389,33 @@ function HubSpotMeetingScheduler({
1208
1389
  }).format(new Date(selectedSlot)),
1209
1390
  " ",
1210
1391
  "\xB7 ",
1211
- _chunkY6I2DGKCcjs.formatDurationCompact.call(void 0, durationMs / 1e3)
1392
+ _chunkOMKI5T2Gcjs.formatDurationCompact.call(void 0, durationMs / 1e3)
1212
1393
  ] }),
1213
1394
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1214
- BookingForm,
1395
+ DetailsForm,
1215
1396
  {
1216
1397
  availability,
1217
1398
  meetingId,
1218
- startTimeMs: selectedSlot,
1219
- durationMs,
1399
+ startTimeMs: _nullishCoalesce(selectedSlot, () => ( void 0)),
1400
+ durationMs: _nullishCoalesce(durationMs, () => ( void 0)),
1220
1401
  timezone,
1402
+ deferSlot: detailsFirst,
1403
+ submitLabel: detailsFirst ? "Continue" : void 0,
1404
+ footerNote: detailsFirst ? "Next step: pick a slot that works. Calendar invite lands right after." : void 0,
1405
+ initialValues: detailsFirst ? _optionalChain([stash, 'optionalAccess', _37 => _37.payload]) : void 0,
1221
1406
  isSubmitting,
1222
- onSubmit: handleSubmit,
1407
+ onSubmit: detailsFirst ? stashDetails : handleSubmit,
1223
1408
  honeypotInputProps,
1224
1409
  getSignals
1225
1410
  }
1226
1411
  )
1227
1412
  ] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-m)] md:min-h-0 md:flex-1", children: [
1228
1413
  bookingError === "SLOT_TAKEN" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1229
- _chunkUBRVIVY4cjs.Alert,
1414
+ _chunkB2CSYMKWcjs.Alert,
1230
1415
  {
1231
1416
  variant: "warning",
1232
1417
  className: "mx-[var(--spacing-system-l)] mt-[var(--spacing-system-l)] w-auto lg:m-0 lg:w-full",
1233
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.AlertDescription, { children: "That time was just taken \u2014 pick another slot below. (If you already submitted, check your email for a confirmation before rebooking.)" })
1418
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.AlertDescription, { children: "That time was just taken \u2014 pick another slot below. (If you already submitted, check your email for a confirmation before rebooking.)" })
1234
1419
  }
1235
1420
  ),
1236
1421
  timezone && durationMs != null ? (
@@ -1250,12 +1435,31 @@ function HubSpotMeetingScheduler({
1250
1435
  },
1251
1436
  selectedSlot,
1252
1437
  onSelectSlot: (ms) => {
1438
+ if (!detailsFirst) {
1439
+ setSelectedSlot(ms);
1440
+ setStep("details");
1441
+ return;
1442
+ }
1443
+ if (isSubmitting || !stash) return;
1253
1444
  setSelectedSlot(ms);
1254
- setStep("details");
1445
+ void handleSubmit({
1446
+ ...stash.payload,
1447
+ ...stash.signals,
1448
+ meetingId,
1449
+ // `ms`, NOT `selectedSlot` — the setState above has not
1450
+ // committed inside this handler, so state holds null on
1451
+ // the first booking and the PREVIOUS slot on a retry.
1452
+ startTimeMs: ms,
1453
+ // Live values: both stay editable after Continue, so the
1454
+ // copies frozen at that point can be stale.
1455
+ durationMs,
1456
+ timezone
1457
+ });
1255
1458
  },
1256
1459
  selectedDay,
1257
1460
  onSelectDay: setSelectedDay,
1258
- isLoading: isLoadingAvailability
1461
+ isLoading: isLoadingAvailability,
1462
+ isSubmitting: detailsFirst ? isSubmitting : void 0
1259
1463
  }
1260
1464
  )
1261
1465
  ) : durations.length === 0 && !isFetchingAvailability ? (
@@ -1280,5 +1484,8 @@ function HubSpotMeetingScheduler({
1280
1484
 
1281
1485
 
1282
1486
 
1283
- exports.HubSpotMeetingScheduler = HubSpotMeetingScheduler; exports.MEETING_SCHEDULER_H = MEETING_SCHEDULER_H; exports.MeetingSchedulerDirectory = MeetingSchedulerDirectory; exports.MeetingSchedulerDirectoryRowSkeleton = MeetingSchedulerDirectoryRowSkeleton;
1487
+
1488
+
1489
+
1490
+ exports.BookingForm = BookingForm; exports.BookingFormSkeleton = BookingFormSkeleton; exports.HubSpotMeetingScheduler = HubSpotMeetingScheduler; exports.MEETING_SCHEDULER_DETAILS_FIRST_H = MEETING_SCHEDULER_DETAILS_FIRST_H; exports.MEETING_SCHEDULER_H = MEETING_SCHEDULER_H; exports.MeetingSchedulerDirectory = MeetingSchedulerDirectory; exports.MeetingSchedulerDirectoryRowSkeleton = MeetingSchedulerDirectoryRowSkeleton;
1284
1491
  //# sourceMappingURL=index.cjs.map