@wix/headless-bookings 0.0.20 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/cjs/dist/api/{time-slot-list → fetch-availability}/index.d.ts +4 -3
  2. package/cjs/dist/api/{time-slot-list → fetch-availability}/index.js +36 -15
  3. package/cjs/dist/api/index.d.ts +1 -1
  4. package/cjs/dist/api/index.js +1 -1
  5. package/cjs/dist/react/booking/Booking.d.ts +2 -1
  6. package/cjs/dist/react/booking/Booking.js +1 -1
  7. package/cjs/dist/react/core/booking/Booking.d.ts +3 -2
  8. package/cjs/dist/react/core/booking/Booking.js +5 -2
  9. package/cjs/dist/react/core/time-slot-list/TimeSlot.d.ts +4 -4
  10. package/cjs/dist/react/core/time-slot-list/TimeSlot.js +17 -7
  11. package/cjs/dist/react/core/time-slot-list/TimeSlotList.js +3 -2
  12. package/cjs/dist/react/time-slot-list/TimeSlot.d.ts +6 -6
  13. package/cjs/dist/react/time-slot-list/TimeSlot.js +6 -6
  14. package/cjs/dist/react/time-slot-list/TimeSlotList.d.ts +4 -4
  15. package/cjs/dist/services/booking/booking.d.ts +6 -0
  16. package/cjs/dist/services/booking/booking.js +21 -1
  17. package/cjs/dist/services/time-slot-list/time-slot-list.def.d.ts +12 -4
  18. package/cjs/dist/services/time-slot-list/time-slot-list.js +37 -34
  19. package/dist/api/{time-slot-list → fetch-availability}/index.d.ts +4 -3
  20. package/dist/api/{time-slot-list → fetch-availability}/index.js +36 -15
  21. package/dist/api/index.d.ts +1 -1
  22. package/dist/api/index.js +1 -1
  23. package/dist/react/booking/Booking.d.ts +2 -1
  24. package/dist/react/booking/Booking.js +1 -1
  25. package/dist/react/core/booking/Booking.d.ts +3 -2
  26. package/dist/react/core/booking/Booking.js +5 -2
  27. package/dist/react/core/time-slot-list/TimeSlot.d.ts +4 -4
  28. package/dist/react/core/time-slot-list/TimeSlot.js +17 -7
  29. package/dist/react/core/time-slot-list/TimeSlotList.js +3 -2
  30. package/dist/react/time-slot-list/TimeSlot.d.ts +6 -6
  31. package/dist/react/time-slot-list/TimeSlot.js +6 -6
  32. package/dist/react/time-slot-list/TimeSlotList.d.ts +4 -4
  33. package/dist/services/booking/booking.d.ts +6 -0
  34. package/dist/services/booking/booking.js +21 -1
  35. package/dist/services/time-slot-list/time-slot-list.def.d.ts +12 -4
  36. package/dist/services/time-slot-list/time-slot-list.js +37 -34
  37. package/package.json +2 -2
@@ -52,10 +52,10 @@ export interface FetchAvailabilityResponse {
52
52
  * // response.timeSlots are grouped by time
53
53
  * ```
54
54
  */
55
- export declare function fetchAvailability({ services: selectedServices, viewMode, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, }: {
55
+ export declare function fetchAvailability({ services: selectedServices, viewMode, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, timeSlotsPerDay, }: {
56
56
  services: Service[];
57
- fromLocalDate: string;
58
- toLocalDate: string;
57
+ fromLocalDate: Date;
58
+ toLocalDate: Date;
59
59
  timeZone?: string;
60
60
  locations?: Location[];
61
61
  staffMemberIds?: string[];
@@ -68,4 +68,5 @@ export declare function fetchAvailability({ services: selectedServices, viewMode
68
68
  bookOnlineDisabled?: boolean;
69
69
  };
70
70
  slotsPerPage?: number;
71
+ timeSlotsPerDay?: number;
71
72
  }): Promise<FetchAvailabilityResponse>;
@@ -5,6 +5,8 @@
5
5
  import { listAvailabilityTimeSlots, } from '@wix/auto_sdk_bookings_availability-time-slots';
6
6
  import { listEventTimeSlots } from '@wix/auto_sdk_bookings_event-time-slots';
7
7
  import { ServiceType } from '@wix/auto_sdk_bookings_services';
8
+ import { format } from 'date-fns';
9
+ import { ANY_STAFF_MEMBER_ID } from '../../services/booking/booking.js';
8
10
  import { ViewMode, } from '../../services/time-slot-list/time-slot-list.def.js';
9
11
  // ============================================================================
10
12
  // Internal Types
@@ -17,6 +19,16 @@ var FlowType;
17
19
  })(FlowType || (FlowType = {}));
18
20
  const STAFF_RESOURCE_TYPE_ID = '1cd44cf8-756f-41c3-bd90-3e2ffcaf1155';
19
21
  // ============================================================================
22
+ // Helpers
23
+ // ============================================================================
24
+ /**
25
+ * Formats a Date to local ISO string (YYYY-MM-DDThh:mm:ss)
26
+ */
27
+ function toLocalDateString(date) {
28
+ const pattern = "yyyy-MM-dd'T'HH:mm:ss";
29
+ return format(date, pattern);
30
+ }
31
+ // ============================================================================
20
32
  // Grouping Functions
21
33
  // ============================================================================
22
34
  /**
@@ -103,11 +115,22 @@ function detectFlow(bookingServices, viewMode) {
103
115
  * // response.timeSlots are grouped by time
104
116
  * ```
105
117
  */
106
- export async function fetchAvailability({ services: selectedServices, viewMode = ViewMode.CLASSIC, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, }) {
118
+ export async function fetchAvailability({ services: selectedServices, viewMode = ViewMode.CLASSIC, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, timeSlotsPerDay, }) {
107
119
  const flow = detectFlow(selectedServices, viewMode);
108
120
  const serviceIds = selectedServices.map((s) => s._id);
121
+ // Convert Date objects to local ISO strings
122
+ const fromLocalDateStr = toLocalDateString(fromLocalDate);
123
+ const toLocalDateStr = toLocalDateString(toLocalDate);
124
+ const isFetchAvailabileDays = timeSlotsPerDay === 1;
125
+ const cursorPaging = isFetchAvailabileDays
126
+ ? undefined
127
+ : {
128
+ cursor,
129
+ limit: slotsPerPage,
130
+ };
109
131
  if (flow === FlowType.SINGLE_SERVICE) {
110
- const resourceTypes = staffMemberIds?.length
132
+ const isAnyStaffMemberSelected = staffMemberIds?.length === 1 && staffMemberIds[0] === ANY_STAFF_MEMBER_ID;
133
+ const resourceTypes = staffMemberIds?.length && !isAnyStaffMemberSelected
111
134
  ? [
112
135
  {
113
136
  resourceTypeId: STAFF_RESOURCE_TYPE_ID,
@@ -117,18 +140,18 @@ export async function fetchAvailability({ services: selectedServices, viewMode =
117
140
  : undefined;
118
141
  const response = await listAvailabilityTimeSlots({
119
142
  serviceId: serviceIds[0],
120
- fromLocalDate,
121
- toLocalDate,
143
+ fromLocalDate: fromLocalDateStr,
144
+ toLocalDate: toLocalDateStr,
122
145
  timeZone,
123
146
  locations,
124
- cursorPaging: {
125
- cursor,
126
- limit: slotsPerPage,
127
- },
147
+ cursorPaging,
128
148
  resourceTypes,
129
149
  bookable,
130
150
  bookingPolicyViolations,
131
- includeResourceTypeIds: [STAFF_RESOURCE_TYPE_ID],
151
+ includeResourceTypeIds: isAnyStaffMemberSelected || isFetchAvailabileDays
152
+ ? undefined
153
+ : [STAFF_RESOURCE_TYPE_ID],
154
+ timeSlotsPerDay,
132
155
  });
133
156
  return {
134
157
  timeSlots: groupTimeSlotsByTime(response.timeSlots || []),
@@ -150,17 +173,15 @@ export async function fetchAvailability({ services: selectedServices, viewMode =
150
173
  eventFilter['resources.id'] = { $hasSome: staffMemberIds };
151
174
  }
152
175
  const response = await listEventTimeSlots({
153
- fromLocalDate,
154
- toLocalDate,
176
+ fromLocalDate: fromLocalDateStr,
177
+ toLocalDate: toLocalDateStr,
155
178
  timeZone,
156
179
  serviceIds: serviceIds.length ? serviceIds : undefined,
157
- cursorPaging: {
158
- cursor,
159
- limit: slotsPerPage,
160
- },
180
+ cursorPaging,
161
181
  eventFilter: Object.keys(eventFilter).length ? eventFilter : undefined,
162
182
  includeNonBookable: bookable ? !bookable : undefined,
163
183
  bookingPolicyViolations,
184
+ maxSlotsPerDay: timeSlotsPerDay,
164
185
  });
165
186
  return {
166
187
  timeSlots: groupTimeSlotsByTime(response.timeSlots || []),
@@ -5,7 +5,7 @@
5
5
  * @module API
6
6
  */
7
7
  export { getServiceById, getServiceBySlug, queryServices, type PagingMetadata, type ServiceListFilters, type QueryServicesRequest, } from './query-services/index.js';
8
- export { fetchAvailability } from './time-slot-list/index.js';
8
+ export { fetchAvailability } from './fetch-availability/index.js';
9
9
  /**
10
10
  * PagingMetadata includes:
11
11
  * - limit: Number of items per page
@@ -5,7 +5,7 @@
5
5
  * @module API
6
6
  */
7
7
  export { getServiceById, getServiceBySlug, queryServices, } from './query-services/index.js';
8
- export { fetchAvailability } from './time-slot-list/index.js';
8
+ export { fetchAvailability } from './fetch-availability/index.js';
9
9
  /**
10
10
  * PagingMetadata includes:
11
11
  * - limit: Number of items per page
@@ -4,12 +4,13 @@
4
4
  */
5
5
  import React from 'react';
6
6
  import type { BookingServiceConfig } from '../../services/booking/booking.js';
7
+ export type { BookingData, DataProps } from '../core/booking/Booking.js';
7
8
  /**
8
9
  * Props for Booking.Root component
9
10
  */
10
11
  export interface BookingRootProps {
11
12
  children: React.ReactNode;
12
- bookingServiceConfig: BookingServiceConfig;
13
+ bookingServiceConfig?: BookingServiceConfig;
13
14
  }
14
15
  /**
15
16
  * Root component that provides booking context to the entire app.
@@ -19,7 +19,7 @@ import * as CoreBooking from '../core/booking/Booking.js';
19
19
  * ```
20
20
  */
21
21
  export const Root = (props) => {
22
- const { children, bookingServiceConfig } = props;
22
+ const { children, bookingServiceConfig = {} } = props;
23
23
  return (_jsx(CoreBooking.Root, { bookingServiceConfig: bookingServiceConfig, children: children }));
24
24
  };
25
25
  Root.displayName = 'Booking.Root';
@@ -10,7 +10,7 @@ import type { FormValues } from '@wix/form-public';
10
10
  */
11
11
  export interface RootProps {
12
12
  children: React.ReactNode;
13
- bookingServiceConfig: BookingServiceConfig;
13
+ bookingServiceConfig?: BookingServiceConfig;
14
14
  }
15
15
  /**
16
16
  * Root component that provides booking context to the entire app.
@@ -35,6 +35,7 @@ export declare function Root(props: RootProps): React.ReactNode;
35
35
  export interface BookingData {
36
36
  serviceSelections: ServiceSelection[];
37
37
  location: Location | null;
38
+ timezone: string | undefined;
38
39
  formSubmission: FormValues | null;
39
40
  actions: BookingServiceActions;
40
41
  }
@@ -52,7 +53,7 @@ export interface DataProps {
52
53
  * @example
53
54
  * ```tsx
54
55
  * <Booking.Data>
55
- * {({ serviceSelections, location, formSubmission, actions }) => (
56
+ * {({ serviceSelections, location, timezone, formSubmission, actions }) => (
56
57
  * serviceSelections.length > 0 ? (
57
58
  * <div>{serviceSelections.map(item => item.service.name).join(', ')}</div>
58
59
  * ) : (
@@ -18,7 +18,8 @@ import { BookingServiceDefinition, BookingService, } from '../../../services/boo
18
18
  * ```
19
19
  */
20
20
  export function Root(props) {
21
- return (_jsx(WixServices, { servicesMap: createServicesMap().addService(BookingServiceDefinition, BookingService, props.bookingServiceConfig), children: props.children }));
21
+ const { bookingServiceConfig = {}, children } = props;
22
+ return (_jsx(WixServices, { servicesMap: createServicesMap().addService(BookingServiceDefinition, BookingService, bookingServiceConfig), children: children }));
22
23
  }
23
24
  /**
24
25
  * Core component that provides access to booking data via render props.
@@ -28,7 +29,7 @@ export function Root(props) {
28
29
  * @example
29
30
  * ```tsx
30
31
  * <Booking.Data>
31
- * {({ serviceSelections, location, formSubmission, actions }) => (
32
+ * {({ serviceSelections, location, timezone, formSubmission, actions }) => (
32
33
  * serviceSelections.length > 0 ? (
33
34
  * <div>{serviceSelections.map(item => item.service.name).join(', ')}</div>
34
35
  * ) : (
@@ -43,11 +44,13 @@ export function Data(props) {
43
44
  const bookingService = useService(BookingServiceDefinition);
44
45
  const serviceSelections = bookingService.serviceSelections.get();
45
46
  const location = bookingService.location.get();
47
+ const timezone = bookingService.timezone.get();
46
48
  const formSubmission = bookingService.formSubmission.get();
47
49
  const { actions } = bookingService;
48
50
  return children({
49
51
  serviceSelections,
50
52
  location,
53
+ timezone,
51
54
  formSubmission,
52
55
  actions,
53
56
  });
@@ -88,10 +88,10 @@ export declare function StaffMemberProvider(props: StaffMemberProviderProps): Re
88
88
  */
89
89
  export interface InfoProps {
90
90
  children: (data: {
91
- /** Raw localStartDate string from timeSlot */
92
- startDate: string | undefined;
93
- /** Raw localEndDate string from timeSlot */
94
- endDate: string | undefined;
91
+ /** Parsed localStartDate as Date (constructed from the raw localStartDate string) */
92
+ startDate: Date | undefined;
93
+ /** Parsed localEndDate as Date (constructed from the raw localEndDate string) */
94
+ endDate: Date | undefined;
95
95
  /** Calculated duration in minutes (null if dates unavailable) */
96
96
  durationInMinutes: number | null;
97
97
  /** Whether the timeSlot is bookable */
@@ -9,6 +9,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
9
9
  import React from 'react';
10
10
  import { useService } from '@wix/services-manager-react';
11
11
  import { TimeSlotListServiceDefinition, } from '../../../services/time-slot-list/time-slot-list.def.js';
12
+ import { ANY_STAFF_MEMBER_ID } from '../../../services/booking/booking.js';
12
13
  const TimeSlotContext = React.createContext(null);
13
14
  /**
14
15
  * Hook to access TimeSlot context
@@ -115,15 +116,17 @@ export function StaffMemberProvider(props) {
115
116
  */
116
117
  export function Info(props) {
117
118
  const { timeSlot, isSelected } = useTimeSlotContext();
118
- const startDate = timeSlot.localStartDate ?? undefined;
119
- const endDate = timeSlot.localEndDate ?? undefined;
119
+ const startDate = timeSlot.localStartDate
120
+ ? new Date(timeSlot.localStartDate)
121
+ : undefined;
122
+ const endDate = timeSlot.localEndDate
123
+ ? new Date(timeSlot.localEndDate)
124
+ : undefined;
120
125
  const bookable = timeSlot.bookable ?? false;
121
126
  // Calculate duration from start and end dates
122
127
  let durationInMinutes = null;
123
128
  if (startDate && endDate) {
124
- const startTime = new Date(startDate).getTime();
125
- const endTime = new Date(endDate).getTime();
126
- durationInMinutes = Math.round((endTime - startTime) / (1000 * 60));
129
+ durationInMinutes = Math.round((endDate.getTime() - startDate.getTime()) / (1000 * 60));
127
130
  }
128
131
  return props.children({
129
132
  startDate,
@@ -202,12 +205,13 @@ export function Locations(props) {
202
205
  const selection = service.selection.get();
203
206
  const selectedLocationId = selection?.locationId ?? null;
204
207
  const selectedStaffMemberId = selection?.staffMemberId ?? null;
208
+ const isAnyStaffMemberSelected = selectedStaffMemberId === ANY_STAFF_MEMBER_ID;
205
209
  // Build locations array from staffByLocation (names already included)
206
210
  const locations = timeSlot.staffByLocation.map(({ location, staffMembers }) => {
207
211
  // Check if this location is selectable based on selected staff
208
212
  // If no staff selected, all locations are selectable
209
213
  // If staff selected, only locations where that staff works are selectable
210
- const isSelectable = selectedStaffMemberId
214
+ const isSelectable = !isAnyStaffMemberSelected && selectedStaffMemberId
211
215
  ? staffMembers.some((s) => s.id === selectedStaffMemberId)
212
216
  : true;
213
217
  return {
@@ -311,12 +315,18 @@ export function StaffMembers(props) {
311
315
  isSelectable: !selectedLocationId ||
312
316
  entries.some((e) => e.locationId === selectedLocationId),
313
317
  }));
318
+ const anyStaffOption = {
319
+ id: ANY_STAFF_MEMBER_ID,
320
+ name: 'Any staff member',
321
+ isSelected: selectedStaffMemberId === ANY_STAFF_MEMBER_ID,
322
+ isSelectable: true,
323
+ };
314
324
  // Return null if only 1 staff member - nothing to choose from
315
325
  if (staffMembers.length <= 1) {
316
326
  return null;
317
327
  }
318
328
  return props.children({
319
- staffMembers,
329
+ staffMembers: [anyStaffOption, ...staffMembers],
320
330
  selectStaffMember: service.actions.selectStaffMember,
321
331
  });
322
332
  }
@@ -2,6 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useService, WixServices } from '@wix/services-manager-react';
3
3
  import { createServicesMap } from '@wix/services-manager';
4
4
  import { TimeSlotListServiceDefinition, TimeSlotListService, } from '../../../services/time-slot-list/index.js';
5
+ import { BookingServiceDefinition } from '../../../services/booking/booking.js';
5
6
  /**
6
7
  * Root component that provides TimeSlotListService context to its children.
7
8
  *
@@ -54,8 +55,8 @@ function getTimezoneDisplayName(timezone) {
54
55
  * ```
55
56
  */
56
57
  export function Timezone(props) {
57
- const service = useService(TimeSlotListServiceDefinition);
58
- const timezone = service.timezone.get();
58
+ const bookingService = useService(BookingServiceDefinition);
59
+ const timezone = bookingService.timezone.get();
59
60
  const displayName = getTimezoneDisplayName(timezone);
60
61
  return props.children({ timezone, displayName });
61
62
  }
@@ -16,18 +16,18 @@ export type { LocationData, StaffMemberData, } from '../core/time-slot-list/Time
16
16
  export interface StartDateProps {
17
17
  asChild?: boolean;
18
18
  children?: AsChildChildren<{
19
- startDate: string | undefined;
19
+ startDate: Date | undefined;
20
20
  }>;
21
21
  className?: string;
22
22
  }
23
23
  /**
24
- * Displays the time slot start date/time as a raw string.
24
+ * Displays the time slot start date/time as a Date.
25
25
  * Consumer is responsible for formatting.
26
26
  *
27
27
  * @component
28
28
  * @example
29
29
  * ```tsx
30
- * // Default usage - displays raw localStartDate string
30
+ * // Default usage - displays Date.toString()
31
31
  * <TimeSlot.StartDate className="text-foreground" />
32
32
  *
33
33
  * // With custom formatting
@@ -45,18 +45,18 @@ export declare const StartDate: React.ForwardRefExoticComponent<StartDateProps &
45
45
  export interface EndDateProps {
46
46
  asChild?: boolean;
47
47
  children?: AsChildChildren<{
48
- endDate: string | undefined;
48
+ endDate: Date | undefined;
49
49
  }>;
50
50
  className?: string;
51
51
  }
52
52
  /**
53
- * Displays the time slot end date/time as a raw string.
53
+ * Displays the time slot end date/time as a Date.
54
54
  * Consumer is responsible for formatting.
55
55
  *
56
56
  * @component
57
57
  * @example
58
58
  * ```tsx
59
- * // Default usage - displays raw localEndDate string
59
+ * // Default usage - displays Date.toString()
60
60
  * <TimeSlot.EndDate className="text-foreground" />
61
61
  *
62
62
  * // With custom formatting
@@ -34,13 +34,13 @@ var TestIds;
34
34
  TestIds["timeSlotStaffMemberActionSelect"] = "time-slot-staff-member-action-select";
35
35
  })(TestIds || (TestIds = {}));
36
36
  /**
37
- * Displays the time slot start date/time as a raw string.
37
+ * Displays the time slot start date/time as a Date.
38
38
  * Consumer is responsible for formatting.
39
39
  *
40
40
  * @component
41
41
  * @example
42
42
  * ```tsx
43
- * // Default usage - displays raw localStartDate string
43
+ * // Default usage - displays Date.toString()
44
44
  * <TimeSlot.StartDate className="text-foreground" />
45
45
  *
46
46
  * // With custom formatting
@@ -53,17 +53,17 @@ var TestIds;
53
53
  */
54
54
  export const StartDate = React.forwardRef((props, ref) => {
55
55
  const { asChild, children, className } = props;
56
- return (_jsx(CoreTimeSlot.Info, { children: ({ startDate }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotStartDate, customElement: children, customElementProps: { startDate }, children: _jsx("span", { children: startDate }) })) }));
56
+ return (_jsx(CoreTimeSlot.Info, { children: ({ startDate }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotStartDate, customElement: children, customElementProps: { startDate }, children: _jsx("span", { children: startDate?.toString() }) })) }));
57
57
  });
58
58
  StartDate.displayName = 'TimeSlot.StartDate';
59
59
  /**
60
- * Displays the time slot end date/time as a raw string.
60
+ * Displays the time slot end date/time as a Date.
61
61
  * Consumer is responsible for formatting.
62
62
  *
63
63
  * @component
64
64
  * @example
65
65
  * ```tsx
66
- * // Default usage - displays raw localEndDate string
66
+ * // Default usage - displays Date.toString()
67
67
  * <TimeSlot.EndDate className="text-foreground" />
68
68
  *
69
69
  * // With custom formatting
@@ -76,7 +76,7 @@ StartDate.displayName = 'TimeSlot.StartDate';
76
76
  */
77
77
  export const EndDate = React.forwardRef((props, ref) => {
78
78
  const { asChild, children, className } = props;
79
- return (_jsx(CoreTimeSlot.Info, { children: ({ endDate }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotEndDate, customElement: children, customElementProps: { endDate }, children: _jsx("span", { children: endDate }) })) }));
79
+ return (_jsx(CoreTimeSlot.Info, { children: ({ endDate }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotEndDate, customElement: children, customElementProps: { endDate }, children: _jsx("span", { children: endDate?.toString() }) })) }));
80
80
  });
81
81
  EndDate.displayName = 'TimeSlot.EndDate';
82
82
  /**
@@ -113,10 +113,10 @@ export interface TimeSlotRepeaterChildProps {
113
113
  isSelected: boolean;
114
114
  /** Whether the slot can be booked */
115
115
  bookable: boolean;
116
- /** Start date/time as ISO string */
117
- startDate: string | undefined;
118
- /** End date/time as ISO string */
119
- endDate: string | undefined;
116
+ /** Start date/time as Date (constructed from the raw localStartDate string) */
117
+ startDate: Date | undefined;
118
+ /** End date/time as Date (constructed from the raw localEndDate string) */
119
+ endDate: Date | undefined;
120
120
  /** Duration in minutes */
121
121
  durationInMinutes: number | null;
122
122
  /** The raw time slot data */
@@ -7,6 +7,7 @@ import { type Signal } from '@wix/services-definitions/core-services/signals';
7
7
  import type { Service } from '@wix/auto_sdk_bookings_services';
8
8
  import type { Resource, EventInfo } from '@wix/auto_sdk_bookings_availability-time-slots';
9
9
  import type { FormValues } from '@wix/form-public';
10
+ export declare const ANY_STAFF_MEMBER_ID = "__any_staff_member__";
10
11
  /**
11
12
  * Minimal time slot data for service selections
12
13
  */
@@ -57,6 +58,7 @@ export interface BookingServiceActions {
57
58
  getResourceById(resourceId: string, instanceId?: string): Resource | undefined;
58
59
  setLocation(location: Location | null): void;
59
60
  clearLocation(): void;
61
+ setTimezone(timezone: string): void;
60
62
  setFormSubmission(values: FormValues | null): void;
61
63
  clearFormSubmission(): void;
62
64
  clearAll(): void;
@@ -70,6 +72,8 @@ export interface BookingService {
70
72
  serviceSelections: Signal<ServiceSelection[]>;
71
73
  /** Signal containing the selected location */
72
74
  location: Signal<Location | null>;
75
+ /** Signal containing the selected timezone */
76
+ timezone: Signal<string | undefined>;
73
77
  /** Signal containing the form submission */
74
78
  formSubmission: Signal<FormValues | null>;
75
79
  /** Actions for modifying booking state */
@@ -92,6 +96,8 @@ export interface BookingServiceConfig {
92
96
  serviceSelections?: ServiceSelection[];
93
97
  /** Optional initial location */
94
98
  location?: Location | null;
99
+ /** Optional initial timezone */
100
+ timezone?: string;
95
101
  /** Optional initial form submission */
96
102
  formSubmission?: FormValues | null;
97
103
  }
@@ -6,7 +6,11 @@
6
6
  import { defineService, implementService } from '@wix/services-definitions';
7
7
  import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
8
8
  // ============================================================================
9
- // Types
9
+ // Constants
10
+ // ============================================================================
11
+ export const ANY_STAFF_MEMBER_ID = '__any_staff_member__';
12
+ // ============================================================================
13
+ // Helpers
10
14
  // ============================================================================
11
15
  /**
12
16
  * Generates a unique instance ID for service selections
@@ -14,6 +18,14 @@ import { SignalsServiceDefinition, } from '@wix/services-definitions/core-servic
14
18
  function generateInstanceId() {
15
19
  return crypto.randomUUID();
16
20
  }
21
+ /**
22
+ * Gets the client's timezone from Intl API
23
+ */
24
+ function getClientTimezone() {
25
+ return typeof Intl !== 'undefined'
26
+ ? Intl.DateTimeFormat().resolvedOptions().timeZone
27
+ : undefined;
28
+ }
17
29
  /**
18
30
  * Service definition for Booking
19
31
  */
@@ -55,6 +67,7 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
55
67
  }));
56
68
  const serviceSelectionsSignal = signalsService.signal(initialItemsWithIds);
57
69
  const locationSignal = signalsService.signal(config.location || null);
70
+ const timezoneSignal = signalsService.signal(config.timezone ?? getClientTimezone());
58
71
  const formSubmissionSignal = signalsService.signal(config.formSubmission || null);
59
72
  // ========================================================================
60
73
  // Actions Implementation
@@ -142,6 +155,12 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
142
155
  clearLocation() {
143
156
  locationSignal.set(null);
144
157
  },
158
+ // Timezone actions
159
+ setTimezone(timezone) {
160
+ if (timezoneSignal.get() !== timezone) {
161
+ timezoneSignal.set(timezone);
162
+ }
163
+ },
145
164
  // Form Submission actions
146
165
  setFormSubmission(values) {
147
166
  formSubmissionSignal.set(values);
@@ -159,6 +178,7 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
159
178
  return {
160
179
  serviceSelections: serviceSelectionsSignal,
161
180
  location: locationSignal,
181
+ timezone: timezoneSignal,
162
182
  formSubmission: formSubmissionSignal,
163
183
  actions,
164
184
  };
@@ -65,11 +65,21 @@ export interface TimeSlotsFilters {
65
65
  * Default: 1000. Max: 1000.
66
66
  * @example
67
67
  * ```ts
68
- * // Load 6 slots at a time
69
- * filters: { slotsPerPage: 6 }
68
+ * // Load 10 slots at a time
69
+ * filters: { slotsPerPage: 10 }
70
70
  * ```
71
71
  */
72
72
  slotsPerPage?: number;
73
+ /**
74
+ * Maximum number of time slots to return per day.
75
+ * Useful for fetching availability indicators (set to 1 to get one slot per day).
76
+ * @example
77
+ * ```ts
78
+ * // Get one slot per day for calendar indicators
79
+ * filters: { timeSlotsPerDay: 1 }
80
+ * ```
81
+ */
82
+ timeSlotsPerDay?: number;
73
83
  }
74
84
  export interface TimeSlotListServiceConfig {
75
85
  /** Services to fetch time slots for */
@@ -92,7 +102,6 @@ export interface TimeSlotListServiceActions {
92
102
  clearPreferences: () => void;
93
103
  loadMore: () => Promise<void>;
94
104
  setDateRange: (start: Date, end: Date) => void;
95
- setTimezone: (tz: string) => void;
96
105
  }
97
106
  export interface TimeSlotListServiceAPI {
98
107
  timeSlots: Signal<TimeSlot[]>;
@@ -102,7 +111,6 @@ export interface TimeSlotListServiceAPI {
102
111
  hasMore: Signal<boolean>;
103
112
  startDate: Signal<Date>;
104
113
  endDate: Signal<Date>;
105
- timezone: Signal<string | undefined>;
106
114
  actions: TimeSlotListServiceActions;
107
115
  }
108
116
  export declare const TimeSlotListServiceDefinition: string & {