@wix/headless-bookings 0.0.16 → 0.0.17

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 (29) hide show
  1. package/cjs/dist/api/time-slot-list/index.d.ts +21 -1
  2. package/cjs/dist/api/time-slot-list/index.js +46 -8
  3. package/cjs/dist/react/core/time-slot-list/TimeSlot.d.ts +22 -18
  4. package/cjs/dist/react/core/time-slot-list/TimeSlot.js +41 -28
  5. package/cjs/dist/react/core/time-slot-list/TimeSlotList.d.ts +39 -7
  6. package/cjs/dist/react/core/time-slot-list/TimeSlotList.js +56 -11
  7. package/cjs/dist/react/time-slot-list/TimeSlot.js +3 -3
  8. package/cjs/dist/react/time-slot-list/TimeSlotList.d.ts +55 -12
  9. package/cjs/dist/react/time-slot-list/TimeSlotList.js +47 -17
  10. package/cjs/dist/services/index.d.ts +2 -2
  11. package/cjs/dist/services/time-slot-list/index.d.ts +1 -1
  12. package/cjs/dist/services/time-slot-list/time-slot-list.d.ts +3 -3
  13. package/cjs/dist/services/time-slot-list/time-slot-list.def.d.ts +23 -4
  14. package/cjs/dist/services/time-slot-list/time-slot-list.js +37 -9
  15. package/dist/api/time-slot-list/index.d.ts +21 -1
  16. package/dist/api/time-slot-list/index.js +46 -8
  17. package/dist/react/core/time-slot-list/TimeSlot.d.ts +22 -18
  18. package/dist/react/core/time-slot-list/TimeSlot.js +41 -28
  19. package/dist/react/core/time-slot-list/TimeSlotList.d.ts +39 -7
  20. package/dist/react/core/time-slot-list/TimeSlotList.js +56 -11
  21. package/dist/react/time-slot-list/TimeSlot.js +3 -3
  22. package/dist/react/time-slot-list/TimeSlotList.d.ts +55 -12
  23. package/dist/react/time-slot-list/TimeSlotList.js +47 -17
  24. package/dist/services/index.d.ts +2 -2
  25. package/dist/services/time-slot-list/index.d.ts +1 -1
  26. package/dist/services/time-slot-list/time-slot-list.d.ts +3 -3
  27. package/dist/services/time-slot-list/time-slot-list.def.d.ts +23 -4
  28. package/dist/services/time-slot-list/time-slot-list.js +37 -9
  29. package/package.json +3 -2
@@ -11,8 +11,20 @@ export interface FetchAvailabilityOptions {
11
11
  toLocalDate?: string | null;
12
12
  timeZone?: string | null;
13
13
  locations?: Location[];
14
+ /** Filter by specific staff member IDs (passed as resourceIds to API) */
15
+ staffMemberIds?: string[];
14
16
  cursorPaging?: CursorPaging;
15
17
  viewMode?: ViewMode;
18
+ /** Maximum slots to return per day (useful for calendar views) */
19
+ slotsPerDay?: number;
20
+ /** Filter by bookable status. If undefined, returns both bookable and non-bookable */
21
+ bookable?: boolean;
22
+ /** Filter by booking policy violations */
23
+ bookingPolicyViolations?: {
24
+ tooEarlyToBook?: boolean;
25
+ tooLateToBook?: boolean;
26
+ bookOnlineDisabled?: boolean;
27
+ };
16
28
  }
17
29
  /**
18
30
  * Response from fetchAvailability with grouped time slots
@@ -42,12 +54,20 @@ export interface FetchAvailabilityResponse {
42
54
  * // response.timeSlots are grouped by time
43
55
  * ```
44
56
  */
45
- export declare function fetchAvailability({ services: selectedServices, viewMode, fromLocalDate, toLocalDate, timeZone, locations, cursorPaging, }: {
57
+ export declare function fetchAvailability({ services: selectedServices, viewMode, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursorPaging, slotsPerDay, bookable, bookingPolicyViolations, }: {
46
58
  services: Service[];
47
59
  fromLocalDate: string;
48
60
  toLocalDate: string;
49
61
  timeZone?: string;
50
62
  locations?: Location[];
63
+ staffMemberIds?: string[];
51
64
  cursorPaging?: CursorPaging;
52
65
  viewMode?: ViewMode;
66
+ slotsPerDay?: number;
67
+ bookable?: boolean;
68
+ bookingPolicyViolations?: {
69
+ tooEarlyToBook?: boolean;
70
+ tooLateToBook?: boolean;
71
+ bookOnlineDisabled?: boolean;
72
+ };
53
73
  }): Promise<FetchAvailabilityResponse>;
@@ -3,6 +3,7 @@
3
3
  * Fetches available time slots for booking services from Wix Bookings
4
4
  */
5
5
  import { listAvailabilityTimeSlots, } from '@wix/auto_sdk_bookings_availability-time-slots';
6
+ import { listEventTimeSlots } from '@wix/auto_sdk_bookings_event-time-slots';
6
7
  import { ServiceType } from '@wix/auto_sdk_bookings_services';
7
8
  import { ViewMode, } from '../../services/time-slot-list/time-slot-list.def.js';
8
9
  // ============================================================================
@@ -101,20 +102,31 @@ function detectFlow(bookingServices, viewMode) {
101
102
  * // response.timeSlots are grouped by time
102
103
  * ```
103
104
  */
104
- export async function fetchAvailability({ services: selectedServices, viewMode = ViewMode.CLASSIC, fromLocalDate, toLocalDate, timeZone, locations, cursorPaging, }) {
105
+ export async function fetchAvailability({ services: selectedServices, viewMode = ViewMode.CLASSIC, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursorPaging, slotsPerDay, bookable, bookingPolicyViolations, }) {
105
106
  const flow = detectFlow(selectedServices, viewMode);
107
+ const serviceIds = selectedServices.map((s) => s._id);
106
108
  if (flow === FlowType.SINGLE_SERVICE) {
107
- const serviceId = selectedServices[0]?._id;
108
- if (!serviceId) {
109
- throw new Error('Service ID is required');
110
- }
109
+ // Build resourceTypes filter for staff members
110
+ // Staff member resource type ID is 1cd44cf8-756f-41c3-bd90-3e2ffcaf1155
111
+ const resourceTypes = staffMemberIds?.length
112
+ ? [
113
+ {
114
+ resourceTypeId: '1cd44cf8-756f-41c3-bd90-3e2ffcaf1155',
115
+ resourceIds: staffMemberIds,
116
+ },
117
+ ]
118
+ : undefined;
111
119
  const response = await listAvailabilityTimeSlots({
112
- serviceId,
120
+ serviceId: serviceIds[0],
113
121
  fromLocalDate,
114
122
  toLocalDate,
115
123
  timeZone,
116
124
  locations,
117
125
  cursorPaging,
126
+ resourceTypes,
127
+ timeSlotsPerDay: slotsPerDay,
128
+ bookable,
129
+ bookingPolicyViolations,
118
130
  });
119
131
  return {
120
132
  timeSlots: groupTimeSlotsByTime(response.timeSlots || []),
@@ -126,8 +138,34 @@ export async function fetchAvailability({ services: selectedServices, viewMode =
126
138
  throw new Error('Multi-service appointments not yet supported');
127
139
  }
128
140
  if (flow === FlowType.CLASS) {
129
- // Phase 2: Class support
130
- throw new Error('Class bookings not yet supported');
141
+ // Build eventFilter for location and staff filtering
142
+ const locationIds = locations?.map((l) => l._id);
143
+ const eventFilter = {};
144
+ if (locationIds?.length) {
145
+ eventFilter['location.id'] = locationIds;
146
+ }
147
+ if (staffMemberIds?.length) {
148
+ eventFilter['resources.id'] = { $hasSome: staffMemberIds };
149
+ }
150
+ const response = await listEventTimeSlots({
151
+ fromLocalDate,
152
+ toLocalDate,
153
+ timeZone,
154
+ serviceIds: serviceIds.length ? serviceIds : undefined,
155
+ cursorPaging,
156
+ eventFilter: Object.keys(eventFilter).length ? eventFilter : undefined,
157
+ maxSlotsPerDay: slotsPerDay,
158
+ // bookable=true means only bookable, so includeNonBookable=false
159
+ // bookable=false means only non-bookable, so includeNonBookable=true
160
+ // bookable=undefined means both, so includeNonBookable=true (default)
161
+ includeNonBookable: bookable === undefined ? undefined : !bookable,
162
+ bookingPolicyViolations,
163
+ });
164
+ return {
165
+ timeSlots: groupTimeSlotsByTime(response.timeSlots || []),
166
+ // Note: listEventTimeSlots uses pagingMetadata instead of cursorPagingMetadata
167
+ cursorPagingMetadata: response.pagingMetadata,
168
+ };
131
169
  }
132
170
  throw new Error(`Unknown flow type: ${flow}`);
133
171
  }
@@ -6,17 +6,17 @@
6
6
  * which provides the TimeSlotProvider context.
7
7
  */
8
8
  import React from 'react';
9
- import type { TimeSlot as TimeSlotType } from '../../../services/time-slot-list/time-slot-list.def.js';
9
+ import { type TimeSlot as TimeSlotType } from '../../../services/time-slot-list/time-slot-list.def.js';
10
10
  /**
11
11
  * Context value for TimeSlot components
12
12
  */
13
13
  export interface TimeSlotContextValue {
14
14
  /** The current time slot data */
15
- slot: TimeSlotType;
16
- /** Whether this slot is currently selected */
15
+ timeSlot: TimeSlotType;
16
+ /** Whether this time slot is currently selected */
17
17
  isSelected: boolean;
18
- /** Action to select this slot */
19
- selectSlot: () => void;
18
+ /** Action to select this time slot */
19
+ selectTimeSlot: () => void;
20
20
  }
21
21
  /**
22
22
  * Hook to access TimeSlot context
@@ -28,7 +28,7 @@ export declare function useTimeSlotContext(): TimeSlotContextValue;
28
28
  */
29
29
  export interface TimeSlotProviderProps {
30
30
  children: React.ReactNode;
31
- slot: TimeSlotType;
31
+ timeSlot: TimeSlotType;
32
32
  }
33
33
  /**
34
34
  * Provider component used by TimeSlotRepeater to provide context.
@@ -88,18 +88,18 @@ export declare function StaffMemberProvider(props: StaffMemberProviderProps): Re
88
88
  */
89
89
  export interface InfoProps {
90
90
  children: (data: {
91
- /** Raw localStartDate string from slot */
91
+ /** Raw localStartDate string from timeSlot */
92
92
  startDate: string | undefined;
93
- /** Raw localEndDate string from slot */
93
+ /** Raw localEndDate string from timeSlot */
94
94
  endDate: string | undefined;
95
95
  /** Calculated duration in minutes (null if dates unavailable) */
96
96
  durationInMinutes: number | null;
97
- /** Whether the slot is bookable */
97
+ /** Whether the timeSlot is bookable */
98
98
  bookable: boolean;
99
- /** Whether this slot is currently selected */
99
+ /** Whether this timeSlot is currently selected */
100
100
  isSelected: boolean;
101
- /** The raw slot object for advanced use cases */
102
- slot: TimeSlotType;
101
+ /** The raw timeSlot object for advanced use cases */
102
+ timeSlot: TimeSlotType;
103
103
  }) => React.ReactNode;
104
104
  }
105
105
  /**
@@ -125,15 +125,15 @@ export declare function Info(props: InfoProps): React.ReactNode;
125
125
  */
126
126
  export interface ActionsProps {
127
127
  children: (data: {
128
- /** Action to select this slot */
129
- selectSlot: () => void;
128
+ /** Action to select this timeSlot */
129
+ selectTimeSlot: () => void;
130
130
  /** Action to clear preferences */
131
131
  clearPreferences?: () => void;
132
- /** The raw slot object */
133
- slot: TimeSlotType;
134
- /** Whether the slot is bookable */
132
+ /** The raw timeSlot object */
133
+ timeSlot: TimeSlotType;
134
+ /** Whether the timeSlot is bookable */
135
135
  bookable: boolean;
136
- /** Whether this slot is currently selected */
136
+ /** Whether this timeSlot is currently selected */
137
137
  isSelected: boolean;
138
138
  }) => React.ReactNode;
139
139
  }
@@ -187,6 +187,8 @@ export interface LocationsProps {
187
187
  * Extracts locations from slot.staffByLocation and enriches with name from originalSlots.
188
188
  * Each location includes isSelected and isSelectable based on current selection state.
189
189
  *
190
+ * Returns null if there's only 1 location (nothing to choose from).
191
+ *
190
192
  * @component
191
193
  * @example
192
194
  * ```tsx
@@ -291,6 +293,8 @@ export interface StaffMembersProps {
291
293
  * Extracts unique staff members from slot.staffByLocation (names already included).
292
294
  * Each staff member includes isSelected and isSelectable based on current selection state.
293
295
  *
296
+ * Returns null if there's only 1 staff member (nothing to choose from).
297
+ *
294
298
  * @component
295
299
  * @example
296
300
  * ```tsx
@@ -7,7 +7,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
7
7
  * which provides the TimeSlotProvider context.
8
8
  */
9
9
  import React from 'react';
10
- import { useTimeSlotListService } from './TimeSlotList.js';
10
+ import { useService } from '@wix/services-manager-react';
11
+ import { TimeSlotListServiceDefinition, } from '../../../services/time-slot-list/time-slot-list.def.js';
11
12
  const TimeSlotContext = React.createContext(null);
12
13
  /**
13
14
  * Hook to access TimeSlot context
@@ -25,17 +26,17 @@ export function useTimeSlotContext() {
25
26
  * Not used directly by consumers - only by TimeSlotList.TimeSlotRepeater.
26
27
  */
27
28
  export function TimeSlotProvider(props) {
28
- const { children, slot } = props;
29
- const service = useTimeSlotListService();
29
+ const { children, timeSlot } = props;
30
+ const service = useService(TimeSlotListServiceDefinition);
30
31
  const selection = service.selection.get();
31
- const isSelected = selection?.slot?.id === slot.id;
32
- const selectSlot = () => {
33
- service.actions.selectSlot(slot);
32
+ const isSelected = selection?.slot?.id === timeSlot.id;
33
+ const selectTimeSlot = () => {
34
+ service.actions.selectSlot(timeSlot);
34
35
  };
35
36
  const contextValue = {
36
- slot,
37
+ timeSlot,
37
38
  isSelected,
38
- selectSlot,
39
+ selectTimeSlot,
39
40
  };
40
41
  return (_jsx(TimeSlotContext.Provider, { value: contextValue, children: children }));
41
42
  }
@@ -57,7 +58,7 @@ export function useLocationContext() {
57
58
  */
58
59
  export function LocationProvider(props) {
59
60
  const { children, location } = props;
60
- const service = useTimeSlotListService();
61
+ const service = useService(TimeSlotListServiceDefinition);
61
62
  const selectLocation = () => {
62
63
  service.actions.selectLocation(location.id);
63
64
  };
@@ -85,7 +86,7 @@ export function useStaffMemberContext() {
85
86
  */
86
87
  export function StaffMemberProvider(props) {
87
88
  const { children, staffMember } = props;
88
- const service = useTimeSlotListService();
89
+ const service = useService(TimeSlotListServiceDefinition);
89
90
  const selectStaffMember = () => {
90
91
  service.actions.selectStaffMember(staffMember.id);
91
92
  };
@@ -113,10 +114,10 @@ export function StaffMemberProvider(props) {
113
114
  * ```
114
115
  */
115
116
  export function Info(props) {
116
- const { slot, isSelected } = useTimeSlotContext();
117
- const startDate = slot.localStartDate ?? undefined;
118
- const endDate = slot.localEndDate ?? undefined;
119
- const bookable = slot.bookable ?? false;
117
+ const { timeSlot, isSelected } = useTimeSlotContext();
118
+ const startDate = timeSlot.localStartDate ?? undefined;
119
+ const endDate = timeSlot.localEndDate ?? undefined;
120
+ const bookable = timeSlot.bookable ?? false;
120
121
  // Calculate duration from start and end dates
121
122
  let durationInMinutes = null;
122
123
  if (startDate && endDate) {
@@ -130,7 +131,7 @@ export function Info(props) {
130
131
  durationInMinutes,
131
132
  bookable,
132
133
  isSelected,
133
- slot,
134
+ timeSlot,
134
135
  });
135
136
  }
136
137
  /**
@@ -154,24 +155,24 @@ export function Info(props) {
154
155
  * ```
155
156
  */
156
157
  export function Actions(props) {
157
- const { selectSlot, slot, isSelected } = useTimeSlotContext();
158
- const service = useTimeSlotListService();
158
+ const { selectTimeSlot, timeSlot, isSelected } = useTimeSlotContext();
159
+ const service = useService(TimeSlotListServiceDefinition);
159
160
  const selection = service.selection.get();
160
- const bookable = slot.bookable ?? false;
161
+ const bookable = timeSlot.bookable ?? false;
161
162
  // Check if at least one preference is selected
162
163
  const hasPreferenceSelected = !!selection?.locationId || !!selection?.staffMemberId;
163
164
  // Check if there are multiple options
164
- const locationCount = slot.staffByLocation.length;
165
- const staffCount = new Set(slot.staffByLocation.flatMap(({ staffMembers }) => staffMembers.map((s) => s.id))).size;
165
+ const locationCount = timeSlot.staffByLocation.length;
166
+ const staffCount = new Set(timeSlot.staffByLocation.flatMap(({ staffMembers }) => staffMembers.map((s) => s.id))).size;
166
167
  const hasMultipleOptions = locationCount > 1 || staffCount > 1;
167
168
  const shouldShowClearPreferences = hasPreferenceSelected && hasMultipleOptions;
168
169
  const clearPreferences = shouldShowClearPreferences
169
170
  ? service.actions.clearPreferences
170
171
  : undefined;
171
172
  return props.children({
172
- selectSlot,
173
+ selectTimeSlot,
173
174
  clearPreferences,
174
- slot,
175
+ timeSlot,
175
176
  bookable,
176
177
  isSelected,
177
178
  });
@@ -181,6 +182,8 @@ export function Actions(props) {
181
182
  * Extracts locations from slot.staffByLocation and enriches with name from originalSlots.
182
183
  * Each location includes isSelected and isSelectable based on current selection state.
183
184
  *
185
+ * Returns null if there's only 1 location (nothing to choose from).
186
+ *
184
187
  * @component
185
188
  * @example
186
189
  * ```tsx
@@ -194,13 +197,13 @@ export function Actions(props) {
194
197
  * ```
195
198
  */
196
199
  export function Locations(props) {
197
- const { slot } = useTimeSlotContext();
198
- const service = useTimeSlotListService();
200
+ const { timeSlot } = useTimeSlotContext();
201
+ const service = useService(TimeSlotListServiceDefinition);
199
202
  const selection = service.selection.get();
200
203
  const selectedLocationId = selection?.locationId ?? null;
201
204
  const selectedStaffMemberId = selection?.staffMemberId ?? null;
202
205
  // Build locations array from staffByLocation (names already included)
203
- const locations = slot.staffByLocation.map(({ location, staffMembers }) => {
206
+ const locations = timeSlot.staffByLocation.map(({ location, staffMembers }) => {
204
207
  // Check if this location is selectable based on selected staff
205
208
  // If no staff selected, all locations are selectable
206
209
  // If staff selected, only locations where that staff works are selectable
@@ -214,6 +217,10 @@ export function Locations(props) {
214
217
  isSelectable,
215
218
  };
216
219
  });
220
+ // Return null if only 1 location - nothing to choose from
221
+ if (locations.length <= 1) {
222
+ return null;
223
+ }
217
224
  return props.children({
218
225
  locations,
219
226
  selectLocation: service.actions.selectLocation,
@@ -272,6 +279,8 @@ export function LocationActions(props) {
272
279
  * Extracts unique staff members from slot.staffByLocation (names already included).
273
280
  * Each staff member includes isSelected and isSelectable based on current selection state.
274
281
  *
282
+ * Returns null if there's only 1 staff member (nothing to choose from).
283
+ *
275
284
  * @component
276
285
  * @example
277
286
  * ```tsx
@@ -285,14 +294,14 @@ export function LocationActions(props) {
285
294
  * ```
286
295
  */
287
296
  export function StaffMembers(props) {
288
- const { slot } = useTimeSlotContext();
289
- const service = useTimeSlotListService();
297
+ const { timeSlot } = useTimeSlotContext();
298
+ const service = useService(TimeSlotListServiceDefinition);
290
299
  const selection = service.selection.get();
291
300
  const selectedStaffMemberId = selection?.staffMemberId ?? null;
292
301
  const selectedLocationId = selection?.locationId ?? null;
293
302
  // Build unique staff members array from staffByLocation
294
303
  // Flatten all staff members with their location IDs, then dedupe by ID
295
- const allStaff = slot.staffByLocation.flatMap(({ location, staffMembers }) => staffMembers.map((s) => ({ ...s, locationId: location.id })));
304
+ const allStaff = timeSlot.staffByLocation.flatMap(({ location, staffMembers }) => staffMembers.map((s) => ({ ...s, locationId: location.id })));
296
305
  // Group by staff ID to get all locations per staff member
297
306
  const grouped = Object.groupBy(allStaff, (s) => s.id);
298
307
  const staffMembers = Object.entries(grouped).map(([id, entries]) => ({
@@ -302,6 +311,10 @@ export function StaffMembers(props) {
302
311
  isSelectable: !selectedLocationId ||
303
312
  entries.some((e) => e.locationId === selectedLocationId),
304
313
  }));
314
+ // Return null if only 1 staff member - nothing to choose from
315
+ if (staffMembers.length <= 1) {
316
+ return null;
317
+ }
305
318
  return props.children({
306
319
  staffMembers,
307
320
  selectStaffMember: service.actions.selectStaffMember,
@@ -3,11 +3,7 @@
3
3
  * Provides low-level access to TimeSlotListService via render props
4
4
  */
5
5
  import React from 'react';
6
- import { type TimeSlotListServiceAPI, type TimeSlotListServiceConfig, type TimeSlot } from '../../../services/time-slot-list/index.js';
7
- /**
8
- * Hook to access TimeSlotListService from within TimeSlotList.Root
9
- */
10
- export declare const useTimeSlotListService: () => TimeSlotListServiceAPI;
6
+ import { type TimeSlotListServiceConfig, type TimeSlot } from '../../../services/time-slot-list/index.js';
11
7
  /**
12
8
  * Props for Root component
13
9
  */
@@ -32,7 +28,10 @@ export declare function Root(props: RootProps): React.ReactNode;
32
28
  */
33
29
  export interface TimezoneProps {
34
30
  children: (data: {
31
+ /** Raw IANA timezone string (e.g., "America/New_York") */
35
32
  timezone: string | undefined;
33
+ /** User-friendly display name (e.g., "Eastern Standard Time") */
34
+ displayName: string;
36
35
  }) => React.ReactNode;
37
36
  }
38
37
  /**
@@ -42,8 +41,8 @@ export interface TimezoneProps {
42
41
  * @example
43
42
  * ```tsx
44
43
  * <Timezone>
45
- * {({ timezone }) => (
46
- * <span>{timezone}</span>
44
+ * {({ timezone, displayName }) => (
45
+ * <span>{displayName}</span> // "Eastern Standard Time"
47
46
  * )}
48
47
  * </Timezone>
49
48
  * ```
@@ -82,3 +81,36 @@ export interface ListDataProps {
82
81
  * ```
83
82
  */
84
83
  export declare function ListData(props: ListDataProps): React.ReactNode;
84
+ /**
85
+ * Render props for DateRange component
86
+ */
87
+ export interface DateRangeRenderProps {
88
+ startDate: Date;
89
+ endDate: Date;
90
+ setDateRange: (start: Date, end: Date) => void;
91
+ }
92
+ /**
93
+ * Props for DateRange render prop component
94
+ */
95
+ export interface DateRangeProps {
96
+ children: (data: DateRangeRenderProps) => React.ReactNode;
97
+ }
98
+ /**
99
+ * Core component that provides access to date range data and actions via render props.
100
+ * Use this to build date range inputs for calendar/week view navigation.
101
+ *
102
+ * @component
103
+ * @example
104
+ * ```tsx
105
+ * <DateRange>
106
+ * {({ startDate, endDate, setDateRange }) => (
107
+ * <MyDateRangePicker
108
+ * start={startDate}
109
+ * end={endDate}
110
+ * onChange={(start, end) => setDateRange(start, end)}
111
+ * />
112
+ * )}
113
+ * </DateRange>
114
+ * ```
115
+ */
116
+ export declare function DateRange(props: DateRangeProps): React.ReactNode;
@@ -2,12 +2,6 @@ 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
- /**
6
- * Hook to access TimeSlotListService from within TimeSlotList.Root
7
- */
8
- export const useTimeSlotListService = () => {
9
- return useService(TimeSlotListServiceDefinition);
10
- };
11
5
  /**
12
6
  * Root component that provides TimeSlotListService context to its children.
13
7
  *
@@ -22,6 +16,30 @@ export const useTimeSlotListService = () => {
22
16
  export function Root(props) {
23
17
  return (_jsx(WixServices, { servicesMap: createServicesMap().addService(TimeSlotListServiceDefinition, TimeSlotListService, props.config || {}), children: props.children }));
24
18
  }
19
+ // ============================================================================
20
+ // Timezone Component
21
+ // ============================================================================
22
+ /**
23
+ * Gets the display name for a timezone using Intl.DateTimeFormat
24
+ * @param timezone - IANA timezone string (e.g., "America/New_York")
25
+ * @returns User-friendly display name (e.g., "Eastern Standard Time")
26
+ */
27
+ function getTimezoneDisplayName(timezone) {
28
+ if (!timezone)
29
+ return '';
30
+ try {
31
+ const formatter = new Intl.DateTimeFormat('en', {
32
+ timeZone: timezone,
33
+ timeZoneName: 'long',
34
+ });
35
+ const parts = formatter.formatToParts(new Date());
36
+ const timeZonePart = parts.find((part) => part.type === 'timeZoneName');
37
+ return timeZonePart?.value || timezone;
38
+ }
39
+ catch {
40
+ return timezone;
41
+ }
42
+ }
25
43
  /**
26
44
  * Core component that provides access to the current timezone via render props.
27
45
  *
@@ -29,16 +47,17 @@ export function Root(props) {
29
47
  * @example
30
48
  * ```tsx
31
49
  * <Timezone>
32
- * {({ timezone }) => (
33
- * <span>{timezone}</span>
50
+ * {({ timezone, displayName }) => (
51
+ * <span>{displayName}</span> // "Eastern Standard Time"
34
52
  * )}
35
53
  * </Timezone>
36
54
  * ```
37
55
  */
38
56
  export function Timezone(props) {
39
- const service = useTimeSlotListService();
57
+ const service = useService(TimeSlotListServiceDefinition);
40
58
  const timezone = service.timezone.get();
41
- return props.children({ timezone });
59
+ const displayName = getTimezoneDisplayName(timezone);
60
+ return props.children({ timezone, displayName });
42
61
  }
43
62
  /**
44
63
  * Core component that provides access to time slots list data via render props.
@@ -57,7 +76,7 @@ export function Timezone(props) {
57
76
  * ```
58
77
  */
59
78
  export function ListData(props) {
60
- const service = useTimeSlotListService();
79
+ const service = useService(TimeSlotListServiceDefinition);
61
80
  return props.children({
62
81
  timeSlots: service.timeSlots.get(),
63
82
  hasMore: service.hasMore.get(),
@@ -66,3 +85,29 @@ export function ListData(props) {
66
85
  loadMore: service.actions.loadMore,
67
86
  });
68
87
  }
88
+ /**
89
+ * Core component that provides access to date range data and actions via render props.
90
+ * Use this to build date range inputs for calendar/week view navigation.
91
+ *
92
+ * @component
93
+ * @example
94
+ * ```tsx
95
+ * <DateRange>
96
+ * {({ startDate, endDate, setDateRange }) => (
97
+ * <MyDateRangePicker
98
+ * start={startDate}
99
+ * end={endDate}
100
+ * onChange={(start, end) => setDateRange(start, end)}
101
+ * />
102
+ * )}
103
+ * </DateRange>
104
+ * ```
105
+ */
106
+ export function DateRange(props) {
107
+ const service = useService(TimeSlotListServiceDefinition);
108
+ return props.children({
109
+ startDate: service.startDate.get(),
110
+ endDate: service.endDate.get(),
111
+ setDateRange: service.actions.setDateRange,
112
+ });
113
+ }
@@ -128,13 +128,13 @@ Duration.displayName = 'TimeSlot.Duration';
128
128
  */
129
129
  export const Select = React.forwardRef((props, ref) => {
130
130
  const { asChild, children, className, label } = props;
131
- return (_jsx(CoreTimeSlot.Actions, { children: ({ selectSlot, isSelected, bookable }) => {
131
+ return (_jsx(CoreTimeSlot.Actions, { children: ({ selectTimeSlot, isSelected, bookable }) => {
132
132
  return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotActionSelect, "data-selected": isSelected, "data-bookable": bookable, customElement: children, customElementProps: {
133
- onClick: selectSlot,
133
+ onClick: selectTimeSlot,
134
134
  disabled: !bookable,
135
135
  isSelected,
136
136
  bookable,
137
- }, children: _jsx("button", { onClick: selectSlot, disabled: !bookable, children: label }) }));
137
+ }, children: _jsx("button", { onClick: selectTimeSlot, disabled: !bookable, children: label }) }));
138
138
  } }));
139
139
  });
140
140
  Select.displayName = 'TimeSlot.Actions.Select';