@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.
- package/dist/{chunk-HQWZ4IXU.cjs → chunk-3CH6VRJX.cjs} +24 -24
- package/dist/{chunk-HQWZ4IXU.cjs.map → chunk-3CH6VRJX.cjs.map} +1 -1
- package/dist/{chunk-LKN2KKYZ.js → chunk-4K7TCJ35.js} +6 -59
- package/dist/{chunk-LKN2KKYZ.js.map → chunk-4K7TCJ35.js.map} +1 -1
- package/dist/{chunk-YLVPQNLO.cjs → chunk-5MSHWXJ5.cjs} +170 -223
- package/dist/chunk-5MSHWXJ5.cjs.map +1 -0
- package/dist/{chunk-CCLPJSY3.cjs → chunk-73BECFSU.cjs} +15 -15
- package/dist/{chunk-CCLPJSY3.cjs.map → chunk-73BECFSU.cjs.map} +1 -1
- package/dist/{chunk-F5Q3DTP5.js → chunk-7EUE3YTC.js} +8 -8
- package/dist/{chunk-GBIC3VNA.js → chunk-7KGN7DV6.js} +6 -6
- package/dist/{chunk-YZLUOZKR.js → chunk-7Q66A4CF.js} +2 -2
- package/dist/{chunk-DRZ224RU.js → chunk-ANSZVKI2.js} +8 -8
- package/dist/{chunk-N3RHX26N.js → chunk-AZZVSEP5.js} +3 -3
- package/dist/{chunk-66I2QUFE.cjs → chunk-B26UT36N.cjs} +6 -6
- package/dist/{chunk-66I2QUFE.cjs.map → chunk-B26UT36N.cjs.map} +1 -1
- package/dist/{chunk-UBRVIVY4.cjs → chunk-B2CSYMKW.cjs} +298 -285
- package/dist/chunk-B2CSYMKW.cjs.map +1 -0
- package/dist/{chunk-ZK3AZ5YF.cjs → chunk-BTOL222V.cjs} +11 -11
- package/dist/{chunk-ZK3AZ5YF.cjs.map → chunk-BTOL222V.cjs.map} +1 -1
- package/dist/{chunk-S7VW4HVL.cjs → chunk-DODE3PD4.cjs} +49 -49
- package/dist/{chunk-S7VW4HVL.cjs.map → chunk-DODE3PD4.cjs.map} +1 -1
- package/dist/{chunk-ZZHHKE2Q.js → chunk-ECXQX4EP.js} +2 -2
- package/dist/{chunk-NEFNARFF.cjs → chunk-EEV7SSBJ.cjs} +30 -30
- package/dist/{chunk-NEFNARFF.cjs.map → chunk-EEV7SSBJ.cjs.map} +1 -1
- package/dist/{chunk-3OQIZPUX.js → chunk-EO3NEGWB.js} +4 -4
- package/dist/{chunk-MOHSA65M.js → chunk-EZM5DNII.js} +2 -2
- package/dist/{chunk-IKQVXZB5.js → chunk-GSPS6Y5U.js} +6 -6
- package/dist/{chunk-CQ35OMPJ.cjs → chunk-I2BNLWC3.cjs} +3 -3
- package/dist/{chunk-CQ35OMPJ.cjs.map → chunk-I2BNLWC3.cjs.map} +1 -1
- package/dist/{chunk-HOLK4ZMT.js → chunk-II2GBWNW.js} +4 -4
- package/dist/{chunk-PETYVGEQ.cjs → chunk-JKGVXLTT.cjs} +5 -5
- package/dist/{chunk-PETYVGEQ.cjs.map → chunk-JKGVXLTT.cjs.map} +1 -1
- package/dist/{chunk-5EM6NGBK.cjs → chunk-KOQCA5X5.cjs} +17 -27
- package/dist/chunk-KOQCA5X5.cjs.map +1 -0
- package/dist/{chunk-ACU7J5BL.cjs → chunk-KPE7OQF6.cjs} +84 -84
- package/dist/{chunk-ACU7J5BL.cjs.map → chunk-KPE7OQF6.cjs.map} +1 -1
- package/dist/{chunk-C4YJC5X7.cjs → chunk-KRKW63LG.cjs} +9 -9
- package/dist/{chunk-C4YJC5X7.cjs.map → chunk-KRKW63LG.cjs.map} +1 -1
- package/dist/{chunk-ZEG3ZJPY.cjs → chunk-LE5SZPMN.cjs} +33 -33
- package/dist/{chunk-ZEG3ZJPY.cjs.map → chunk-LE5SZPMN.cjs.map} +1 -1
- package/dist/{chunk-A5AKGC4S.js → chunk-LPMDCQLL.js} +17 -27
- package/dist/chunk-LPMDCQLL.js.map +1 -0
- package/dist/{chunk-EWOFXJGH.cjs → chunk-M3OQLL7D.cjs} +63 -63
- package/dist/{chunk-EWOFXJGH.cjs.map → chunk-M3OQLL7D.cjs.map} +1 -1
- package/dist/{chunk-FKXDDJEQ.cjs → chunk-M4YQUHOR.cjs} +5 -5
- package/dist/{chunk-FKXDDJEQ.cjs.map → chunk-M4YQUHOR.cjs.map} +1 -1
- package/dist/{chunk-5XQMEDGE.cjs → chunk-OHJ4QOWN.cjs} +12 -12
- package/dist/{chunk-5XQMEDGE.cjs.map → chunk-OHJ4QOWN.cjs.map} +1 -1
- package/dist/{chunk-Y6I2DGKC.cjs → chunk-OMKI5T2G.cjs} +1 -1
- package/dist/chunk-OMKI5T2G.cjs.map +1 -0
- package/dist/{chunk-M5HGULIY.js → chunk-OQODJ26H.js} +5 -5
- package/dist/{chunk-MEWAFY6X.js → chunk-OT5IQMSI.js} +4 -4
- package/dist/{chunk-Y22VQDVW.js → chunk-QB244ZDI.js} +4 -4
- package/dist/{chunk-3T7ZP3TL.js → chunk-QL6ECU6Y.js} +3 -3
- package/dist/{chunk-3XDPXOMS.js → chunk-R2SZYRB2.js} +7 -7
- package/dist/{chunk-QAVT6P5F.cjs → chunk-RFA5T5MW.cjs} +28 -28
- package/dist/{chunk-QAVT6P5F.cjs.map → chunk-RFA5T5MW.cjs.map} +1 -1
- package/dist/{chunk-BTF3CNDP.js → chunk-ROQO355A.js} +1 -1
- package/dist/chunk-ROQO355A.js.map +1 -0
- package/dist/{chunk-43ADGEWL.cjs → chunk-UJAMXLA3.cjs} +40 -40
- package/dist/{chunk-43ADGEWL.cjs.map → chunk-UJAMXLA3.cjs.map} +1 -1
- package/dist/{chunk-KVNA3HU2.js → chunk-XANQTIHS.js} +3 -3
- package/dist/{chunk-PMN7WDXI.js → chunk-YUHOKPKS.js} +26 -13
- package/dist/chunk-YUHOKPKS.js.map +1 -0
- package/dist/components/case-studies/index.cjs +16 -16
- package/dist/components/case-studies/index.js +6 -6
- package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +4 -4
- package/dist/components/chat/index.js +3 -3
- package/dist/components/contact/index.cjs +7 -7
- package/dist/components/contact/index.js +6 -6
- package/dist/components/docs/index.cjs +10 -10
- package/dist/components/docs/index.js +9 -9
- package/dist/components/embeds/index.cjs +7 -7
- package/dist/components/embeds/index.js +6 -6
- package/dist/components/faq/index.cjs +7 -7
- package/dist/components/faq/index.js +6 -6
- package/dist/components/features/index.cjs +6 -6
- package/dist/components/features/index.js +5 -5
- package/dist/components/help-center-pages/index.cjs +26 -26
- package/dist/components/help-center-pages/index.js +17 -17
- package/dist/components/icons/index.cjs +2 -2
- package/dist/components/icons/index.js +1 -1
- package/dist/components/icons/mlg-logo.d.ts.map +1 -1
- package/dist/components/index.cjs +56 -56
- package/dist/components/index.js +17 -17
- package/dist/components/meeting-scheduler/booking-form.d.ts +70 -6
- package/dist/components/meeting-scheduler/booking-form.d.ts.map +1 -1
- package/dist/components/meeting-scheduler/context-panel.d.ts +9 -1
- package/dist/components/meeting-scheduler/context-panel.d.ts.map +1 -1
- package/dist/components/meeting-scheduler/index.cjs +395 -188
- package/dist/components/meeting-scheduler/index.cjs.map +1 -1
- package/dist/components/meeting-scheduler/index.d.ts +55 -1
- package/dist/components/meeting-scheduler/index.d.ts.map +1 -1
- package/dist/components/meeting-scheduler/index.js +381 -174
- package/dist/components/meeting-scheduler/index.js.map +1 -1
- package/dist/components/meeting-scheduler/slot-picker.d.ts +8 -1
- package/dist/components/meeting-scheduler/slot-picker.d.ts.map +1 -1
- package/dist/components/navigation/index.cjs +9 -9
- package/dist/components/navigation/index.js +8 -8
- package/dist/components/onboarding-guides/index.cjs +9 -9
- package/dist/components/onboarding-guides/index.js +8 -8
- package/dist/components/related-content/index.cjs +3 -3
- package/dist/components/related-content/index.js +2 -2
- package/dist/components/tickets/index.cjs +10 -10
- package/dist/components/tickets/index.js +9 -9
- package/dist/components/ui/benefit-card.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +6 -6
- package/dist/components/ui/index.js +5 -5
- package/dist/hooks/index.cjs +3 -3
- package/dist/hooks/index.js +2 -2
- package/dist/index.cjs +10 -10
- package/dist/index.js +9 -9
- package/dist/schemas/meeting-booking-schema.cjs +19 -4
- package/dist/schemas/meeting-booking-schema.cjs.map +1 -1
- package/dist/schemas/meeting-booking-schema.d.ts +41 -16
- package/dist/schemas/meeting-booking-schema.d.ts.map +1 -1
- package/dist/schemas/meeting-booking-schema.js +19 -5
- package/dist/schemas/meeting-booking-schema.js.map +1 -1
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.cjs +18 -40
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js +18 -40
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/source-icons.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/entity-cards/dispatch.tsx +0 -57
- package/src/components/icons/mlg-logo.tsx +1 -7
- package/src/components/meeting-scheduler/booking-form.tsx +425 -154
- package/src/components/meeting-scheduler/context-panel.tsx +13 -3
- package/src/components/meeting-scheduler/index.tsx +317 -69
- package/src/components/meeting-scheduler/slot-picker.tsx +17 -1
- package/src/components/ui/benefit-card.tsx +30 -9
- package/src/schemas/meeting-booking-schema.ts +58 -4
- package/src/types/tmcg.ts +0 -2
- package/src/utils/format.ts +1 -1
- package/src/utils/source-icons.ts +0 -24
- package/dist/chunk-5EM6NGBK.cjs.map +0 -1
- package/dist/chunk-A5AKGC4S.js.map +0 -1
- package/dist/chunk-BTF3CNDP.js.map +0 -1
- package/dist/chunk-PMN7WDXI.js.map +0 -1
- package/dist/chunk-UBRVIVY4.cjs.map +0 -1
- package/dist/chunk-Y6I2DGKC.cjs.map +0 -1
- package/dist/chunk-YLVPQNLO.cjs.map +0 -1
- /package/dist/{chunk-F5Q3DTP5.js.map → chunk-7EUE3YTC.js.map} +0 -0
- /package/dist/{chunk-GBIC3VNA.js.map → chunk-7KGN7DV6.js.map} +0 -0
- /package/dist/{chunk-YZLUOZKR.js.map → chunk-7Q66A4CF.js.map} +0 -0
- /package/dist/{chunk-DRZ224RU.js.map → chunk-ANSZVKI2.js.map} +0 -0
- /package/dist/{chunk-N3RHX26N.js.map → chunk-AZZVSEP5.js.map} +0 -0
- /package/dist/{chunk-ZZHHKE2Q.js.map → chunk-ECXQX4EP.js.map} +0 -0
- /package/dist/{chunk-3OQIZPUX.js.map → chunk-EO3NEGWB.js.map} +0 -0
- /package/dist/{chunk-MOHSA65M.js.map → chunk-EZM5DNII.js.map} +0 -0
- /package/dist/{chunk-IKQVXZB5.js.map → chunk-GSPS6Y5U.js.map} +0 -0
- /package/dist/{chunk-HOLK4ZMT.js.map → chunk-II2GBWNW.js.map} +0 -0
- /package/dist/{chunk-M5HGULIY.js.map → chunk-OQODJ26H.js.map} +0 -0
- /package/dist/{chunk-MEWAFY6X.js.map → chunk-OT5IQMSI.js.map} +0 -0
- /package/dist/{chunk-Y22VQDVW.js.map → chunk-QB244ZDI.js.map} +0 -0
- /package/dist/{chunk-3T7ZP3TL.js.map → chunk-QL6ECU6Y.js.map} +0 -0
- /package/dist/{chunk-3XDPXOMS.js.map → chunk-R2SZYRB2.js.map} +0 -0
- /package/dist/{chunk-KVNA3HU2.js.map → chunk-XANQTIHS.js.map} +0 -0
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
AlertDescription,
|
|
12
12
|
Autocomplete,
|
|
13
13
|
BackButton,
|
|
14
|
+
CheckboxBlock,
|
|
14
15
|
DatePickerCalendar,
|
|
15
16
|
HoneypotField,
|
|
16
17
|
MAX_MONTH_OFFSET,
|
|
@@ -22,13 +23,13 @@ import {
|
|
|
22
23
|
SelectTrigger,
|
|
23
24
|
SelectValue,
|
|
24
25
|
Textarea
|
|
25
|
-
} from "../../chunk-
|
|
26
|
+
} from "../../chunk-YUHOKPKS.js";
|
|
26
27
|
import "../../chunk-L2SLFCXP.js";
|
|
27
28
|
import "../../chunk-BJXDHKUX.js";
|
|
28
29
|
import {
|
|
29
30
|
useHumanitySignals,
|
|
30
31
|
useToast
|
|
31
|
-
} from "../../chunk-
|
|
32
|
+
} from "../../chunk-EZM5DNII.js";
|
|
32
33
|
import "../../chunk-ZRIVCLPR.js";
|
|
33
34
|
import "../../chunk-GBON2OCG.js";
|
|
34
35
|
import {
|
|
@@ -42,10 +43,10 @@ import {
|
|
|
42
43
|
} from "../../chunk-T2NQSKH4.js";
|
|
43
44
|
import {
|
|
44
45
|
useIsHydrated
|
|
45
|
-
} from "../../chunk-
|
|
46
|
+
} from "../../chunk-4K7TCJ35.js";
|
|
46
47
|
import "../../chunk-5LIDR7HL.js";
|
|
47
48
|
import "../../chunk-XXMHLZ3Y.js";
|
|
48
|
-
import "../../chunk-
|
|
49
|
+
import "../../chunk-LPMDCQLL.js";
|
|
49
50
|
import "../../chunk-IMDG23LW.js";
|
|
50
51
|
import "../../chunk-W72U7OU7.js";
|
|
51
52
|
import {
|
|
@@ -53,7 +54,7 @@ import {
|
|
|
53
54
|
SquareAvatar,
|
|
54
55
|
StatusBadge,
|
|
55
56
|
formatDurationCompact
|
|
56
|
-
} from "../../chunk-
|
|
57
|
+
} from "../../chunk-ROQO355A.js";
|
|
57
58
|
import "../../chunk-MDKCTSDS.js";
|
|
58
59
|
import "../../chunk-MYBXCWEI.js";
|
|
59
60
|
import "../../chunk-OTX6XNSA.js";
|
|
@@ -76,7 +77,7 @@ import "../../chunk-3DTTSBDF.js";
|
|
|
76
77
|
import "../../chunk-DCHYNTHI.js";
|
|
77
78
|
|
|
78
79
|
// src/components/meeting-scheduler/index.tsx
|
|
79
|
-
import { useCallback as useCallback3, useEffect as
|
|
80
|
+
import { useCallback as useCallback3, useEffect as useEffect3, useMemo as useMemo5, useRef as useRef2, useState as useState4 } from "react";
|
|
80
81
|
|
|
81
82
|
// src/hooks/use-meeting-booking.ts
|
|
82
83
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
@@ -113,7 +114,7 @@ function isValidBcp47Locale(locale) {
|
|
|
113
114
|
return false;
|
|
114
115
|
}
|
|
115
116
|
}
|
|
116
|
-
function
|
|
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 = z.object(answers);
|
|
151
152
|
return z.object({
|
|
152
153
|
meetingId: z.string().min(1),
|
|
153
|
-
startTimeMs:
|
|
154
|
-
durationMs:
|
|
154
|
+
startTimeMs: slot.startTimeMs,
|
|
155
|
+
durationMs: slot.durationMs,
|
|
155
156
|
firstName: z.string().min(1, { message: "First name is required" }).max(255),
|
|
156
157
|
lastName: z.string().min(1, { message: "Last name is required" }).max(255),
|
|
157
158
|
email: z.string().email({ message: "Please enter a valid email address" }).max(255),
|
|
158
|
-
timezone:
|
|
159
|
+
timezone: slot.timezone,
|
|
159
160
|
locale: 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: z.number().int().positive().nullish(),
|
|
184
|
+
durationMs: z.number().int().positive().nullish(),
|
|
185
|
+
timezone: 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;
|
|
@@ -268,15 +276,28 @@ function useMeetingBooking(options) {
|
|
|
268
276
|
|
|
269
277
|
// src/components/meeting-scheduler/booking-form.tsx
|
|
270
278
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
271
|
-
import { useMemo } from "react";
|
|
279
|
+
import { Fragment, useEffect, useMemo, useState as useState2 } from "react";
|
|
272
280
|
import { useForm, Controller } from "react-hook-form";
|
|
273
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
281
|
+
import { Fragment as Fragment2, jsx, jsxs } from "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 = useMemo(() => formFields.filter(isSupportedFormField), [formFields]);
|
|
287
|
-
const schema = useMemo(
|
|
308
|
+
const schema = useMemo(
|
|
309
|
+
() => makeDeferredBookingSchema(supportedFields, legalConsent),
|
|
310
|
+
[supportedFields, legalConsent]
|
|
311
|
+
);
|
|
312
|
+
const consentDefaults = useMemo(
|
|
313
|
+
() => (legalConsent?.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
|
} = useForm({
|
|
294
326
|
resolver: zodResolver(schema),
|
|
295
327
|
defaultValues: {
|
|
296
328
|
meetingId,
|
|
297
|
-
|
|
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:
|
|
306
|
-
|
|
307
|
-
|
|
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
|
+
...initialValues ?? {}
|
|
309
341
|
}
|
|
310
342
|
});
|
|
311
|
-
const
|
|
312
|
-
|
|
343
|
+
const priorConsents = initialValues?.legalConsentResponses;
|
|
344
|
+
const [consented, setConsented] = useState2(initialValues?.hostConsent === true);
|
|
345
|
+
const [consentError, setConsentError] = useState2(null);
|
|
346
|
+
const consentMissing = Boolean(consent) && !consented;
|
|
347
|
+
useEffect(() => {
|
|
348
|
+
setValue(
|
|
349
|
+
"legalConsentResponses",
|
|
350
|
+
consentDefaults.map((next) => ({
|
|
351
|
+
...next,
|
|
352
|
+
consented: priorConsents?.find((r) => r.communicationTypeId === next.communicationTypeId)?.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(consent?.errorMessage ?? "Please agree to continue.");
|
|
367
|
+
return submitValid(event);
|
|
368
|
+
};
|
|
314
369
|
const fieldError = (name) => {
|
|
315
370
|
const err = errors.formFields?.[name];
|
|
316
371
|
return err?.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
|
-
|
|
321
|
-
/* @__PURE__ */ jsx(
|
|
322
|
-
/* @__PURE__ */ jsx(FieldWrapper, { label: "Email", htmlFor: "ms-email", error: errors.email?.message, children: /* @__PURE__ */ jsx(
|
|
375
|
+
const builtInFields = {
|
|
376
|
+
email: /* @__PURE__ */ jsx(FieldWrapper, { label: "Email", htmlFor: "ms-email", error: errors.email?.message, children: /* @__PURE__ */ jsx(
|
|
323
377
|
Input,
|
|
324
378
|
{
|
|
325
379
|
id: "ms-email",
|
|
@@ -332,129 +386,210 @@ function BookingForm({
|
|
|
332
386
|
...register("email")
|
|
333
387
|
}
|
|
334
388
|
) }),
|
|
335
|
-
/* @__PURE__ */
|
|
336
|
-
|
|
337
|
-
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__ */ jsx(FieldWrapper, { label: "Last Name", htmlFor: "ms-last-name", error: errors.lastName?.message, children: /* @__PURE__ */ jsx(
|
|
349
|
-
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__ */ jsxs(
|
|
362
|
-
FieldWrapper,
|
|
389
|
+
firstName: /* @__PURE__ */ jsx(FieldWrapper, { label: "First Name", htmlFor: "ms-first-name", error: errors.firstName?.message, children: /* @__PURE__ */ jsx(
|
|
390
|
+
Input,
|
|
363
391
|
{
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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__ */ jsx(FieldWrapper, { label: "Last Name", htmlFor: "ms-last-name", error: errors.lastName?.message, children: /* @__PURE__ */ jsx(
|
|
402
|
+
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__ */ jsxs(FieldWrapper, { label: field.label, htmlFor: `ms-q-${field.name}`, error: fieldError(field.name), children: [
|
|
415
|
+
field.type === "textarea" && /* @__PURE__ */ jsx(
|
|
416
|
+
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__ */ jsx(
|
|
424
|
+
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__ */ jsx(
|
|
432
|
+
Controller,
|
|
433
|
+
{
|
|
434
|
+
control,
|
|
435
|
+
name: `formFields.${field.name}`,
|
|
436
|
+
render: ({ field: rhf }) => field.type === "select" ? /* @__PURE__ */ jsxs(Select, { value: rhf.value ?? "", onValueChange: rhf.onChange, children: [
|
|
437
|
+
/* @__PURE__ */ jsx(SelectTrigger, { id: `ms-q-${field.name}`, children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select\u2026" }) }),
|
|
438
|
+
/* @__PURE__ */ jsx(SelectContent, { children: (field.options ?? []).map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt, children: opt }, opt)) })
|
|
439
|
+
] }) : /* @__PURE__ */ jsx(RadioGroup, { value: rhf.value ?? "", onValueChange: rhf.onChange, children: (field.options ?? []).map((opt) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
|
|
440
|
+
/* @__PURE__ */ jsx(RadioGroupItem, { id: `ms-q-${field.name}-${opt}`, value: opt }),
|
|
441
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: `ms-q-${field.name}-${opt}`, children: opt })
|
|
442
|
+
] }, opt)) })
|
|
443
|
+
}
|
|
444
|
+
),
|
|
445
|
+
field.type === "checkbox" && /* @__PURE__ */ jsx(
|
|
446
|
+
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__ */ jsx("div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: /* @__PURE__ */ jsx(
|
|
455
|
+
Checkbox,
|
|
378
456
|
{
|
|
379
457
|
id: `ms-q-${field.name}`,
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
}
|
|
383
|
-
),
|
|
384
|
-
(field.type === "select" || field.type === "radio") && /* @__PURE__ */ jsx(
|
|
385
|
-
Controller,
|
|
386
|
-
{
|
|
387
|
-
control,
|
|
388
|
-
name: `formFields.${field.name}`,
|
|
389
|
-
render: ({ field: rhf }) => field.type === "select" ? /* @__PURE__ */ jsxs(Select, { value: rhf.value ?? "", onValueChange: rhf.onChange, children: [
|
|
390
|
-
/* @__PURE__ */ jsx(SelectTrigger, { id: `ms-q-${field.name}`, children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select\u2026" }) }),
|
|
391
|
-
/* @__PURE__ */ jsx(SelectContent, { children: (field.options ?? []).map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt, children: opt }, opt)) })
|
|
392
|
-
] }) : /* @__PURE__ */ jsx(RadioGroup, { value: rhf.value ?? "", onValueChange: rhf.onChange, children: (field.options ?? []).map((opt) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
|
|
393
|
-
/* @__PURE__ */ jsx(RadioGroupItem, { id: `ms-q-${field.name}-${opt}`, value: opt }),
|
|
394
|
-
/* @__PURE__ */ jsx(Label, { htmlFor: `ms-q-${field.name}-${opt}`, children: opt })
|
|
395
|
-
] }, opt)) })
|
|
458
|
+
checked: Boolean(rhf.value),
|
|
459
|
+
onCheckedChange: (v) => rhf.onChange(v === true)
|
|
396
460
|
}
|
|
397
|
-
)
|
|
398
|
-
|
|
399
|
-
|
|
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 = (fieldRows ?? []).map((row) => row.filter((slot) => slotResolves(slot.name))).filter((row) => row.length > 0);
|
|
476
|
+
const submitButton = /* @__PURE__ */ jsx(
|
|
477
|
+
Button,
|
|
478
|
+
{
|
|
479
|
+
type: "submit",
|
|
480
|
+
loading: isSubmitting,
|
|
481
|
+
disabled: isSubmitting,
|
|
482
|
+
className: footerNote ? "md:w-60" : void 0,
|
|
483
|
+
children: submitLabel ?? "Confirm Booking"
|
|
484
|
+
}
|
|
485
|
+
);
|
|
486
|
+
return /* @__PURE__ */ jsxs("form", { onSubmit: submit, className: FORM_STACK, noValidate: true, children: [
|
|
487
|
+
/* @__PURE__ */ jsx(HoneypotField, { ...honeypotInputProps }),
|
|
488
|
+
fieldRows ? /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
489
|
+
placedRows.map((row, rowIndex) => /* @__PURE__ */ jsx(
|
|
490
|
+
"div",
|
|
491
|
+
{
|
|
492
|
+
className: "grid grid-cols-2 gap-[var(--spacing-system-m)] md:grid-cols-4",
|
|
493
|
+
children: row.map((slot) => /* @__PURE__ */ jsx(
|
|
494
|
+
"div",
|
|
400
495
|
{
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
//
|
|
405
|
-
//
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
496
|
+
className: cn(
|
|
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[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__ */ jsx(Fragment, { children: renderDeclaredField(field) }, field.name))
|
|
512
|
+
] }) : /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
513
|
+
builtInFields.email,
|
|
514
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-[var(--spacing-system-m)]", children: [
|
|
515
|
+
builtInFields.firstName,
|
|
516
|
+
builtInFields.lastName
|
|
517
|
+
] }),
|
|
518
|
+
supportedFields.map((field) => /* @__PURE__ */ jsx(Fragment, { children: renderDeclaredField(field) }, field.name))
|
|
519
|
+
] }),
|
|
520
|
+
consent && /* @__PURE__ */ jsx(
|
|
521
|
+
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: 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__ */ jsx(FieldWrapper, { error: errors.legalConsentResponses?.message, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-[var(--spacing-system-xs)]
|
|
427
|
-
/* @__PURE__ */ jsx("p", { className: "text-ods-text-secondary text-h6", children: legalConsent.processingConsentText }),
|
|
428
|
-
legalConsent.communicationConsentText && /* @__PURE__ */ jsx("p", { className: "text-ods-text-secondary text-h6", children: legalConsent.communicationConsentText }),
|
|
539
|
+
/* @__PURE__ */ jsx(FieldWrapper, { error: errors.legalConsentResponses?.message, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-[var(--spacing-system-xs)]", children: [
|
|
429
540
|
/* @__PURE__ */ jsx(
|
|
430
541
|
Controller,
|
|
431
542
|
{
|
|
432
543
|
control,
|
|
433
544
|
name: "legalConsentResponses",
|
|
434
|
-
render: ({ field: rhf }) => /* @__PURE__ */ jsx(
|
|
545
|
+
render: ({ field: rhf }) => /* @__PURE__ */ jsx(Fragment2, { children: legalConsent.communicationConsentCheckboxes.map((box, index) => {
|
|
435
546
|
const responses = rhf.value ?? [];
|
|
436
547
|
const current = responses.find((r) => r.communicationTypeId === box.communicationTypeId);
|
|
437
|
-
return
|
|
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__ */ jsx(
|
|
439
|
-
|
|
556
|
+
CheckboxBlock,
|
|
440
557
|
{
|
|
441
558
|
id: `ms-consent-${box.communicationTypeId}`,
|
|
442
559
|
checked: current?.consented ?? false,
|
|
443
560
|
onCheckedChange: (v) => rhf.onChange(
|
|
444
561
|
responses.map(
|
|
445
|
-
(r) => r.communicationTypeId === box.communicationTypeId ? { ...r, consented: v
|
|
562
|
+
(r) => r.communicationTypeId === box.communicationTypeId ? { ...r, consented: v } : r
|
|
446
563
|
)
|
|
447
|
-
)
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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__ */ jsx("p", { className: "text-ods-text-secondary text-h6", children: legalConsent.communicationConsentText }),
|
|
455
575
|
legalConsent.privacyPolicyText && /* @__PURE__ */ jsx("p", { className: "text-ods-text-secondary text-h6", children: legalConsent.privacyPolicyText })
|
|
456
576
|
] }) }),
|
|
457
|
-
/* @__PURE__ */
|
|
577
|
+
footerNote ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-[var(--spacing-system-m)]", children: [
|
|
578
|
+
/* @__PURE__ */ jsx("p", { className: "text-ods-text-secondary text-h6", children: footerNote }),
|
|
579
|
+
submitButton
|
|
580
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "flex", children: submitButton })
|
|
581
|
+
] });
|
|
582
|
+
}
|
|
583
|
+
function BookingFormSkeleton() {
|
|
584
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-[var(--spacing-system-l)] p-[var(--spacing-system-l)] lg:p-0", children: [
|
|
585
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-[var(--spacing-system-m)] md:grid-cols-2", children: [
|
|
586
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-[4.75rem] w-full" }),
|
|
587
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-[4.75rem] w-full" })
|
|
588
|
+
] }),
|
|
589
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-[4.75rem] w-full" }),
|
|
590
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-[7.75rem] w-full" }),
|
|
591
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-[4.25rem] w-full" }),
|
|
592
|
+
/* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-40" }) })
|
|
458
593
|
] });
|
|
459
594
|
}
|
|
460
595
|
|
|
@@ -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
|
}) {
|
|
@@ -585,8 +721,9 @@ function SchedulerContextPanel({
|
|
|
585
721
|
" hosts on this calendar"
|
|
586
722
|
] })
|
|
587
723
|
] }),
|
|
588
|
-
locked || durationsMs.length <= 1 ? (
|
|
589
|
-
// Post-selection, or a link that offers one
|
|
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__ */ jsxs3("p", { className: "shrink-0 text-ods-text-secondary text-h6", children: [
|
|
592
729
|
formatDurationCompact(selectedDurationMs / 1e3),
|
|
@@ -596,7 +733,7 @@ function SchedulerContextPanel({
|
|
|
596
733
|
] }),
|
|
597
734
|
title && /* @__PURE__ */ jsx3("p", { className: "text-ods-text-primary text-h3", children: title }),
|
|
598
735
|
description && /* @__PURE__ */ jsx3("p", { className: "text-ods-text-secondary text-h6", children: description }),
|
|
599
|
-
!locked && durationsMs.length > 1 && /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-[var(--spacing-system-xxs)]", children: [
|
|
736
|
+
!locked && !fixedDuration && durationsMs.length > 1 && /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-[var(--spacing-system-xxs)]", children: [
|
|
600
737
|
/* @__PURE__ */ jsx3("p", { className: FIELD_LABEL_CLASS, children: "Duration" }),
|
|
601
738
|
/* @__PURE__ */ jsx3("div", { className: "flex flex-wrap gap-[var(--spacing-system-xs)]", children: durationsMs.map((ms) => /* @__PURE__ */ jsx3(
|
|
602
739
|
Button,
|
|
@@ -639,7 +776,7 @@ function SchedulerContextPanel({
|
|
|
639
776
|
// src/components/meeting-scheduler/slot-picker.tsx
|
|
640
777
|
import { ChevronRight } from "lucide-react";
|
|
641
778
|
import { useCallback as useCallback2, useMemo as useMemo3 } from "react";
|
|
642
|
-
import { Fragment as
|
|
779
|
+
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
643
780
|
function dayKeyInZone(ms, timeZone) {
|
|
644
781
|
return new Intl.DateTimeFormat("en-CA", { timeZone, year: "numeric", month: "2-digit", day: "2-digit" }).format(
|
|
645
782
|
new Date(ms)
|
|
@@ -750,7 +887,7 @@ function SlotPickerSkeleton({ monthOffset = 0 }) {
|
|
|
750
887
|
] });
|
|
751
888
|
}
|
|
752
889
|
function TimeChipsSkeleton() {
|
|
753
|
-
return /* @__PURE__ */ jsxs4(
|
|
890
|
+
return /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
754
891
|
/* @__PURE__ */ jsx4("div", { className: COLUMN_HEADING_CLASS, children: /* @__PURE__ */ jsx4(Skeleton, { className: "inline-block h-4 w-40 align-middle" }) }),
|
|
755
892
|
/* @__PURE__ */ jsx4("div", { className: CHIP_GRID_CLASS, children: Array.from({ length: 16 }, (_, i) => (
|
|
756
893
|
// h-11 md:h-12 — the loaded chip's own default-size height.
|
|
@@ -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 = useMemo3(() => {
|
|
773
911
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -801,7 +939,7 @@ function SlotPicker({
|
|
|
801
939
|
}
|
|
802
940
|
)
|
|
803
941
|
] }),
|
|
804
|
-
/* @__PURE__ */ jsx4("div", { className: cn(COLUMN_STACK, COLUMN_BOX, "min-w-0 md:flex-1"), children: isLoading ? /* @__PURE__ */ jsx4(TimeChipsSkeleton, {}) : selectedDay ? /* @__PURE__ */ jsxs4(
|
|
942
|
+
/* @__PURE__ */ jsx4("div", { className: cn(COLUMN_STACK, COLUMN_BOX, "min-w-0 md:flex-1"), children: isLoading ? /* @__PURE__ */ jsx4(TimeChipsSkeleton, {}) : selectedDay ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
805
943
|
/* @__PURE__ */ jsx4("p", { className: COLUMN_HEADING_CLASS, children: new Intl.DateTimeFormat(void 0, {
|
|
806
944
|
weekday: "long",
|
|
807
945
|
month: "long",
|
|
@@ -813,7 +951,12 @@ function SlotPicker({
|
|
|
813
951
|
Button,
|
|
814
952
|
{
|
|
815
953
|
variant: isSelected ? void 0 : "outline",
|
|
816
|
-
|
|
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
|
},
|
|
@@ -849,7 +992,7 @@ function SlotPicker({
|
|
|
849
992
|
|
|
850
993
|
// src/components/meeting-scheduler/directory.tsx
|
|
851
994
|
import { ChevronRight as ChevronRight2 } from "lucide-react";
|
|
852
|
-
import { useEffect, useMemo as useMemo4, useState as
|
|
995
|
+
import { useEffect as useEffect2, useMemo as useMemo4, useState as useState3 } from "react";
|
|
853
996
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
854
997
|
function useNextAvailableLabel(ms) {
|
|
855
998
|
const hydrated = useIsHydrated();
|
|
@@ -926,11 +1069,11 @@ function MeetingSchedulerDirectory({
|
|
|
926
1069
|
contactHref,
|
|
927
1070
|
className
|
|
928
1071
|
}) {
|
|
929
|
-
const [data, setData] =
|
|
930
|
-
const [isLoading, setIsLoading] =
|
|
931
|
-
const [error, setError] =
|
|
932
|
-
const [page, setPage] =
|
|
933
|
-
|
|
1072
|
+
const [data, setData] = useState3(initialData);
|
|
1073
|
+
const [isLoading, setIsLoading] = useState3(initialData === null);
|
|
1074
|
+
const [error, setError] = useState3(null);
|
|
1075
|
+
const [page, setPage] = useState3(1);
|
|
1076
|
+
useEffect2(() => {
|
|
934
1077
|
if (initialData !== null) return void 0;
|
|
935
1078
|
const controller = new AbortController();
|
|
936
1079
|
let active = true;
|
|
@@ -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 = cn(
|
|
1023
1167
|
"overflow-hidden rounded-md border border-ods-border bg-ods-card",
|
|
1024
|
-
"md:flex md:flex-col"
|
|
1025
|
-
|
|
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 = cn(
|
|
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,8 +1210,9 @@ function HubSpotMeetingScheduler({
|
|
|
1063
1210
|
book,
|
|
1064
1211
|
isSubmitting
|
|
1065
1212
|
} = useMeetingBooking({ meetingId, apiBaseUrl, initialAvailability });
|
|
1213
|
+
const detailsFirst = flow === "details-first";
|
|
1066
1214
|
const hydrated = useIsHydrated();
|
|
1067
|
-
const [pickedTimezone, setTimezone] =
|
|
1215
|
+
const [pickedTimezone, setTimezone] = useState4(null);
|
|
1068
1216
|
const resolvedLocalTimezone = useMemo5(() => {
|
|
1069
1217
|
if (!hydrated) return null;
|
|
1070
1218
|
try {
|
|
@@ -1074,26 +1222,29 @@ function HubSpotMeetingScheduler({
|
|
|
1074
1222
|
}
|
|
1075
1223
|
}, [hydrated]);
|
|
1076
1224
|
const timezone = pickedTimezone ?? displayTimezone ?? resolvedLocalTimezone;
|
|
1077
|
-
const [step, setStep] =
|
|
1078
|
-
const [
|
|
1079
|
-
const
|
|
1080
|
-
const [
|
|
1081
|
-
const [
|
|
1082
|
-
const [
|
|
1225
|
+
const [step, setStep] = useState4(detailsFirst ? "details" : "slot");
|
|
1226
|
+
const [stash, setStash] = useState4(null);
|
|
1227
|
+
const formOnly = detailsFirst && step === "details";
|
|
1228
|
+
const [pickedDurationMs, setDurationMs] = useState4(null);
|
|
1229
|
+
const [pickedDay, setSelectedDay] = useState4(null);
|
|
1230
|
+
const [selectedSlot, setSelectedSlot] = useState4(null);
|
|
1231
|
+
const [confirmation, setConfirmation] = useState4(null);
|
|
1232
|
+
const [bookingError, setBookingError] = useState4(null);
|
|
1083
1233
|
const { honeypotInputProps, getSignals, resetSignals } = useHumanitySignals();
|
|
1084
1234
|
const { toast } = useToast();
|
|
1085
1235
|
const autoAdvanceCount = useRef2(0);
|
|
1086
|
-
const [machineFor, setMachineFor] =
|
|
1236
|
+
const [machineFor, setMachineFor] = useState4(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
|
+
useEffect3(() => {
|
|
1097
1248
|
autoAdvanceCount.current = 0;
|
|
1098
1249
|
}, [meetingId]);
|
|
1099
1250
|
const durations = useMemo5(() => availability?.durationsMs ?? [], [availability?.durationsMs]);
|
|
@@ -1116,7 +1267,7 @@ function HubSpotMeetingScheduler({
|
|
|
1116
1267
|
if (pickedDay && dayKeys.has(pickedDay)) return pickedDay;
|
|
1117
1268
|
return dayKeyInZone(inMonth[0], timezone);
|
|
1118
1269
|
}, [step, timezone, slots, pickedDay, monthOffset]);
|
|
1119
|
-
|
|
1270
|
+
useEffect3(() => {
|
|
1120
1271
|
if (step === "slot" && availability && !isFetchingAvailability && durationMs != null && slots.length === 0 && availability.hasMore && autoAdvanceCount.current < 3) {
|
|
1121
1272
|
autoAdvanceCount.current += 1;
|
|
1122
1273
|
setMonthOffset(monthOffset + 1);
|
|
@@ -1126,10 +1277,30 @@ function HubSpotMeetingScheduler({
|
|
|
1126
1277
|
setStep("slot");
|
|
1127
1278
|
setBookingError(null);
|
|
1128
1279
|
}, []);
|
|
1280
|
+
const backToDetails = useCallback3(() => {
|
|
1281
|
+
setStep("details");
|
|
1282
|
+
setBookingError(null);
|
|
1283
|
+
}, []);
|
|
1284
|
+
const stashDetails = useCallback3(
|
|
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 = useCallback3(
|
|
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");
|
|
@@ -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__ */ jsx6(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__ */ jsxs6("div", { className: cn(CARD_DEGRADED_CLASS, flowHeight, className), children: [
|
|
1333
|
+
/* @__PURE__ */ jsx6("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__ */ jsx6("div", { className: cn(CARD_CLASS, className), children: /* @__PURE__ */ jsxs6("div", { className: CARD_INNER_CLASS, children: [
|
|
1159
|
-
/* @__PURE__ */ jsx6(ContextPanelSkeleton, { onBack, className: CONTEXT_PANEL_CLASS }),
|
|
1160
|
-
/* @__PURE__ */ jsx6("div", { className: ACTION_PANEL_CLASS, children: /* @__PURE__ */ jsx6(SlotPickerSkeleton, { monthOffset }) })
|
|
1338
|
+
return /* @__PURE__ */ jsx6("div", { className: cn(CARD_CLASS, flowHeight, formOnly && "bg-ods-bg", className), children: /* @__PURE__ */ jsxs6("div", { className: CARD_INNER_CLASS, children: [
|
|
1339
|
+
!formOnly && /* @__PURE__ */ jsx6(ContextPanelSkeleton, { onBack, className: CONTEXT_PANEL_CLASS }),
|
|
1340
|
+
/* @__PURE__ */ jsx6("div", { className: ACTION_PANEL_CLASS, children: detailsFirst && step === "details" ? /* @__PURE__ */ jsx6(BookingFormSkeleton, {}) : /* @__PURE__ */ jsx6(SlotPickerSkeleton, { monthOffset }) })
|
|
1161
1341
|
] }) });
|
|
1162
1342
|
}
|
|
1163
|
-
if (availabilityError || !availability)
|
|
1164
|
-
return /* @__PURE__ */ jsxs6("div", { className: cn(CARD_DEGRADED_CLASS, className), children: [
|
|
1165
|
-
/* @__PURE__ */ jsx6("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__ */ jsxs6("div", { className: cn(CARD_DEGRADED_CLASS, className), children: [
|
|
1345
|
+
return /* @__PURE__ */ jsxs6("div", { className: cn(CARD_DEGRADED_CLASS, flowHeight, className), children: [
|
|
1171
1346
|
/* @__PURE__ */ jsx6("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__ */ jsx6("div", { className: cn(CARD_CLASS, className), children: /* @__PURE__ */ jsxs6("div", { className: CARD_INNER_CLASS, children: [
|
|
1176
|
-
/* @__PURE__ */ jsx6(
|
|
1350
|
+
return /* @__PURE__ */ jsx6("div", { className: cn(CARD_CLASS, flowHeight, formOnly && "bg-ods-bg", className), children: /* @__PURE__ */ jsxs6("div", { className: CARD_INNER_CLASS, children: [
|
|
1351
|
+
!formOnly && /* @__PURE__ */ jsx6(
|
|
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__ */ jsx6("div", { className: ACTION_PANEL_CLASS, children: step === "confirmed" && confirmation && timezone ? /* @__PURE__ */ jsx6("div", { className: cn("flex flex-1 flex-col", PANEL_STEP_CLASS), children: /* @__PURE__ */ jsx6(Confirmation, { confirmation, timezone }) }) : step === "details" &&
|
|
1199
|
-
|
|
1374
|
+
/* @__PURE__ */ jsx6("div", { className: ACTION_PANEL_CLASS, children: step === "confirmed" && confirmation && timezone ? /* @__PURE__ */ jsx6("div", { className: cn("flex flex-1 flex-col", PANEL_STEP_CLASS), children: /* @__PURE__ */ jsx6(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__ */ jsxs6("div", { className: cn("flex flex-1 flex-col gap-[var(--spacing-system-m)]", PANEL_STEP_CLASS), children: [
|
|
1380
|
+
selectedSlot != null && durationMs != null && timezone != null && /* @__PURE__ */ jsxs6("p", { className: "text-ods-text-primary text-h4", children: [
|
|
1200
1381
|
new Intl.DateTimeFormat(void 0, {
|
|
1201
1382
|
timeZone: timezone,
|
|
1202
1383
|
weekday: "long",
|
|
@@ -1211,15 +1392,19 @@ function HubSpotMeetingScheduler({
|
|
|
1211
1392
|
formatDurationCompact(durationMs / 1e3)
|
|
1212
1393
|
] }),
|
|
1213
1394
|
/* @__PURE__ */ jsx6(
|
|
1214
|
-
|
|
1395
|
+
DetailsForm,
|
|
1215
1396
|
{
|
|
1216
1397
|
availability,
|
|
1217
1398
|
meetingId,
|
|
1218
|
-
startTimeMs: selectedSlot,
|
|
1219
|
-
durationMs,
|
|
1399
|
+
startTimeMs: selectedSlot ?? void 0,
|
|
1400
|
+
durationMs: 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 ? stash?.payload : void 0,
|
|
1221
1406
|
isSubmitting,
|
|
1222
|
-
onSubmit: handleSubmit,
|
|
1407
|
+
onSubmit: detailsFirst ? stashDetails : handleSubmit,
|
|
1223
1408
|
honeypotInputProps,
|
|
1224
1409
|
getSignals
|
|
1225
1410
|
}
|
|
@@ -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
|
-
|
|
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 ? (
|
|
@@ -1276,7 +1480,10 @@ function HubSpotMeetingScheduler({
|
|
|
1276
1480
|
] }) });
|
|
1277
1481
|
}
|
|
1278
1482
|
export {
|
|
1483
|
+
BookingForm,
|
|
1484
|
+
BookingFormSkeleton,
|
|
1279
1485
|
HubSpotMeetingScheduler,
|
|
1486
|
+
MEETING_SCHEDULER_DETAILS_FIRST_H,
|
|
1280
1487
|
MEETING_SCHEDULER_H,
|
|
1281
1488
|
MeetingSchedulerDirectory,
|
|
1282
1489
|
MeetingSchedulerDirectoryRowSkeleton
|