@asksable/site-connector 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,23 +1,25 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useMemo, useRef, useState } from 'react';
2
+ import { useEffect, useMemo, useRef, useState, } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
4
  import { loadStripe } from '@stripe/stripe-js';
5
- import { Elements, PaymentElement, useElements, useStripe } from '@stripe/react-stripe-js';
5
+ import { Elements, PaymentElement, useElements, useStripe, } from '@stripe/react-stripe-js';
6
6
  import { Skeleton } from 'boneyard-js/react';
7
7
  // Side-effect: registers all named bones with the boneyard runtime.
8
8
  // Regenerate by running `npx boneyard-js build` against a host site
9
9
  // that mounts <BookingWidgetPanel /> in its loaded state.
10
10
  import './bones/registry.js';
11
11
  import { BookingWidgetPlaceholder } from './booking-widget-placeholder.js';
12
- import { useSableSiteClient, useSableSiteConfig, useTranslation } from './provider.js';
13
- import { DEFAULT_LOCALE, localeToIntl, pickLocaleField } from './translations.js';
12
+ import { useSableSiteAnalytics, useSableSiteClient, useSableSiteConfig, useTranslation, } from './provider.js';
13
+ import { DEFAULT_LOCALE, localeToIntl, pickLocaleField, } from './translations.js';
14
14
  const stripePromises = new Map();
15
15
  function getStripePromise(publishableKey, connectAccountId) {
16
16
  const key = `${publishableKey}:${connectAccountId}`;
17
17
  const cached = stripePromises.get(key);
18
18
  if (cached)
19
19
  return cached;
20
- const promise = loadStripe(publishableKey, { stripeAccount: connectAccountId });
20
+ const promise = loadStripe(publishableKey, {
21
+ stripeAccount: connectAccountId,
22
+ });
21
23
  stripePromises.set(key, promise);
22
24
  return promise;
23
25
  }
@@ -52,6 +54,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
52
54
  const client = useSableSiteClient();
53
55
  const { siteSlug } = useSableSiteConfig();
54
56
  const { t, locale } = useTranslation();
57
+ const analytics = useSableSiteAnalytics();
55
58
  const intlLocale = localeToIntl(locale);
56
59
  const [setup, setSetup] = useState(null);
57
60
  const [isSetupLoading, setIsSetupLoading] = useState(true);
@@ -104,7 +107,11 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
104
107
  // Dev-only: force viewState to 'details' when previewing a payment
105
108
  // variant, since the payment panel renders inside the details form.
106
109
  useEffect(() => {
107
- if (__devForceState === 'payment-full' || __devForceState === 'payment-deposit') {
110
+ analytics.capture('sable_booking_widget_viewed', { mode });
111
+ }, [analytics, mode]);
112
+ useEffect(() => {
113
+ if (__devForceState === 'payment-full' ||
114
+ __devForceState === 'payment-deposit') {
108
115
  setViewState('details');
109
116
  }
110
117
  }, [__devForceState]);
@@ -177,7 +184,9 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
177
184
  })
178
185
  .catch((nextError) => {
179
186
  if (!cancelled) {
180
- setError(nextError instanceof Error ? nextError.message : 'Unable to load booking setup.');
187
+ setError(nextError instanceof Error
188
+ ? nextError.message
189
+ : 'Unable to load booking setup.');
181
190
  }
182
191
  })
183
192
  .finally(() => {
@@ -189,9 +198,12 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
189
198
  cancelled = true;
190
199
  };
191
200
  }, [client, siteSlug]);
192
- const selectedService = useMemo(() => setup?.services.find((service) => service._id === selectedServiceId) ?? null, [selectedServiceId, setup]);
201
+ const selectedService = useMemo(() => setup?.services.find((service) => service._id === selectedServiceId) ??
202
+ null, [selectedServiceId, setup]);
193
203
  const selectedServiceRequiresSlot = selectedService?.publicBookingMode !== 'async';
194
- const selectedServicePath = selectedServiceRequiresSlot ? 'scheduled' : 'async';
204
+ const selectedServicePath = selectedServiceRequiresSlot
205
+ ? 'scheduled'
206
+ : 'async';
195
207
  const selectedServiceHasIntakeForm = hasIntakeFormSections(selectedService);
196
208
  const isIntakeComplete = useMemo(() => !selectedService?.intakeForm ||
197
209
  areRequiredIntakeFieldsComplete(selectedService.intakeForm, intakeResponses, selectedServicePath), [intakeResponses, selectedService?.intakeForm, selectedServicePath]);
@@ -217,7 +229,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
217
229
  const uncategorizedKey = '__uncategorized__';
218
230
  for (const service of visibleServices) {
219
231
  const category = service.categoryId != null
220
- ? categoriesById.get(service.categoryId) ?? null
232
+ ? (categoriesById.get(service.categoryId) ?? null)
221
233
  : null;
222
234
  const key = category?._id ?? uncategorizedKey;
223
235
  const existing = groups.get(key);
@@ -286,7 +298,8 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
286
298
  // wiped on the first render before the staff list arrives.
287
299
  if (availableStaff.length === 0)
288
300
  return;
289
- if (selectedStaffId && !availableStaff.some((staffMember) => staffMember._id === selectedStaffId)) {
301
+ if (selectedStaffId &&
302
+ !availableStaff.some((staffMember) => staffMember._id === selectedStaffId)) {
290
303
  setSelectedStaffId(null);
291
304
  }
292
305
  }, [availableStaff, selectedStaffId]);
@@ -351,7 +364,9 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
351
364
  if (!cancelled) {
352
365
  setAvailabilityByDate(new Map());
353
366
  setSelectedDate(null);
354
- setError(nextError instanceof Error ? nextError.message : t('calendarLoadError'));
367
+ setError(nextError instanceof Error
368
+ ? nextError.message
369
+ : t('calendarLoadError'));
355
370
  }
356
371
  })
357
372
  .finally(() => {
@@ -362,7 +377,15 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
362
377
  return () => {
363
378
  cancelled = true;
364
379
  };
365
- }, [calendarMonth, client, selectedDate, selectedService?.publicBookingMode, selectedServiceId, selectedStaffId, siteSlug]);
380
+ }, [
381
+ calendarMonth,
382
+ client,
383
+ selectedDate,
384
+ selectedService?.publicBookingMode,
385
+ selectedServiceId,
386
+ selectedStaffId,
387
+ siteSlug,
388
+ ]);
366
389
  useEffect(() => {
367
390
  if (!selectedServiceId || selectedService?.publicBookingMode === 'async') {
368
391
  return;
@@ -375,7 +398,14 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
375
398
  calendarMonth: nextMonth,
376
399
  cacheRef: availabilityCacheRef,
377
400
  });
378
- }, [calendarMonth, client, selectedService?.publicBookingMode, selectedServiceId, selectedStaffId, siteSlug]);
401
+ }, [
402
+ calendarMonth,
403
+ client,
404
+ selectedService?.publicBookingMode,
405
+ selectedServiceId,
406
+ selectedStaffId,
407
+ siteSlug,
408
+ ]);
379
409
  useEffect(() => {
380
410
  setSelectedSlot(null);
381
411
  setPendingSlotKey(null);
@@ -394,7 +424,12 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
394
424
  else {
395
425
  setViewState('slots');
396
426
  }
397
- }, [selectedDate, selectedService?.publicBookingMode, selectedServiceId, selectedStaffId]);
427
+ }, [
428
+ selectedDate,
429
+ selectedService?.publicBookingMode,
430
+ selectedServiceId,
431
+ selectedStaffId,
432
+ ]);
398
433
  useEffect(() => {
399
434
  setIntakeResponses({});
400
435
  setQuote(null);
@@ -424,7 +459,9 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
424
459
  })
425
460
  .catch((nextError) => {
426
461
  if (!cancelled) {
427
- setError(nextError instanceof Error ? nextError.message : 'Unable to calculate price.');
462
+ setError(nextError instanceof Error
463
+ ? nextError.message
464
+ : 'Unable to calculate price.');
428
465
  }
429
466
  })
430
467
  .finally(() => {
@@ -436,7 +473,14 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
436
473
  cancelled = true;
437
474
  window.clearTimeout(handle);
438
475
  };
439
- }, [client, intakeResponses, isIntakeComplete, selectedService?.pricingMode, selectedServiceId, siteSlug]);
476
+ }, [
477
+ client,
478
+ intakeResponses,
479
+ isIntakeComplete,
480
+ selectedService?.pricingMode,
481
+ selectedServiceId,
482
+ siteSlug,
483
+ ]);
440
484
  useEffect(() => {
441
485
  return () => {
442
486
  if (!holdId) {
@@ -576,9 +620,15 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
576
620
  }
577
621
  return set;
578
622
  }, [availabilityByDate, selectedDate]);
579
- const selectedDateSlots = selectedDate ? filteredAvailabilityByDate.get(selectedDate) ?? [] : [];
580
- const selectedHeldStaff = availableStaff.find((staffMember) => staffMember._id === heldStaffId) ?? selectedStaff ?? null;
581
- const holdSecondsRemaining = holdExpiresAt !== null ? Math.max(0, Math.floor((holdExpiresAt - holdNow) / 1000)) : null;
623
+ const selectedDateSlots = selectedDate
624
+ ? (filteredAvailabilityByDate.get(selectedDate) ?? [])
625
+ : [];
626
+ const selectedHeldStaff = availableStaff.find((staffMember) => staffMember._id === heldStaffId) ??
627
+ selectedStaff ??
628
+ null;
629
+ const holdSecondsRemaining = holdExpiresAt !== null
630
+ ? Math.max(0, Math.floor((holdExpiresAt - holdNow) / 1000))
631
+ : null;
582
632
  const monthOptions = useMemo(() => getMonthOptions(calendarMonth, 4, intlLocale), [calendarMonth, intlLocale]);
583
633
  const calendarDays = useMemo(() => buildCalendarDays(calendarMonth), [calendarMonth]);
584
634
  // Mobile 4-step gates. canAdvanceStepN = "the user can move PAST
@@ -623,11 +673,15 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
623
673
  const slotKey = `${slot.time}-${slot.endTime}`;
624
674
  const isPending = pendingSlotKey === slotKey;
625
675
  const isActive = isPending ||
626
- (selectedSlot?.time === slot.time && selectedSlot?.endTime === slot.endTime);
627
- return (_jsx("button", { type: "button", className: `bw-slot${isActive ? ' is-active' : ''}${isPending ? ' is-pending' : ''}`, style: { '--bw-slot-i': index }, onClick: () => void handleSlotSelect(slot), disabled: isSubmitting, children: isPending ? t('slotSecuring') : formatTimeLabel(slot.time, intlLocale) }, slotKey));
676
+ (selectedSlot?.time === slot.time &&
677
+ selectedSlot?.endTime === slot.endTime);
678
+ return (_jsx("button", { type: "button", className: `bw-slot${isActive ? ' is-active' : ''}${isPending ? ' is-pending' : ''}`, style: { '--bw-slot-i': index }, onClick: () => void handleSlotSelect(slot), disabled: isSubmitting, children: isPending
679
+ ? t('slotSecuring')
680
+ : formatTimeLabel(slot.time, intlLocale) }, slotKey));
628
681
  }) })) : (_jsx("p", { className: "bw-no-slots", children: t('slotsEmptyForDate') }))) : null }, slotsAreaKey));
629
682
  const canSubmit = Boolean(selectedService &&
630
- (!selectedServiceRequiresSlot || (selectedDate && selectedSlot && holdId)) &&
683
+ (!selectedServiceRequiresSlot ||
684
+ (selectedDate && selectedSlot && holdId)) &&
631
685
  isIntakeComplete &&
632
686
  (selectedService.pricingMode !== 'calculated' || quote) &&
633
687
  customerName.trim() &&
@@ -668,7 +722,7 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
668
722
  return null;
669
723
  const visibleBlockers = submitBlockers.slice(0, 5);
670
724
  const hiddenCount = submitBlockers.length - visibleBlockers.length;
671
- return (_jsxs("div", { className: "bw-submit-help", role: "status", "aria-live": "polite", children: [_jsx("span", { className: "bw-submit-help-title", children: isQuoteLoading ? t('helpCalculating') : t('helpComplete') }), !isQuoteLoading && visibleBlockers.length > 0 ? (_jsxs("ul", { children: [visibleBlockers.map((blocker) => (_jsx("li", { children: blocker }, blocker))), hiddenCount > 0 ? _jsx("li", { children: t('helpMoreFields', { count: hiddenCount }) }) : null] })) : null] }));
725
+ return (_jsxs("div", { className: "bw-submit-help", role: "status", "aria-live": "polite", children: [_jsx("span", { className: "bw-submit-help-title", children: isQuoteLoading ? t('helpCalculating') : t('helpComplete') }), !isQuoteLoading && visibleBlockers.length > 0 ? (_jsxs("ul", { children: [visibleBlockers.map((blocker) => (_jsx("li", { children: blocker }, blocker))), hiddenCount > 0 ? (_jsx("li", { children: t('helpMoreFields', { count: hiddenCount }) })) : null] })) : null] }));
672
726
  }
673
727
  function renderContactFields(idSuffix) {
674
728
  const nameId = `bw-name${idSuffix}`;
@@ -689,6 +743,12 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
689
743
  return (_jsxs(_Fragment, { children: [contactFields, intakeFields] }));
690
744
  }
691
745
  function handleServiceSelect(service) {
746
+ analytics.capture('sable_booking_service_selected', {
747
+ service_id: service._id,
748
+ service_name: pickLocaleField(service, 'name', locale) ?? service.name,
749
+ booking_mode: service.publicBookingMode ?? 'scheduled',
750
+ requires_payment: service.requiresPayment === true,
751
+ });
692
752
  if (holdId) {
693
753
  void client
694
754
  .releasePublicBookingHold({ siteSlug, holdId, sessionToken })
@@ -810,7 +870,8 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
810
870
  async function handleConfirmBooking() {
811
871
  if (!selectedServiceId ||
812
872
  !selectedService ||
813
- (selectedServiceRequiresSlot && (!selectedDate || !selectedSlot || !holdId))) {
873
+ (selectedServiceRequiresSlot &&
874
+ (!selectedDate || !selectedSlot || !holdId))) {
814
875
  return;
815
876
  }
816
877
  setIsSubmitting(true);
@@ -832,6 +893,11 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
832
893
  try {
833
894
  await onRescheduleSubmit({ newStartTime, newEndTime });
834
895
  setSuccess(t('successRescheduleConfirmed'));
896
+ analytics.capture('sable_booking_rescheduled', {
897
+ service_id: selectedServiceId,
898
+ service_name: pickLocaleField(selectedService, 'name', locale) ??
899
+ selectedService.name,
900
+ });
835
901
  setMobileStep(4);
836
902
  }
837
903
  catch (nextError) {
@@ -849,11 +915,16 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
849
915
  siteSlug,
850
916
  serviceId: selectedServiceId,
851
917
  staffMemberId: selectedServiceRequiresSlot
852
- ? heldStaffId ?? selectedStaffId ?? selectedSlot?.availableStaffIds[0]
918
+ ? (heldStaffId ??
919
+ selectedStaffId ??
920
+ selectedSlot?.availableStaffIds[0])
853
921
  : undefined,
854
922
  startTime: newStartTime,
855
923
  endTime: newEndTime,
856
- timezone: selectedHeldStaff?.timezone ?? availableStaff[0]?.timezone ?? setup?.workspaceTimezone ?? 'UTC',
924
+ timezone: selectedHeldStaff?.timezone ??
925
+ availableStaff[0]?.timezone ??
926
+ setup?.workspaceTimezone ??
927
+ 'UTC',
857
928
  deliveryMethod: selectedService.deliveryMethods[0] ?? 'in-person',
858
929
  customerName: customerName.trim(),
859
930
  customerEmail: customerEmail.trim(),
@@ -862,15 +933,34 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
862
933
  intakeResponses,
863
934
  quotedTotalCents: quote?.totalCents,
864
935
  bookingHoldId: selectedServiceRequiresSlot ? holdId : undefined,
865
- bookingSessionToken: selectedServiceRequiresSlot ? sessionToken : undefined,
936
+ bookingSessionToken: selectedServiceRequiresSlot
937
+ ? sessionToken
938
+ : undefined,
866
939
  });
867
940
  if (created.payment) {
941
+ analytics.capture('sable_booking_payment_started', {
942
+ appointment_id: created.appointmentId,
943
+ service_id: selectedServiceId,
944
+ service_name: pickLocaleField(selectedService, 'name', locale) ??
945
+ selectedService.name,
946
+ amount_cents: created.payment.amountCents,
947
+ currency: created.payment.currency,
948
+ });
868
949
  setPayment(created.payment);
869
950
  setPaymentAppointmentId(created.appointmentId);
870
951
  setError(null);
871
952
  return;
872
953
  }
873
954
  setSuccess(t('successBookingConfirmed'));
955
+ analytics.capture('sable_booking_created', {
956
+ appointment_id: created.appointmentId,
957
+ service_id: selectedServiceId,
958
+ service_name: pickLocaleField(selectedService, 'name', locale) ??
959
+ selectedService.name,
960
+ booking_mode: selectedService.publicBookingMode ?? 'scheduled',
961
+ requires_payment: selectedService.requiresPayment === true,
962
+ quoted_total_cents: quote?.totalCents ?? null,
963
+ });
874
964
  setSelectedSlot(null);
875
965
  setPendingSlotKey(null);
876
966
  setHoldId(null);
@@ -887,7 +977,9 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
887
977
  setMobileStep(4);
888
978
  }
889
979
  catch (nextError) {
890
- setError(nextError instanceof Error ? nextError.message : t('errorConfirmFailed'));
980
+ setError(nextError instanceof Error
981
+ ? nextError.message
982
+ : t('errorConfirmFailed'));
891
983
  }
892
984
  finally {
893
985
  setIsSubmitting(false);
@@ -909,22 +1001,30 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
909
1001
  }, children: t('cancelledCta') })] }) }));
910
1002
  }
911
1003
  if (success || forcedState === 'success') {
912
- return (_jsx("section", { className: "bw", children: _jsxs("div", { className: "bw-done", children: [_jsx("div", { className: "bw-done-icon", children: _jsx(CheckIcon, {}) }), _jsx("h3", { className: "bw-done-title", children: isReschedule ? t('successTitleReschedule') : t('successTitleCreate') }), _jsx("p", { className: "bw-done-text", children: isReschedule ? t('successBodyReschedule') : t('successBodyCreate') }), isReschedule ? null : (_jsx("button", { type: "button", className: "bw-btn-primary", onClick: () => {
1004
+ return (_jsx("section", { className: "bw", children: _jsxs("div", { className: "bw-done", children: [_jsx("div", { className: "bw-done-icon", children: _jsx(CheckIcon, {}) }), _jsx("h3", { className: "bw-done-title", children: isReschedule
1005
+ ? t('successTitleReschedule')
1006
+ : t('successTitleCreate') }), _jsx("p", { className: "bw-done-text", children: isReschedule ? t('successBodyReschedule') : t('successBodyCreate') }), isReschedule ? null : (_jsx("button", { type: "button", className: "bw-btn-primary", onClick: () => {
913
1007
  window.location.assign(successRedirectHref);
914
1008
  }, children: t('successCtaBackHome') }))] }) }));
915
1009
  }
916
- return (_jsx(Skeleton, { name: "booking-widget", loading: false, children: _jsxs("section", { className: "bw", "data-view-state": viewState, ref: widgetRootRef, children: [mobileHeader ? _jsx("div", { className: "bw-mobile-header", children: mobileHeader }) : null, _jsxs("div", { className: "bw-header", children: [_jsxs("div", { className: "bw-header-row", children: [_jsx("h2", { className: "bw-title bw-title--desktop", children: title ||
1010
+ return (_jsx(Skeleton, { name: "booking-widget", loading: false, children: _jsxs("section", { className: "bw", "data-view-state": viewState, ref: widgetRootRef, children: [mobileHeader ? (_jsx("div", { className: "bw-mobile-header", children: mobileHeader })) : null, _jsxs("div", { className: "bw-header", children: [_jsxs("div", { className: "bw-header-row", children: [_jsx("h2", { className: "bw-title bw-title--desktop", children: title ||
917
1011
  (isReschedule
918
1012
  ? rescheduleContext?.customerName
919
- ? t('rescheduleTitleNamed', { name: rescheduleContext.customerName })
1013
+ ? t('rescheduleTitleNamed', {
1014
+ name: rescheduleContext.customerName,
1015
+ })
920
1016
  : t('rescheduleTitle')
921
1017
  : t('pageTitle')) }), _jsx("h2", { className: "bw-title bw-title--mobile", children: isReschedule
922
1018
  ? rescheduleContext?.customerName
923
- ? t('rescheduleTitleNamed', { name: rescheduleContext.customerName })
1019
+ ? t('rescheduleTitleNamed', {
1020
+ name: rescheduleContext.customerName,
1021
+ })
924
1022
  : t('rescheduleTitle')
925
1023
  : mobileStepTitle(mobileStep, t) }), mobileStep > 1 ? (_jsx("div", { className: "bw-progress", "aria-hidden": "true", children: (selectedServiceRequiresSlot
926
1024
  ? MOBILE_PROGRESS_STEPS_SCHEDULED
927
- : MOBILE_PROGRESS_STEPS_ASYNC).map((step) => (_jsx("span", { className: `bw-dot${mobileStep >= step ? ' is-filled' : ''}` }, step))) })) : null] }), description ? _jsx("p", { className: "bw-description", children: description }) : null] }), _jsxs("div", { className: "bw-content", children: [_jsx("div", { className: "bw-body", "data-mobile-step": mobileStep, children: _jsxs("div", { className: "bw-body-inner", children: [_jsxs("div", { className: "bw-col bw-col--left", children: [_jsxs("div", { className: "bw-step-1", children: [_jsx("div", { className: "bw-service-picker", children: selectedService && !isEditingService ? (_jsxs("div", { className: "bw-svc-selected", children: [_jsxs("div", { className: "bw-svc-selected-header", children: [_jsx("label", { className: "bw-label", children: t('selectedService') }), _jsx("button", { type: "button", className: "bw-svc-change", onClick: () => setIsEditingService(true), children: t('btnChange') })] }), _jsxs("div", { className: "bw-svc-row bw-svc-row--readonly", children: [selectedService.image ? (_jsxs("span", { className: "bw-svc-image is-checked", children: [_jsx("img", { src: selectedService.image.url, alt: selectedService.image.alt ?? pickLocaleField(selectedService, 'name', locale) ?? selectedService.name, loading: "lazy" }), _jsx("span", { className: "bw-svc-image-badge", children: _jsx(CheckIcon, {}) })] })) : (_jsx("span", { className: "bw-check is-checked", children: _jsx(CheckIcon, {}) })), _jsxs("span", { className: "bw-svc-info", children: [_jsx("span", { className: "bw-svc-name", children: pickLocaleField(selectedService, 'name', locale) ?? selectedService.name }), pickLocaleField(selectedService, 'description', locale) ?? selectedService.description ? (_jsx("span", { className: "bw-svc-desc", children: pickLocaleField(selectedService, 'description', locale) ?? selectedService.description })) : null, _jsxs("span", { className: "bw-svc-meta-row", children: [_jsx("span", { className: "bw-svc-meta", children: formatDuration(selectedService.durationMinutes) }), _jsx("span", { className: "bw-svc-meta-dot", "aria-hidden": "true", children: "\u00B7" }), _jsx("span", { className: "bw-svc-price", children: formatServicePrice(selectedService, undefined, intlLocale) })] })] })] })] })) : (_jsxs(_Fragment, { children: [_jsx("label", { className: "bw-label", children: t('selectService') }), _jsx("div", { className: "bw-svc-scroll is-open", children: _jsx("div", { className: "bw-svc-scroll-wrap", children: _jsx("div", { className: "bw-svc-scroll-inner", children: serviceGroups.map((group) => (_jsxs("div", { className: "bw-svc-group", children: [group.categoryName ? (_jsx("div", { className: "bw-svc-category", children: group.categoryName })) : null, group.services.map((service) => {
1025
+ : MOBILE_PROGRESS_STEPS_ASYNC).map((step) => (_jsx("span", { className: `bw-dot${mobileStep >= step ? ' is-filled' : ''}` }, step))) })) : null] }), description ? _jsx("p", { className: "bw-description", children: description }) : null] }), _jsxs("div", { className: "bw-content", children: [_jsx("div", { className: "bw-body", "data-mobile-step": mobileStep, children: _jsxs("div", { className: "bw-body-inner", children: [_jsxs("div", { className: "bw-col bw-col--left", children: [_jsxs("div", { className: "bw-step-1", children: [_jsx("div", { className: "bw-service-picker", children: selectedService && !isEditingService ? (_jsxs("div", { className: "bw-svc-selected", children: [_jsxs("div", { className: "bw-svc-selected-header", children: [_jsx("label", { className: "bw-label", children: t('selectedService') }), _jsx("button", { type: "button", className: "bw-svc-change", onClick: () => setIsEditingService(true), children: t('btnChange') })] }), _jsxs("div", { className: "bw-svc-row bw-svc-row--readonly", children: [selectedService.image ? (_jsxs("span", { className: "bw-svc-image is-checked", children: [_jsx("img", { src: selectedService.image.url, alt: selectedService.image.alt ??
1026
+ pickLocaleField(selectedService, 'name', locale) ??
1027
+ selectedService.name, loading: "lazy" }), _jsx("span", { className: "bw-svc-image-badge", children: _jsx(CheckIcon, {}) })] })) : (_jsx("span", { className: "bw-check is-checked", children: _jsx(CheckIcon, {}) })), _jsxs("span", { className: "bw-svc-info", children: [_jsx("span", { className: "bw-svc-name", children: pickLocaleField(selectedService, 'name', locale) ?? selectedService.name }), (pickLocaleField(selectedService, 'description', locale) ?? selectedService.description) ? (_jsx("span", { className: "bw-svc-desc", children: pickLocaleField(selectedService, 'description', locale) ?? selectedService.description })) : null, _jsxs("span", { className: "bw-svc-meta-row", children: [_jsx("span", { className: "bw-svc-meta", children: formatDuration(selectedService.durationMinutes) }), _jsx("span", { className: "bw-svc-meta-dot", "aria-hidden": "true", children: "\u00B7" }), _jsx("span", { className: "bw-svc-price", children: formatServicePrice(selectedService, undefined, intlLocale) })] })] })] })] })) : (_jsxs(_Fragment, { children: [_jsx("label", { className: "bw-label", children: t('selectService') }), _jsx("div", { className: "bw-svc-scroll is-open", children: _jsx("div", { className: "bw-svc-scroll-wrap", children: _jsx("div", { className: "bw-svc-scroll-inner", children: serviceGroups.map((group) => (_jsxs("div", { className: "bw-svc-group", children: [group.categoryName ? (_jsx("div", { className: "bw-svc-category", children: group.categoryName })) : null, group.services.map((service) => {
928
1028
  const isActive = selectedServiceId === service._id;
929
1029
  return (_jsxs("button", { type: "button", className: "bw-svc-row", onMouseEnter: () => {
930
1030
  void prefetchAvailability({
@@ -944,8 +1044,12 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
944
1044
  });
945
1045
  }, onClick: () => {
946
1046
  handleServiceSelect(service);
947
- }, children: [service.image ? (_jsxs("span", { className: `bw-svc-image${isActive ? ' is-checked' : ''}`, children: [_jsx("img", { src: service.image.url, alt: service.image.alt ?? pickLocaleField(service, 'name', locale) ?? service.name, loading: "lazy" }), isActive ? (_jsx("span", { className: "bw-svc-image-badge", children: _jsx(CheckIcon, {}) })) : null] })) : (_jsx("span", { className: `bw-check${isActive ? ' is-checked' : ''}`, children: isActive ? _jsx(CheckIcon, {}) : null })), _jsxs("span", { className: "bw-svc-info", children: [_jsx("span", { className: "bw-svc-name", children: pickLocaleField(service, 'name', locale) ?? service.name }), pickLocaleField(service, 'description', locale) ?? service.description ? (_jsx("span", { className: "bw-svc-desc", children: pickLocaleField(service, 'description', locale) ?? service.description })) : null, _jsxs("span", { className: "bw-svc-meta-row", children: [_jsx("span", { className: "bw-svc-meta", children: formatDuration(service.durationMinutes) }), _jsx("span", { className: "bw-svc-meta-dot", "aria-hidden": "true", children: "\u00B7" }), _jsx("span", { className: "bw-svc-price", children: formatServicePrice(service, undefined, intlLocale) })] })] })] }, service._id));
948
- })] }, group.key))) }) }) })] })) }), selectedService && selectedServiceRequiresSlot && !isEditingService ? (_jsxs("div", { className: "bw-provider-section", children: [_jsx("div", { className: "bw-section-divider" }), _jsx("label", { className: "bw-label", children: t('selectProvider') }), providerRow] })) : null] }), _jsxs("div", { className: "bw-step-2", children: [_jsx("p", { className: "bw-step-2-heading", children: t('chooseYourService') }), _jsx("div", { className: "bw-step-2-divider" }), serviceGroups.map((group) => (_jsxs("div", { className: "bw-svc-group", children: [group.categoryName ? (_jsx("div", { className: "bw-svc-category", children: group.categoryName })) : null, group.services.map((service) => {
1047
+ }, children: [service.image ? (_jsxs("span", { className: `bw-svc-image${isActive ? ' is-checked' : ''}`, children: [_jsx("img", { src: service.image.url, alt: service.image.alt ??
1048
+ pickLocaleField(service, 'name', locale) ??
1049
+ service.name, loading: "lazy" }), isActive ? (_jsx("span", { className: "bw-svc-image-badge", children: _jsx(CheckIcon, {}) })) : null] })) : (_jsx("span", { className: `bw-check${isActive ? ' is-checked' : ''}`, children: isActive ? _jsx(CheckIcon, {}) : null })), _jsxs("span", { className: "bw-svc-info", children: [_jsx("span", { className: "bw-svc-name", children: pickLocaleField(service, 'name', locale) ?? service.name }), (pickLocaleField(service, 'description', locale) ?? service.description) ? (_jsx("span", { className: "bw-svc-desc", children: pickLocaleField(service, 'description', locale) ?? service.description })) : null, _jsxs("span", { className: "bw-svc-meta-row", children: [_jsx("span", { className: "bw-svc-meta", children: formatDuration(service.durationMinutes) }), _jsx("span", { className: "bw-svc-meta-dot", "aria-hidden": "true", children: "\u00B7" }), _jsx("span", { className: "bw-svc-price", children: formatServicePrice(service, undefined, intlLocale) })] })] })] }, service._id));
1050
+ })] }, group.key))) }) }) })] })) }), selectedService &&
1051
+ selectedServiceRequiresSlot &&
1052
+ !isEditingService ? (_jsxs("div", { className: "bw-provider-section", children: [_jsx("div", { className: "bw-section-divider" }), _jsx("label", { className: "bw-label", children: t('selectProvider') }), providerRow] })) : null] }), _jsxs("div", { className: "bw-step-2", children: [_jsx("p", { className: "bw-step-2-heading", children: t('chooseYourService') }), _jsx("div", { className: "bw-step-2-divider" }), serviceGroups.map((group) => (_jsxs("div", { className: "bw-svc-group", children: [group.categoryName ? (_jsx("div", { className: "bw-svc-category", children: group.categoryName })) : null, group.services.map((service) => {
949
1053
  const isActive = selectedServiceId === service._id;
950
1054
  return (_jsxs("div", { children: [_jsxs("button", { type: "button", className: "bw-svc-row bw-svc-row--full", onMouseEnter: () => {
951
1055
  void prefetchAvailability({
@@ -965,12 +1069,16 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
965
1069
  });
966
1070
  }, onClick: () => {
967
1071
  handleServiceSelect(service);
968
- }, children: [service.image ? (_jsxs("span", { className: `bw-svc-image bw-svc-image--lg${isActive ? ' is-checked' : ''}`, children: [_jsx("img", { src: service.image.url, alt: service.image.alt ?? pickLocaleField(service, 'name', locale) ?? service.name, loading: "lazy" }), isActive ? (_jsx("span", { className: "bw-svc-image-badge", children: _jsx(CheckIcon, {}) })) : null] })) : (_jsx("span", { className: `bw-check bw-check--lg${isActive ? ' is-checked' : ''}`, children: isActive ? _jsx(CheckIcon, {}) : null })), _jsxs("span", { className: "bw-svc-info", children: [_jsx("span", { className: "bw-svc-name", children: pickLocaleField(service, 'name', locale) ?? service.name }), pickLocaleField(service, 'description', locale) ?? service.description ? (_jsx("span", { className: "bw-svc-desc", children: pickLocaleField(service, 'description', locale) ?? service.description })) : null, _jsxs("span", { className: "bw-svc-meta-row", children: [_jsx("span", { className: "bw-svc-meta", children: formatDuration(service.durationMinutes) }), _jsx("span", { className: "bw-svc-meta-dot", "aria-hidden": "true", children: "\u00B7" }), _jsx("span", { className: "bw-svc-price", children: formatServicePrice(service, undefined, intlLocale) })] })] })] }), _jsx("div", { className: "bw-row-divider" })] }, service._id));
1072
+ }, children: [service.image ? (_jsxs("span", { className: `bw-svc-image bw-svc-image--lg${isActive ? ' is-checked' : ''}`, children: [_jsx("img", { src: service.image.url, alt: service.image.alt ??
1073
+ pickLocaleField(service, 'name', locale) ??
1074
+ service.name, loading: "lazy" }), isActive ? (_jsx("span", { className: "bw-svc-image-badge", children: _jsx(CheckIcon, {}) })) : null] })) : (_jsx("span", { className: `bw-check bw-check--lg${isActive ? ' is-checked' : ''}`, children: isActive ? _jsx(CheckIcon, {}) : null })), _jsxs("span", { className: "bw-svc-info", children: [_jsx("span", { className: "bw-svc-name", children: pickLocaleField(service, 'name', locale) ??
1075
+ service.name }), (pickLocaleField(service, 'description', locale) ?? service.description) ? (_jsx("span", { className: "bw-svc-desc", children: pickLocaleField(service, 'description', locale) ?? service.description })) : null, _jsxs("span", { className: "bw-svc-meta-row", children: [_jsx("span", { className: "bw-svc-meta", children: formatDuration(service.durationMinutes) }), _jsx("span", { className: "bw-svc-meta-dot", "aria-hidden": "true", children: "\u00B7" }), _jsx("span", { className: "bw-svc-price", children: formatServicePrice(service, undefined, intlLocale) })] })] })] }), _jsx("div", { className: "bw-row-divider" })] }, service._id));
969
1076
  })] }, group.key)))] })] }), _jsxs("div", { className: "bw-col bw-col--center", children: [_jsxs("div", { className: "bw-cal-card", ref: calCardRef, children: [_jsxs("div", { className: "bw-cal-header", children: [_jsxs("div", { className: "bw-month-dropdown", children: [_jsxs("button", { type: "button", className: "bw-month-btn", onClick: () => setMonthOpen((current) => !current), children: [_jsx("span", { children: formatMonthLabel(calendarMonth, intlLocale) }), _jsx(ChevronDownIcon, {})] }), monthOpen ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "bw-month-overlay", "aria-label": t('closeMonthPicker'), onClick: () => setMonthOpen(false) }), _jsx("div", { className: "bw-month-list", children: monthOptions.map((option) => (_jsx("button", { type: "button", className: `bw-month-option${option.value === optionCurrentValue(calendarMonth) ? ' is-active' : ''}`, onClick: () => {
970
1077
  setCalendarMonth(option.date);
971
1078
  setMonthOpen(false);
972
1079
  }, children: option.label }, option.value))) })] })) : null] }), _jsxs("div", { className: "bw-cal-navs", children: [_jsx("button", { type: "button", className: "bw-cal-nav", onMouseEnter: () => {
973
- if (!sameMonth(calendarMonth, startOfMonth(new Date())) && selectedServiceId) {
1080
+ if (!sameMonth(calendarMonth, startOfMonth(new Date())) &&
1081
+ selectedServiceId) {
974
1082
  void prefetchAvailability({
975
1083
  client,
976
1084
  siteSlug,
@@ -980,7 +1088,8 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
980
1088
  });
981
1089
  }
982
1090
  }, onClick: () => setCalendarMonth((current) => addMonths(current, -1)), disabled: sameMonth(calendarMonth, startOfMonth(new Date())), "aria-label": t('prevMonth'), children: _jsx(ChevronLeftIcon, {}) }), _jsx("button", { type: "button", className: "bw-cal-nav", onMouseEnter: () => {
983
- if (!sameMonth(calendarMonth, addMonths(startOfMonth(new Date()), 3)) && selectedServiceId) {
1091
+ if (!sameMonth(calendarMonth, addMonths(startOfMonth(new Date()), 3)) &&
1092
+ selectedServiceId) {
984
1093
  void prefetchAvailability({
985
1094
  client,
986
1095
  siteSlug,
@@ -1010,22 +1119,53 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
1010
1119
  isSelected ? 'is-selected' : '',
1011
1120
  isAvailable && !isPast ? 'is-available' : '',
1012
1121
  isPast ? 'is-disabled' : '',
1013
- !isAvailable && isCurrentMonth && !isPast ? 'is-blocked' : '',
1014
- dateKey === formatDateKey(startOfDay(new Date())) ? 'is-today' : '',
1122
+ !isAvailable && isCurrentMonth && !isPast
1123
+ ? 'is-blocked'
1124
+ : '',
1125
+ dateKey === formatDateKey(startOfDay(new Date()))
1126
+ ? 'is-today'
1127
+ : '',
1015
1128
  ]
1016
1129
  .filter(Boolean)
1017
1130
  .join(' ');
1018
1131
  return (_jsx("button", { type: "button", className: className, disabled: !isCurrentMonth || isPast || !isAvailable, onClick: () => {
1019
1132
  setSelectedDate(dateKey);
1020
1133
  setSelectedSlot(null);
1021
- setMobileStep((current) => (current < 2 ? 2 : current));
1134
+ setMobileStep((current) => current < 2 ? 2 : current);
1022
1135
  }, children: day.getDate() }, dateKey));
1023
- }) }), !selectedService ? (_jsx("p", { className: "bw-cal-prompt", children: t('calendarSelectServicePrompt') })) : null, _jsxs("div", { className: "bw-timezone", children: [_jsx(GlobeIcon, {}), _jsx("span", { children: selectedHeldStaff?.timezone ?? selectedStaff?.timezone ?? setup?.workspaceTimezone ?? setup?.staff?.[0]?.timezone ?? 'UTC' })] })] }), selectedService && !isEditingService ? (_jsxs("div", { className: "bw-mobile-card bw-provider-section--mobile", children: [_jsx("label", { className: "bw-label", children: t('selectProvider') }), providerRow] })) : null, selectedService && selectedDate ? (_jsxs("div", { className: "bw-mobile-card bw-slots-mobile", children: [_jsx("label", { className: "bw-label", children: t('selectTimePrompt') }), slotsArea] })) : null] }), _jsx("div", { className: "bw-col bw-col--review", "aria-hidden": mobileStep !== 4, children: selectedService ? (_jsxs("div", { className: "bw-summary bw-summary--review", children: [_jsx("span", { className: "bw-summary-title", children: isReschedule ? t('summaryTitleReschedule') : t('summaryTitleCreate') }), holdSecondsRemaining !== null ? (_jsx("div", { className: "bw-summary-rows", children: _jsxs("div", { className: "bw-summary-row bw-summary-row--hold", "aria-live": "polite", children: [_jsx("span", { children: t('summaryReservationHold') }), _jsx("span", { className: "bw-summary-val bw-summary-val--hold", children: formatHoldCountdown(holdSecondsRemaining) })] }) })) : null, _jsxs("div", { className: "bw-summary-group", children: [_jsx("span", { className: "bw-summary-subhead", children: t('reviewBookingDetails') }), _jsxs("div", { className: "bw-summary-rows", children: [isReschedule && rescheduleContext ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryFormerTime') }), _jsx("span", { className: "bw-summary-val", style: { ...summaryValStyle, textDecoration: 'line-through', opacity: 0.55 }, children: formatFormerSlot(rescheduleContext.formerStartTime, rescheduleContext.formerEndTime, intlLocale) })] })) : null, serviceChanged && formerService ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryFormerService') }), _jsx("span", { className: "bw-summary-val", style: { ...summaryValStyle, textDecoration: 'line-through', opacity: 0.55 }, children: formerService.name })] })) : null, staffChanged ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryFormerStaff') }), _jsx("span", { className: "bw-summary-val", style: { ...summaryValStyle, textDecoration: 'line-through', opacity: 0.55 }, children: formerStaffName ?? t('providerAny') })] })) : null, _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryService') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: pickLocaleField(selectedService, 'name', locale) ?? selectedService.name })] }), _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryProvider') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: selectedHeldStaff?.name ?? selectedStaff?.name ?? t('providerAny') })] }), selectedDate ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryDate') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatReadableDate(selectedDate, intlLocale) })] })) : null, selectedSlot ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryTime') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatTimeLabel(selectedSlot.time, intlLocale) })] })) : null, _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryDuration') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatDuration(selectedService.durationMinutes) })] })] })] }), _jsxs("div", { className: "bw-summary-group", children: [_jsx("span", { className: "bw-summary-subhead", children: t('reviewYourDetails') }), _jsxs("div", { className: "bw-summary-rows", children: [_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('contactFullName') }), _jsx("span", { className: "bw-summary-val", children: customerName.trim() || t('reviewNotProvided') })] }), _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('contactEmail') }), _jsx("span", { className: "bw-summary-val", children: customerEmail.trim() || t('reviewNotProvided') })] }), _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('contactPhone') }), _jsx("span", { className: "bw-summary-val", children: customerPhone.trim() || t('reviewNotProvided') })] })] })] }), (() => {
1136
+ }) }), !selectedService ? (_jsx("p", { className: "bw-cal-prompt", children: t('calendarSelectServicePrompt') })) : null, _jsxs("div", { className: "bw-timezone", children: [_jsx(GlobeIcon, {}), _jsx("span", { children: selectedHeldStaff?.timezone ??
1137
+ selectedStaff?.timezone ??
1138
+ setup?.workspaceTimezone ??
1139
+ setup?.staff?.[0]?.timezone ??
1140
+ 'UTC' })] })] }), selectedService && !isEditingService ? (_jsxs("div", { className: "bw-mobile-card bw-provider-section--mobile", children: [_jsx("label", { className: "bw-label", children: t('selectProvider') }), providerRow] })) : null, selectedService && selectedDate ? (_jsxs("div", { className: "bw-mobile-card bw-slots-mobile", children: [_jsx("label", { className: "bw-label", children: t('selectTimePrompt') }), slotsArea] })) : null] }), _jsx("div", { className: "bw-col bw-col--review", "aria-hidden": mobileStep !== 4, children: selectedService ? (_jsxs("div", { className: "bw-summary bw-summary--review", children: [_jsx("span", { className: "bw-summary-title", children: isReschedule
1141
+ ? t('summaryTitleReschedule')
1142
+ : t('summaryTitleCreate') }), holdSecondsRemaining !== null ? (_jsx("div", { className: "bw-summary-rows", children: _jsxs("div", { className: "bw-summary-row bw-summary-row--hold", "aria-live": "polite", children: [_jsx("span", { children: t('summaryReservationHold') }), _jsx("span", { className: "bw-summary-val bw-summary-val--hold", children: formatHoldCountdown(holdSecondsRemaining) })] }) })) : null, _jsxs("div", { className: "bw-summary-group", children: [_jsx("span", { className: "bw-summary-subhead", children: t('reviewBookingDetails') }), _jsxs("div", { className: "bw-summary-rows", children: [isReschedule && rescheduleContext ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryFormerTime') }), _jsx("span", { className: "bw-summary-val", style: {
1143
+ ...summaryValStyle,
1144
+ textDecoration: 'line-through',
1145
+ opacity: 0.55,
1146
+ }, children: formatFormerSlot(rescheduleContext.formerStartTime, rescheduleContext.formerEndTime, intlLocale) })] })) : null, serviceChanged && formerService ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryFormerService') }), _jsx("span", { className: "bw-summary-val", style: {
1147
+ ...summaryValStyle,
1148
+ textDecoration: 'line-through',
1149
+ opacity: 0.55,
1150
+ }, children: formerService.name })] })) : null, staffChanged ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryFormerStaff') }), _jsx("span", { className: "bw-summary-val", style: {
1151
+ ...summaryValStyle,
1152
+ textDecoration: 'line-through',
1153
+ opacity: 0.55,
1154
+ }, children: formerStaffName ?? t('providerAny') })] })) : null, _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryService') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: pickLocaleField(selectedService, 'name', locale) ??
1155
+ selectedService.name })] }), _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryProvider') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: selectedHeldStaff?.name ??
1156
+ selectedStaff?.name ??
1157
+ t('providerAny') })] }), selectedDate ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryDate') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatReadableDate(selectedDate, intlLocale) })] })) : null, selectedSlot ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryTime') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatTimeLabel(selectedSlot.time, intlLocale) })] })) : null, _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryDuration') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatDuration(selectedService.durationMinutes) })] })] })] }), _jsxs("div", { className: "bw-summary-group", children: [_jsx("span", { className: "bw-summary-subhead", children: t('reviewYourDetails') }), _jsxs("div", { className: "bw-summary-rows", children: [_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('contactFullName') }), _jsx("span", { className: "bw-summary-val", children: customerName.trim() || t('reviewNotProvided') })] }), _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('contactEmail') }), _jsx("span", { className: "bw-summary-val", children: customerEmail.trim() || t('reviewNotProvided') })] }), _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('contactPhone') }), _jsx("span", { className: "bw-summary-val", children: customerPhone.trim() || t('reviewNotProvided') })] })] })] }), (() => {
1024
1158
  const intakeRows = buildIntakeReviewRows(selectedService.intakeForm, intakeResponses, selectedServicePath, locale, t);
1025
1159
  if (intakeRows.length === 0)
1026
1160
  return null;
1027
1161
  return (_jsxs("div", { className: "bw-summary-group", children: [_jsx("span", { className: "bw-summary-subhead", children: t('reviewAdditionalInfo') }), _jsx("div", { className: "bw-summary-rows", children: intakeRows.map((row) => (_jsxs("div", { className: `bw-summary-row${row.multiline ? ' bw-summary-row--stack' : ''}`, children: [_jsx("span", { children: row.label }), _jsx("span", { className: "bw-summary-val", children: row.value })] }, row.key))) })] }));
1028
- })(), customerNotes.trim() ? (_jsxs("div", { className: "bw-summary-group", children: [_jsx("span", { className: "bw-summary-subhead", children: isReschedule ? t('notesLabelReschedule') : t('reviewNotesSection') }), _jsx("p", { className: "bw-summary-notes", children: customerNotes.trim() })] })) : null, _jsx("div", { className: "bw-summary-rows bw-summary-rows--total", children: _jsxs("div", { className: "bw-summary-row bw-summary-total", children: [_jsx("span", { children: isQuoteLoading ? t('summaryCalculating') : t('summaryEstimatedTotal') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatServicePrice(selectedService, quote, intlLocale) })] }) })] })) : null }), _jsx("div", { className: "bw-col bw-col--right", children: _jsx("div", { className: "bw-right-scroll", children: _jsx("div", { className: "bw-right-inner", children: _jsxs("div", { className: "bw-right-stage", children: [_jsxs("div", { className: `bw-pane bw-pane--slots${viewState === 'slots' ? ' is-active' : ' is-hidden'}`, "aria-hidden": viewState !== 'slots', children: [_jsxs("div", { className: "bw-slots-heading bw-slots-heading--sticky", children: [_jsx("span", { children: t('slotsHeading') }), selectedDateSlots.length > 0 ? (_jsx("span", { className: "bw-slots-count", children: selectedDateSlots.length })) : null] }), _jsx("div", { className: "bw-slots-desktop", children: slotsArea })] }), _jsxs("div", { className: `bw-pane bw-pane--details${viewState === 'details' ? ' is-active' : ' is-hidden'}`, "aria-hidden": viewState !== 'details', children: [selectedServiceRequiresSlot ? (_jsxs("button", { type: "button", className: "bw-back-btn", onClick: () => void handleBackToSlots(), children: [_jsx(ArrowLeftIcon, {}), _jsx("span", { children: t('backToDifferentTime') })] })) : (_jsxs("button", { type: "button", className: "bw-back-btn", onClick: handleBackToServicePicker, children: [_jsx(ArrowLeftIcon, {}), _jsx("span", { children: t('backToDifferentService') })] })), _jsxs("div", { className: "bw-form", children: [serviceWarning ? _jsx(ServiceWarningCallout, { warning: serviceWarning }) : null, renderIntakeAndContact('bw-intake', ''), renderNotesField('bw-notes', t('notesLabel'), t('notesPlaceholder')), selectedService ? (_jsxs("div", { className: "bw-summary", children: [_jsx("span", { className: "bw-summary-title", children: isReschedule ? t('summaryTitleReschedule') : t('summaryTitleCreate') }), _jsxs("div", { className: "bw-summary-rows", children: [holdSecondsRemaining !== null ? (_jsxs("div", { className: "bw-summary-row bw-summary-row--hold", "aria-live": "polite", children: [_jsx("span", { children: t('summaryReservationHold') }), _jsx("span", { className: "bw-summary-val bw-summary-val--hold", children: formatHoldCountdown(holdSecondsRemaining) })] })) : null, isReschedule && rescheduleContext ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryFormerTime') }), _jsx("span", { className: "bw-summary-val", style: {
1162
+ })(), customerNotes.trim() ? (_jsxs("div", { className: "bw-summary-group", children: [_jsx("span", { className: "bw-summary-subhead", children: isReschedule
1163
+ ? t('notesLabelReschedule')
1164
+ : t('reviewNotesSection') }), _jsx("p", { className: "bw-summary-notes", children: customerNotes.trim() })] })) : null, _jsx("div", { className: "bw-summary-rows bw-summary-rows--total", children: _jsxs("div", { className: "bw-summary-row bw-summary-total", children: [_jsx("span", { children: isQuoteLoading
1165
+ ? t('summaryCalculating')
1166
+ : t('summaryEstimatedTotal') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatServicePrice(selectedService, quote, intlLocale) })] }) })] })) : null }), _jsx("div", { className: "bw-col bw-col--right", children: _jsx("div", { className: "bw-right-scroll", children: _jsx("div", { className: "bw-right-inner", children: _jsxs("div", { className: "bw-right-stage", children: [_jsxs("div", { className: `bw-pane bw-pane--slots${viewState === 'slots' ? ' is-active' : ' is-hidden'}`, "aria-hidden": viewState !== 'slots', children: [_jsxs("div", { className: "bw-slots-heading bw-slots-heading--sticky", children: [_jsx("span", { children: t('slotsHeading') }), selectedDateSlots.length > 0 ? (_jsx("span", { className: "bw-slots-count", children: selectedDateSlots.length })) : null] }), _jsx("div", { className: "bw-slots-desktop", children: slotsArea })] }), _jsxs("div", { className: `bw-pane bw-pane--details${viewState === 'details' ? ' is-active' : ' is-hidden'}`, "aria-hidden": viewState !== 'details', children: [selectedServiceRequiresSlot ? (_jsxs("button", { type: "button", className: "bw-back-btn", onClick: () => void handleBackToSlots(), children: [_jsx(ArrowLeftIcon, {}), _jsx("span", { children: t('backToDifferentTime') })] })) : (_jsxs("button", { type: "button", className: "bw-back-btn", onClick: handleBackToServicePicker, children: [_jsx(ArrowLeftIcon, {}), _jsx("span", { children: t('backToDifferentService') })] })), _jsxs("div", { className: "bw-form", children: [serviceWarning ? (_jsx(ServiceWarningCallout, { warning: serviceWarning })) : null, renderIntakeAndContact('bw-intake', ''), renderNotesField('bw-notes', t('notesLabel'), t('notesPlaceholder')), selectedService ? (_jsxs("div", { className: "bw-summary", children: [_jsx("span", { className: "bw-summary-title", children: isReschedule
1167
+ ? t('summaryTitleReschedule')
1168
+ : t('summaryTitleCreate') }), _jsxs("div", { className: "bw-summary-rows", children: [holdSecondsRemaining !== null ? (_jsxs("div", { className: "bw-summary-row bw-summary-row--hold", "aria-live": "polite", children: [_jsx("span", { children: t('summaryReservationHold') }), _jsx("span", { className: "bw-summary-val bw-summary-val--hold", children: formatHoldCountdown(holdSecondsRemaining) })] })) : null, isReschedule && rescheduleContext ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryFormerTime') }), _jsx("span", { className: "bw-summary-val", style: {
1029
1169
  ...summaryValStyle,
1030
1170
  textDecoration: 'line-through',
1031
1171
  opacity: 0.55,
@@ -1037,7 +1177,11 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
1037
1177
  ...summaryValStyle,
1038
1178
  textDecoration: 'line-through',
1039
1179
  opacity: 0.55,
1040
- }, children: formerStaffName ?? t('providerAny') })] })) : null, _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryService') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: pickLocaleField(selectedService, 'name', locale) ?? selectedService.name })] }), _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryProvider') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: selectedHeldStaff?.name ?? selectedStaff?.name ?? t('providerAny') })] }), selectedDate ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryDate') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatReadableDate(selectedDate, intlLocale) })] })) : null, selectedSlot ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryTime') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatTimeLabel(selectedSlot.time, intlLocale) })] })) : null, _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryDuration') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatDuration(selectedService.durationMinutes) })] }), _jsxs("div", { className: "bw-summary-row bw-summary-total", children: [_jsx("span", { children: isQuoteLoading ? t('summaryCalculating') : t('summaryEstimatedTotal') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatServicePrice(selectedService, quote, intlLocale) })] })] })] })) : null, error ? _jsx("div", { className: "bw-error", children: error }) : null, renderSubmitHelp(), payment ? (_jsx(StripePaymentBlock, { payment: payment, appointmentId: paymentAppointmentId, showInlineButton: false, actionTarget: mobilePaymentActionTarget, onSuccess: () => {
1180
+ }, children: formerStaffName ?? t('providerAny') })] })) : null, _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryService') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: pickLocaleField(selectedService, 'name', locale) ?? selectedService.name })] }), _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryProvider') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: selectedHeldStaff?.name ??
1181
+ selectedStaff?.name ??
1182
+ t('providerAny') })] }), selectedDate ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryDate') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatReadableDate(selectedDate, intlLocale) })] })) : null, selectedSlot ? (_jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryTime') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatTimeLabel(selectedSlot.time, intlLocale) })] })) : null, _jsxs("div", { className: "bw-summary-row", children: [_jsx("span", { children: t('summaryDuration') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatDuration(selectedService.durationMinutes) })] }), _jsxs("div", { className: "bw-summary-row bw-summary-total", children: [_jsx("span", { children: isQuoteLoading
1183
+ ? t('summaryCalculating')
1184
+ : t('summaryEstimatedTotal') }), _jsx("span", { className: "bw-summary-val", style: summaryValStyle, children: formatServicePrice(selectedService, quote, intlLocale) })] })] })] })) : null, error ? (_jsx("div", { className: "bw-error", children: error })) : null, renderSubmitHelp(), payment ? (_jsx(StripePaymentBlock, { payment: payment, appointmentId: paymentAppointmentId, showInlineButton: false, actionTarget: mobilePaymentActionTarget, onSuccess: () => {
1041
1185
  setSuccess(t('successPaymentReceived'));
1042
1186
  setPayment(null);
1043
1187
  }, onError: setError })) : (_jsxs("button", { type: "button", className: `bw-confirm-btn${!canSubmit || isQuoteLoading ? ' is-disabled' : ''}`, "aria-disabled": !canSubmit || isQuoteLoading, onClick: handleConfirmAttempt, children: [_jsx("span", { children: isSubmitting
@@ -1048,7 +1192,23 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
1048
1192
  ? t('btnConfirmReschedule')
1049
1193
  : selectedServiceRequiresPayment
1050
1194
  ? t('btnContinueToPayment')
1051
- : t('btnConfirmBooking') }), !isSubmitting ? _jsx(ArrowRightIcon, {}) : null] }))] })] })] }) }) }) })] }) }), _jsxs("div", { className: "bw-details-view", children: [_jsx("div", { className: "bw-details-summary", children: selectedService ? (_jsxs(_Fragment, { children: [selectedServiceRequiresSlot ? (_jsxs("button", { type: "button", className: "bw-back-btn bw-back-btn--details", onClick: () => void handleBackToSlots(), children: [_jsx(ArrowLeftIcon, {}), _jsx("span", { children: t('backToDifferentTime') })] })) : (_jsxs("button", { type: "button", className: "bw-back-btn bw-back-btn--details", onClick: handleBackToServicePicker, children: [_jsx(ArrowLeftIcon, {}), _jsx("span", { children: t('backToDifferentService') })] })), _jsx("h3", { className: "bw-details-service", children: pickLocaleField(selectedService, 'name', locale) ?? selectedService.name }), pickLocaleField(selectedService, 'description', locale) ?? selectedService.description ? (_jsx("p", { className: "bw-details-desc", children: pickLocaleField(selectedService, 'description', locale) ?? selectedService.description })) : null, _jsxs("div", { className: "bw-details-meta", children: [isReschedule && rescheduleContext ? (_jsxs("div", { className: "bw-details-meta-row bw-details-meta-row--strike", children: [_jsx("span", { className: "bw-details-meta-icon", children: _jsx(CalendarIcon, {}) }), _jsxs("div", { className: "bw-details-meta-text", children: [_jsx("span", { className: "bw-details-meta-label", children: t('summaryFormerTime') }), _jsx("span", { className: "bw-details-meta-value", children: formatFormerSlot(rescheduleContext.formerStartTime, rescheduleContext.formerEndTime, intlLocale) })] })] })) : null, selectedDate && selectedSlot ? (_jsxs("div", { className: "bw-details-meta-row", children: [_jsx("span", { className: "bw-details-meta-icon", children: _jsx(CalendarIcon, {}) }), _jsxs("div", { className: "bw-details-meta-text", children: [_jsx("span", { className: "bw-details-meta-label", children: isReschedule ? t('summaryNewTime') : t('summaryWhen') }), _jsxs("span", { className: "bw-details-meta-value", children: [formatReadableDate(selectedDate, intlLocale), _jsx("br", {}), formatTimeLabel(selectedSlot.time, intlLocale), " \u2013 ", formatTimeLabel(selectedSlot.endTime, intlLocale)] })] })] })) : null, _jsxs("div", { className: "bw-details-meta-row", children: [_jsx("span", { className: "bw-details-meta-icon", children: _jsx(ClockIcon, {}) }), _jsx("span", { className: "bw-details-meta-value", children: formatDuration(selectedService.durationMinutes) })] }), _jsxs("div", { className: "bw-details-meta-row", children: [_jsx("span", { className: "bw-details-meta-icon", children: _jsx(UserIcon, {}) }), _jsx("span", { className: "bw-details-meta-value", children: selectedHeldStaff?.name ?? selectedStaff?.name ?? t('providerAny') })] }), _jsxs("div", { className: "bw-details-meta-row", children: [_jsx("span", { className: "bw-details-meta-icon", children: _jsx(GlobeIcon, {}) }), _jsx("span", { className: "bw-details-meta-value", children: selectedHeldStaff?.timezone ?? selectedStaff?.timezone ?? setup?.workspaceTimezone ?? setup?.staff?.[0]?.timezone ?? 'UTC' })] }), _jsxs("div", { className: "bw-details-meta-row", children: [_jsx("span", { className: "bw-details-meta-icon", "aria-hidden": "true", children: "$" }), _jsxs("div", { className: "bw-details-meta-text", children: [_jsx("span", { className: "bw-details-meta-label", children: isQuoteLoading ? t('summaryCalculating') : t('summaryEstimatedTotal') }), _jsx("span", { className: "bw-details-meta-value", children: formatServicePrice(selectedService, quote, intlLocale) })] })] }), holdSecondsRemaining !== null ? (_jsxs("div", { className: "bw-details-meta-row bw-details-meta-row--hold", "aria-live": "polite", children: [_jsx("span", { className: "bw-details-meta-icon", children: _jsx(ClockIcon, {}) }), _jsxs("div", { className: "bw-details-meta-text", children: [_jsx("span", { className: "bw-details-meta-label", children: t('summaryReservationHold') }), _jsx("span", { className: "bw-details-meta-value bw-details-hold", children: formatHoldCountdown(holdSecondsRemaining) })] })] })) : null] })] })) : null }), _jsx("div", { className: "bw-details-form", children: _jsxs("div", { className: "bw-form bw-form--details", children: [serviceWarning ? _jsx(ServiceWarningCallout, { warning: serviceWarning }) : null, renderIntakeAndContact('bw-intake-d', '-d'), renderNotesField('bw-notes-d', isReschedule ? t('notesLabelReschedule') : t('notesLabel'), isReschedule ? t('notesPlaceholderReschedule') : t('notesPlaceholder')), error ? _jsx("div", { className: "bw-error", children: error }) : null, renderSubmitHelp(), !payment && (forcedState === 'payment-full' || forcedState === 'payment-deposit') ? (_jsx(PaymentPanel, { service: selectedService, mode: forcedState === 'payment-full' ? 'full' : 'deposit' })) : null, payment ? (_jsx(StripePaymentBlock, { payment: payment, appointmentId: paymentAppointmentId, onSuccess: () => {
1195
+ : t('btnConfirmBooking') }), !isSubmitting ? _jsx(ArrowRightIcon, {}) : null] }))] })] })] }) }) }) })] }) }), _jsxs("div", { className: "bw-details-view", children: [_jsx("div", { className: "bw-details-summary", children: selectedService ? (_jsxs(_Fragment, { children: [selectedServiceRequiresSlot ? (_jsxs("button", { type: "button", className: "bw-back-btn bw-back-btn--details", onClick: () => void handleBackToSlots(), children: [_jsx(ArrowLeftIcon, {}), _jsx("span", { children: t('backToDifferentTime') })] })) : (_jsxs("button", { type: "button", className: "bw-back-btn bw-back-btn--details", onClick: handleBackToServicePicker, children: [_jsx(ArrowLeftIcon, {}), _jsx("span", { children: t('backToDifferentService') })] })), _jsx("h3", { className: "bw-details-service", children: pickLocaleField(selectedService, 'name', locale) ??
1196
+ selectedService.name }), (pickLocaleField(selectedService, 'description', locale) ??
1197
+ selectedService.description) ? (_jsx("p", { className: "bw-details-desc", children: pickLocaleField(selectedService, 'description', locale) ?? selectedService.description })) : null, _jsxs("div", { className: "bw-details-meta", children: [isReschedule && rescheduleContext ? (_jsxs("div", { className: "bw-details-meta-row bw-details-meta-row--strike", children: [_jsx("span", { className: "bw-details-meta-icon", children: _jsx(CalendarIcon, {}) }), _jsxs("div", { className: "bw-details-meta-text", children: [_jsx("span", { className: "bw-details-meta-label", children: t('summaryFormerTime') }), _jsx("span", { className: "bw-details-meta-value", children: formatFormerSlot(rescheduleContext.formerStartTime, rescheduleContext.formerEndTime, intlLocale) })] })] })) : null, selectedDate && selectedSlot ? (_jsxs("div", { className: "bw-details-meta-row", children: [_jsx("span", { className: "bw-details-meta-icon", children: _jsx(CalendarIcon, {}) }), _jsxs("div", { className: "bw-details-meta-text", children: [_jsx("span", { className: "bw-details-meta-label", children: isReschedule
1198
+ ? t('summaryNewTime')
1199
+ : t('summaryWhen') }), _jsxs("span", { className: "bw-details-meta-value", children: [formatReadableDate(selectedDate, intlLocale), _jsx("br", {}), formatTimeLabel(selectedSlot.time, intlLocale), " \u2013", ' ', formatTimeLabel(selectedSlot.endTime, intlLocale)] })] })] })) : null, _jsxs("div", { className: "bw-details-meta-row", children: [_jsx("span", { className: "bw-details-meta-icon", children: _jsx(ClockIcon, {}) }), _jsx("span", { className: "bw-details-meta-value", children: formatDuration(selectedService.durationMinutes) })] }), _jsxs("div", { className: "bw-details-meta-row", children: [_jsx("span", { className: "bw-details-meta-icon", children: _jsx(UserIcon, {}) }), _jsx("span", { className: "bw-details-meta-value", children: selectedHeldStaff?.name ??
1200
+ selectedStaff?.name ??
1201
+ t('providerAny') })] }), _jsxs("div", { className: "bw-details-meta-row", children: [_jsx("span", { className: "bw-details-meta-icon", children: _jsx(GlobeIcon, {}) }), _jsx("span", { className: "bw-details-meta-value", children: selectedHeldStaff?.timezone ??
1202
+ selectedStaff?.timezone ??
1203
+ setup?.workspaceTimezone ??
1204
+ setup?.staff?.[0]?.timezone ??
1205
+ 'UTC' })] }), _jsxs("div", { className: "bw-details-meta-row", children: [_jsx("span", { className: "bw-details-meta-icon", "aria-hidden": "true", children: "$" }), _jsxs("div", { className: "bw-details-meta-text", children: [_jsx("span", { className: "bw-details-meta-label", children: isQuoteLoading
1206
+ ? t('summaryCalculating')
1207
+ : t('summaryEstimatedTotal') }), _jsx("span", { className: "bw-details-meta-value", children: formatServicePrice(selectedService, quote, intlLocale) })] })] }), holdSecondsRemaining !== null ? (_jsxs("div", { className: "bw-details-meta-row bw-details-meta-row--hold", "aria-live": "polite", children: [_jsx("span", { className: "bw-details-meta-icon", children: _jsx(ClockIcon, {}) }), _jsxs("div", { className: "bw-details-meta-text", children: [_jsx("span", { className: "bw-details-meta-label", children: t('summaryReservationHold') }), _jsx("span", { className: "bw-details-meta-value bw-details-hold", children: formatHoldCountdown(holdSecondsRemaining) })] })] })) : null] })] })) : null }), _jsx("div", { className: "bw-details-form", children: _jsxs("div", { className: "bw-form bw-form--details", children: [serviceWarning ? (_jsx(ServiceWarningCallout, { warning: serviceWarning })) : null, renderIntakeAndContact('bw-intake-d', '-d'), renderNotesField('bw-notes-d', isReschedule ? t('notesLabelReschedule') : t('notesLabel'), isReschedule
1208
+ ? t('notesPlaceholderReschedule')
1209
+ : t('notesPlaceholder')), error ? _jsx("div", { className: "bw-error", children: error }) : null, renderSubmitHelp(), !payment &&
1210
+ (forcedState === 'payment-full' ||
1211
+ forcedState === 'payment-deposit') ? (_jsx(PaymentPanel, { service: selectedService, mode: forcedState === 'payment-full' ? 'full' : 'deposit' })) : null, payment ? (_jsx(StripePaymentBlock, { payment: payment, appointmentId: paymentAppointmentId, onSuccess: () => {
1052
1212
  setSuccess(t('successPaymentReceived'));
1053
1213
  setPayment(null);
1054
1214
  }, onError: setError })) : (_jsxs("button", { type: "button", className: `bw-confirm-btn${!canSubmit || isQuoteLoading ? ' is-disabled' : ''}`, "aria-disabled": !canSubmit || isQuoteLoading, onClick: handleConfirmAttempt, children: [_jsx("span", { children: isSubmitting
@@ -1056,7 +1216,9 @@ export function BookingWidgetPanel({ title, description, mobileHeader, mode = 'c
1056
1216
  ? t('btnRescheduling')
1057
1217
  : t('btnBooking')
1058
1218
  : forcedState === 'payment-full'
1059
- ? t('btnPayAndConfirm', { price: formatPrice(selectedService, intlLocale) })
1219
+ ? t('btnPayAndConfirm', {
1220
+ price: formatPrice(selectedService, intlLocale),
1221
+ })
1060
1222
  : forcedState === 'payment-deposit'
1061
1223
  ? t('btnPayDepositAndConfirm')
1062
1224
  : isReschedule
@@ -1156,7 +1318,8 @@ function areRequiredIntakeFieldsComplete(form, responses, mode) {
1156
1318
  }
1157
1319
  function getSubmitBlockers({ selectedService, selectedServiceRequiresSlot, selectedDate, selectedSlot, holdId, isIntakeComplete, intakeResponses, selectedServicePath, quote, customerName, customerEmail, t, locale = DEFAULT_LOCALE, }) {
1158
1320
  const blockers = [];
1159
- if (selectedServiceRequiresSlot && (!selectedDate || !selectedSlot || !holdId)) {
1321
+ if (selectedServiceRequiresSlot &&
1322
+ (!selectedDate || !selectedSlot || !holdId)) {
1160
1323
  blockers.push(t('blockerDateTime'));
1161
1324
  }
1162
1325
  if (!customerName.trim())
@@ -1284,7 +1447,9 @@ function buildIntakeReviewRows(form, responses, servicePath, locale, t) {
1284
1447
  continue;
1285
1448
  for (const field of section.fields) {
1286
1449
  if (field.type === 'repeatable-group') {
1287
- const items = Array.isArray(responses[field.id]) ? responses[field.id] : [];
1450
+ const items = Array.isArray(responses[field.id])
1451
+ ? responses[field.id]
1452
+ : [];
1288
1453
  items.forEach((item, index) => {
1289
1454
  const record = item && typeof item === 'object' && !Array.isArray(item)
1290
1455
  ? item
@@ -1489,7 +1654,9 @@ function IntakeField({ field, value, onChange, idPrefix, }) {
1489
1654
  if (field.type === 'repeatable-group') {
1490
1655
  const items = Array.isArray(value) && value.length > 0 ? value : [{}];
1491
1656
  return (_jsxs("div", { className: "bw-field bw-field--wide bw-repeatable", children: [_jsx("label", { children: label }), items.map((item, index) => {
1492
- const record = item && typeof item === 'object' && !Array.isArray(item) ? item : {};
1657
+ const record = item && typeof item === 'object' && !Array.isArray(item)
1658
+ ? item
1659
+ : {};
1493
1660
  return (_jsxs("div", { className: "bw-repeatable-item", children: [_jsxs("div", { className: "bw-repeatable-head", children: [_jsx("span", { children: t('repeatItemLabel', { index: index + 1 }) }), items.length > 1 ? (_jsx("button", { type: "button", className: "bw-link-btn", onClick: () => onChange(items.filter((_, itemIndex) => itemIndex !== index)), children: t('repeatRemove') })) : null] }), _jsx("div", { className: "bw-form-fields", children: (field.fields ?? []).map((child) => (_jsx(IntakeField, { field: child, value: record[child.id], idPrefix: `${id}-${index}`, onChange: (nextValue) => {
1494
1661
  const nextItems = [...items];
1495
1662
  nextItems[index] = { ...record, [child.id]: nextValue };
@@ -1513,7 +1680,11 @@ function IntakeField({ field, value, onChange, idPrefix, }) {
1513
1680
  if (field.type === 'textarea') {
1514
1681
  return (_jsxs("div", { className: "bw-field bw-field--wide", children: [_jsxs("label", { htmlFor: id, children: [label, field.required ? _jsx("span", { className: "bw-required", children: " *" }) : null] }), _jsx("textarea", { id: id, rows: 3, required: field.required, value: stringValue, placeholder: field.placeholder, onChange: (event) => onChange(event.target.value) }), field.helpText ? _jsx("p", { className: "bw-help", children: field.helpText }) : null] }));
1515
1682
  }
1516
- return (_jsxs("div", { className: "bw-field", children: [_jsxs("label", { htmlFor: id, children: [label, field.required ? _jsx("span", { className: "bw-required", children: " *" }) : null] }), _jsx("input", { id: id, type: field.type === 'email' ? 'email' : field.type === 'number' ? 'number' : 'text', min: field.min, max: field.max, required: field.required, value: stringValue, placeholder: field.placeholder, onChange: (event) => {
1683
+ return (_jsxs("div", { className: "bw-field", children: [_jsxs("label", { htmlFor: id, children: [label, field.required ? _jsx("span", { className: "bw-required", children: " *" }) : null] }), _jsx("input", { id: id, type: field.type === 'email'
1684
+ ? 'email'
1685
+ : field.type === 'number'
1686
+ ? 'number'
1687
+ : 'text', min: field.min, max: field.max, required: field.required, value: stringValue, placeholder: field.placeholder, onChange: (event) => {
1517
1688
  onChange(field.type === 'number'
1518
1689
  ? event.target.value === ''
1519
1690
  ? ''
@@ -1744,7 +1915,8 @@ function buildCalendarDays(month) {
1744
1915
  });
1745
1916
  }
1746
1917
  function sameMonth(left, right) {
1747
- return left.getFullYear() === right.getFullYear() && left.getMonth() === right.getMonth();
1918
+ return (left.getFullYear() === right.getFullYear() &&
1919
+ left.getMonth() === right.getMonth());
1748
1920
  }
1749
1921
  function getMonthOptions(currentMonth, total, locale = 'en-US') {
1750
1922
  const start = startOfMonth(new Date());
@@ -1763,7 +1935,8 @@ function optionCurrentValue(date) {
1763
1935
  }
1764
1936
  function isDateInMonth(dateKey, month) {
1765
1937
  const date = new Date(`${dateKey}T00:00:00`);
1766
- return date.getMonth() === month.getMonth() && date.getFullYear() === month.getFullYear();
1938
+ return (date.getMonth() === month.getMonth() &&
1939
+ date.getFullYear() === month.getFullYear());
1767
1940
  }
1768
1941
  function findFirstAvailableDate(availabilityByDate, month) {
1769
1942
  const dates = [...availabilityByDate.entries()]