@wix/headless-bookings 0.0.19 → 0.0.21

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.
@@ -15,8 +15,6 @@ export interface FetchAvailabilityOptions {
15
15
  staffMemberIds?: string[];
16
16
  cursorPaging?: CursorPaging;
17
17
  viewMode?: ViewMode;
18
- /** Maximum slots to return per day (useful for calendar views) */
19
- slotsPerDay?: number;
20
18
  /** Filter by bookable status. If undefined, returns both bookable and non-bookable */
21
19
  bookable?: boolean;
22
20
  /** Filter by booking policy violations */
@@ -54,20 +52,20 @@ export interface FetchAvailabilityResponse {
54
52
  * // response.timeSlots are grouped by time
55
53
  * ```
56
54
  */
57
- export declare function fetchAvailability({ services: selectedServices, viewMode, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursorPaging, slotsPerDay, bookable, bookingPolicyViolations, }: {
55
+ export declare function fetchAvailability({ services: selectedServices, viewMode, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, }: {
58
56
  services: Service[];
59
57
  fromLocalDate: string;
60
58
  toLocalDate: string;
61
59
  timeZone?: string;
62
60
  locations?: Location[];
63
61
  staffMemberIds?: string[];
64
- cursorPaging?: CursorPaging;
62
+ cursor?: string;
65
63
  viewMode?: ViewMode;
66
- slotsPerDay?: number;
67
64
  bookable?: boolean;
68
65
  bookingPolicyViolations?: {
69
66
  tooEarlyToBook?: boolean;
70
67
  tooLateToBook?: boolean;
71
68
  bookOnlineDisabled?: boolean;
72
69
  };
70
+ slotsPerPage?: number;
73
71
  }): Promise<FetchAvailabilityResponse>;
@@ -5,6 +5,7 @@
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 { ANY_STAFF_MEMBER_ID } from '../../services/booking/booking.js';
8
9
  import { ViewMode, } from '../../services/time-slot-list/time-slot-list.def.js';
9
10
  // ============================================================================
10
11
  // Internal Types
@@ -15,6 +16,7 @@ var FlowType;
15
16
  FlowType["MULTI_SERVICE"] = "multi_service";
16
17
  FlowType["CLASS"] = "class";
17
18
  })(FlowType || (FlowType = {}));
19
+ const STAFF_RESOURCE_TYPE_ID = '1cd44cf8-756f-41c3-bd90-3e2ffcaf1155';
18
20
  // ============================================================================
19
21
  // Grouping Functions
20
22
  // ============================================================================
@@ -102,16 +104,15 @@ function detectFlow(bookingServices, viewMode) {
102
104
  * // response.timeSlots are grouped by time
103
105
  * ```
104
106
  */
105
- export async function fetchAvailability({ services: selectedServices, viewMode = ViewMode.CLASSIC, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursorPaging, slotsPerDay, bookable, bookingPolicyViolations, }) {
107
+ export async function fetchAvailability({ services: selectedServices, viewMode = ViewMode.CLASSIC, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, }) {
106
108
  const flow = detectFlow(selectedServices, viewMode);
107
109
  const serviceIds = selectedServices.map((s) => s._id);
108
110
  if (flow === FlowType.SINGLE_SERVICE) {
109
- // Build resourceTypes filter for staff members
110
- // Staff member resource type ID is 1cd44cf8-756f-41c3-bd90-3e2ffcaf1155
111
- const resourceTypes = staffMemberIds?.length
111
+ const isAnyStaffMemberSelected = staffMemberIds?.length === 1 && staffMemberIds[0] === ANY_STAFF_MEMBER_ID;
112
+ const resourceTypes = staffMemberIds?.length && !isAnyStaffMemberSelected
112
113
  ? [
113
114
  {
114
- resourceTypeId: '1cd44cf8-756f-41c3-bd90-3e2ffcaf1155',
115
+ resourceTypeId: STAFF_RESOURCE_TYPE_ID,
115
116
  resourceIds: staffMemberIds,
116
117
  },
117
118
  ]
@@ -122,11 +123,16 @@ export async function fetchAvailability({ services: selectedServices, viewMode =
122
123
  toLocalDate,
123
124
  timeZone,
124
125
  locations,
125
- cursorPaging,
126
+ cursorPaging: {
127
+ cursor,
128
+ limit: slotsPerPage,
129
+ },
126
130
  resourceTypes,
127
- timeSlotsPerDay: slotsPerDay,
128
131
  bookable,
129
132
  bookingPolicyViolations,
133
+ includeResourceTypeIds: isAnyStaffMemberSelected
134
+ ? undefined
135
+ : [STAFF_RESOURCE_TYPE_ID],
130
136
  });
131
137
  return {
132
138
  timeSlots: groupTimeSlotsByTime(response.timeSlots || []),
@@ -152,13 +158,12 @@ export async function fetchAvailability({ services: selectedServices, viewMode =
152
158
  toLocalDate,
153
159
  timeZone,
154
160
  serviceIds: serviceIds.length ? serviceIds : undefined,
155
- cursorPaging,
161
+ cursorPaging: {
162
+ cursor,
163
+ limit: slotsPerPage,
164
+ },
156
165
  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,
166
+ includeNonBookable: bookable ? !bookable : undefined,
162
167
  bookingPolicyViolations,
163
168
  });
164
169
  return {
@@ -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
@@ -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
@@ -202,12 +203,13 @@ export function Locations(props) {
202
203
  const selection = service.selection.get();
203
204
  const selectedLocationId = selection?.locationId ?? null;
204
205
  const selectedStaffMemberId = selection?.staffMemberId ?? null;
206
+ const isAnyStaffMemberSelected = selectedStaffMemberId === ANY_STAFF_MEMBER_ID;
205
207
  // Build locations array from staffByLocation (names already included)
206
208
  const locations = timeSlot.staffByLocation.map(({ location, staffMembers }) => {
207
209
  // Check if this location is selectable based on selected staff
208
210
  // If no staff selected, all locations are selectable
209
211
  // If staff selected, only locations where that staff works are selectable
210
- const isSelectable = selectedStaffMemberId
212
+ const isSelectable = !isAnyStaffMemberSelected && selectedStaffMemberId
211
213
  ? staffMembers.some((s) => s.id === selectedStaffMemberId)
212
214
  : true;
213
215
  return {
@@ -311,12 +313,18 @@ export function StaffMembers(props) {
311
313
  isSelectable: !selectedLocationId ||
312
314
  entries.some((e) => e.locationId === selectedLocationId),
313
315
  }));
316
+ const anyStaffOption = {
317
+ id: ANY_STAFF_MEMBER_ID,
318
+ name: 'Any staff member',
319
+ isSelected: selectedStaffMemberId === ANY_STAFF_MEMBER_ID,
320
+ isSelectable: true,
321
+ };
314
322
  // Return null if only 1 staff member - nothing to choose from
315
323
  if (staffMembers.length <= 1) {
316
324
  return null;
317
325
  }
318
326
  return props.children({
319
- staffMembers,
327
+ staffMembers: [anyStaffOption, ...staffMembers],
320
328
  selectStaffMember: service.actions.selectStaffMember,
321
329
  });
322
330
  }
@@ -5,7 +5,7 @@
5
5
  import React from 'react';
6
6
  import { ListVariant } from '@wix/headless-components/react';
7
7
  import { AsChildChildren } from '@wix/headless-utils/react';
8
- import type { TimeSlotListServiceConfig } from '../../services/time-slot-list/time-slot-list.def.js';
8
+ import type { TimeSlotListServiceConfig, TimeSlot as TimeSlotType } from '../../services/time-slot-list/time-slot-list.def.js';
9
9
  export type { StartDateProps as TimeSlotStartDateProps, EndDateProps as TimeSlotEndDateProps, DurationProps as TimeSlotDurationProps, SelectProps as TimeSlotSelectProps, LocationsProps as TimeSlotLocationsProps, LocationRepeaterProps as TimeSlotLocationRepeaterProps, LocationNameProps as TimeSlotLocationNameProps, SelectLocationProps as TimeSlotSelectLocationProps, StaffMembersProps as TimeSlotStaffMembersProps, StaffMemberRepeaterProps as TimeSlotStaffMemberRepeaterProps, StaffMemberNameProps as TimeSlotStaffMemberNameProps, SelectStaffMemberProps as TimeSlotSelectStaffMemberProps, } from './TimeSlot.js';
10
10
  /**
11
11
  * Render props for TimeSlotList.Timezone component
@@ -81,17 +81,23 @@ export declare const Root: React.ForwardRefExoticComponent<RootProps & React.Ref
81
81
  */
82
82
  export interface TimeSlotsProps {
83
83
  children: React.ReactNode;
84
+ /** Content to display when no time slots are available */
84
85
  emptyState?: React.ReactNode;
86
+ /** Content to display while time slots are loading */
87
+ loadingState?: React.ReactNode;
85
88
  className?: string;
86
89
  }
87
90
  /**
88
- * Container for the time slots list with empty state support.
91
+ * Container for the time slots list with empty state and loading state support.
89
92
  * Wraps GenericList.Items. Follows List Container Level pattern.
90
93
  *
91
94
  * @component
92
95
  * @example
93
96
  * ```tsx
94
- * <TimeSlotList.TimeSlots emptyState={<div>No slots available</div>}>
97
+ * <TimeSlotList.TimeSlots
98
+ * emptyState={<div>No slots available</div>}
99
+ * loadingState={<div>Loading...</div>}
100
+ * >
95
101
  * <TimeSlotList.TimeSlotRepeater>
96
102
  * {children}
97
103
  * </TimeSlotList.TimeSlotRepeater>
@@ -99,11 +105,32 @@ export interface TimeSlotsProps {
99
105
  * ```
100
106
  */
101
107
  export declare const TimeSlots: React.ForwardRefExoticComponent<TimeSlotsProps & React.RefAttributes<HTMLElement>>;
108
+ /**
109
+ * Data provided to TimeSlotRepeater function children
110
+ */
111
+ export interface TimeSlotRepeaterChildProps {
112
+ /** Whether the slot is currently selected */
113
+ isSelected: boolean;
114
+ /** Whether the slot can be booked */
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;
120
+ /** Duration in minutes */
121
+ durationInMinutes: number | null;
122
+ /** The raw time slot data */
123
+ timeSlot: TimeSlotType;
124
+ }
125
+ /**
126
+ * Children type for TimeSlotRepeater - can be ReactNode or function
127
+ */
128
+ type TimeSlotRepeaterChildren = React.ReactNode | ((props: TimeSlotRepeaterChildProps) => React.ReactNode);
102
129
  /**
103
130
  * Props for TimeSlotList.TimeSlotRepeater component
104
131
  */
105
132
  export interface TimeSlotRepeaterProps {
106
- children: React.ReactNode;
133
+ children: TimeSlotRepeaterChildren;
107
134
  }
108
135
  /**
109
136
  * Repeater component that renders each time slot.
@@ -113,11 +140,21 @@ export interface TimeSlotRepeaterProps {
113
140
  * @component
114
141
  * @example
115
142
  * ```tsx
143
+ * // Standard usage with nested components
116
144
  * <TimeSlotList.TimeSlotRepeater>
117
145
  * <TimeSlot.StartDate />
118
146
  * <TimeSlot.Duration />
119
147
  * <TimeSlot.Actions.Select />
120
148
  * </TimeSlotList.TimeSlotRepeater>
149
+ *
150
+ * // Function children pattern - all data available directly
151
+ * <TimeSlotList.TimeSlotRepeater>
152
+ * {({ isSelected, bookable, startDate }) => (
153
+ * <button disabled={!bookable} className={isSelected ? 'selected' : ''}>
154
+ * {formatTime(startDate)}
155
+ * </button>
156
+ * )}
157
+ * </TimeSlotList.TimeSlotRepeater>
121
158
  * ```
122
159
  */
123
160
  export declare const TimeSlotRepeater: React.ForwardRefExoticComponent<TimeSlotRepeaterProps & React.RefAttributes<HTMLElement>>;
@@ -81,13 +81,16 @@ const RootContent = React.forwardRef((props, ref) => {
81
81
  });
82
82
  RootContent.displayName = 'TimeSlotList.RootContent';
83
83
  /**
84
- * Container for the time slots list with empty state support.
84
+ * Container for the time slots list with empty state and loading state support.
85
85
  * Wraps GenericList.Items. Follows List Container Level pattern.
86
86
  *
87
87
  * @component
88
88
  * @example
89
89
  * ```tsx
90
- * <TimeSlotList.TimeSlots emptyState={<div>No slots available</div>}>
90
+ * <TimeSlotList.TimeSlots
91
+ * emptyState={<div>No slots available</div>}
92
+ * loadingState={<div>Loading...</div>}
93
+ * >
91
94
  * <TimeSlotList.TimeSlotRepeater>
92
95
  * {children}
93
96
  * </TimeSlotList.TimeSlotRepeater>
@@ -101,10 +104,12 @@ export const TimeSlots = React.forwardRef((props, ref) => {
101
104
  TimeSlots.displayName = 'TimeSlotList.TimeSlots';
102
105
  /**
103
106
  * Internal component that wraps each time slot item with context provider.
104
- * This is separate to allow using the service hook within the repeater.
107
+ * Supports both ReactNode and function children patterns.
105
108
  */
106
109
  const TimeSlotItemWrapper = ({ timeSlot, children, }) => {
107
- return (_jsx(TimeSlotProvider, { timeSlot: timeSlot, children: _jsx(CoreTimeSlotInfo, { children: ({ bookable, isSelected }) => (_jsx("div", { "data-testid": TestIds.timeSlotListTimeSlot, "data-slot-start": timeSlot.localStartDate, "data-slot-id": timeSlot.id, "data-bookable": bookable, "data-selected": isSelected, children: children })) }) }));
110
+ return (_jsx(TimeSlotProvider, { timeSlot: timeSlot, children: _jsx(CoreTimeSlotInfo, { children: (props) => {
111
+ return (_jsx("div", { "data-testid": TestIds.timeSlotListTimeSlot, "data-bookable": props.bookable, "data-selected": props.isSelected, children: typeof children === 'function' ? children(props) : children }));
112
+ } }) }));
108
113
  };
109
114
  /**
110
115
  * Repeater component that renders each time slot.
@@ -114,16 +119,26 @@ const TimeSlotItemWrapper = ({ timeSlot, children, }) => {
114
119
  * @component
115
120
  * @example
116
121
  * ```tsx
122
+ * // Standard usage with nested components
117
123
  * <TimeSlotList.TimeSlotRepeater>
118
124
  * <TimeSlot.StartDate />
119
125
  * <TimeSlot.Duration />
120
126
  * <TimeSlot.Actions.Select />
121
127
  * </TimeSlotList.TimeSlotRepeater>
128
+ *
129
+ * // Function children pattern - all data available directly
130
+ * <TimeSlotList.TimeSlotRepeater>
131
+ * {({ isSelected, bookable, startDate }) => (
132
+ * <button disabled={!bookable} className={isSelected ? 'selected' : ''}>
133
+ * {formatTime(startDate)}
134
+ * </button>
135
+ * )}
136
+ * </TimeSlotList.TimeSlotRepeater>
122
137
  * ```
123
138
  */
124
139
  export const TimeSlotRepeater = React.forwardRef((props, ref) => {
125
140
  const { children } = props;
126
- return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: ({ item: timeSlot, children: itemChildren }) => (_jsx(TimeSlotItemWrapper, { timeSlot: timeSlot, children: itemChildren }, timeSlot.id)), children: children }));
141
+ return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: ({ item: timeSlot }) => (_jsx(TimeSlotItemWrapper, { timeSlot: timeSlot, children: children }, timeSlot.id)), children: undefined }));
127
142
  });
128
143
  TimeSlotRepeater.displayName = 'TimeSlotList.TimeSlotRepeater';
129
144
  /**
@@ -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
  */
@@ -6,6 +6,10 @@
6
6
  import { defineService, implementService } from '@wix/services-definitions';
7
7
  import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
8
8
  // ============================================================================
9
+ // Constants
10
+ // ============================================================================
11
+ export const ANY_STAFF_MEMBER_ID = '__any_staff_member__';
12
+ // ============================================================================
9
13
  // Types
10
14
  // ============================================================================
11
15
  /**
@@ -51,8 +51,6 @@ export interface TimeSlotsFilters {
51
51
  locations?: Location[];
52
52
  /** Filter by specific staff member IDs */
53
53
  staffMemberIds?: string[];
54
- /** Maximum slots to return per day (useful for calendar views) */
55
- slotsPerDay?: number;
56
54
  /** Filter by bookable status. If undefined, returns both bookable and non-bookable */
57
55
  bookable?: boolean;
58
56
  /** Filter by booking policy violations */
@@ -61,6 +59,17 @@ export interface TimeSlotsFilters {
61
59
  tooLateToBook?: boolean;
62
60
  bookOnlineDisabled?: boolean;
63
61
  };
62
+ /**
63
+ * Number of time slots to load per request.
64
+ * Controls how many slots are fetched initially and on each "Load More" action.
65
+ * Default: 1000. Max: 1000.
66
+ * @example
67
+ * ```ts
68
+ * // Load 6 slots at a time
69
+ * filters: { slotsPerPage: 6 }
70
+ * ```
71
+ */
72
+ slotsPerPage?: number;
64
73
  }
65
74
  export interface TimeSlotListServiceConfig {
66
75
  /** Services to fetch time slots for */
@@ -4,9 +4,10 @@
4
4
  */
5
5
  import { implementService } from '@wix/services-definitions';
6
6
  import { SignalsServiceDefinition } from '@wix/services-definitions/core-services/signals';
7
+ import { format } from 'date-fns';
7
8
  import { TimeSlotListServiceDefinition, ViewMode, } from './time-slot-list.def.js';
8
- import { fetchAvailability } from '../../api/time-slot-list/index.js';
9
- import { BookingServiceDefinition, } from '../booking/booking.js';
9
+ import { fetchAvailability } from '../../api/fetch-availability/index.js';
10
+ import { BookingServiceDefinition, ANY_STAFF_MEMBER_ID, } from '../booking/booking.js';
10
11
  // ============================================================================
11
12
  // Helpers
12
13
  // ============================================================================
@@ -22,13 +23,8 @@ function getClientTimezone() {
22
23
  * Formats a Date to local ISO string (YYYY-MM-DDThh:mm:ss)
23
24
  */
24
25
  function toLocalDateString(date) {
25
- const year = date.getFullYear();
26
- const month = String(date.getMonth() + 1).padStart(2, '0');
27
- const day = String(date.getDate()).padStart(2, '0');
28
- const hours = String(date.getHours()).padStart(2, '0');
29
- const minutes = String(date.getMinutes()).padStart(2, '0');
30
- const seconds = String(date.getSeconds()).padStart(2, '0');
31
- return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`;
26
+ const pattern = "yyyy-MM-dd'T'HH:mm:ss";
27
+ return format(date, pattern);
32
28
  }
33
29
  /**
34
30
  * Merges new grouped slots with existing ones
@@ -88,8 +84,8 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
88
84
  const getFilters = () => {
89
85
  // Get BookingService selections (these take priority)
90
86
  const location = bookingService.location.get();
91
- const selections = bookingService.serviceSelections.get();
92
- const selectedStaffMemberIds = selections
87
+ const serviceSelections = bookingService.serviceSelections.get();
88
+ const selectedStaffMemberIds = serviceSelections
93
89
  .map(({ resources }) => resources.map((r) => r._id))
94
90
  .flat();
95
91
  const selectedLocation = location ? { _id: location.id } : null;
@@ -114,6 +110,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
114
110
  isLoadingSignal.set(true);
115
111
  errorSignal.set(null);
116
112
  cursorSignal.set(undefined);
113
+ timeSlotsSignal.set([]);
117
114
  try {
118
115
  const response = await fetchAvailability({
119
116
  services: selectedServices,
@@ -121,6 +118,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
121
118
  toLocalDate: toLocalDateString(endDateSignal.get()),
122
119
  timeZone: timezoneSignal.get(),
123
120
  viewMode: viewModeSignal.get(),
121
+ cursor: cursorSignal.get(),
124
122
  ...filters,
125
123
  });
126
124
  timeSlotsSignal.set(response.timeSlots);
@@ -245,6 +243,18 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
245
243
  const currentSelections = selectionSignal.get();
246
244
  if (!currentSelections?.slot)
247
245
  return;
246
+ if (staffMemberId === ANY_STAFF_MEMBER_ID) {
247
+ bookingService.actions.updateItem({
248
+ resources: [
249
+ {
250
+ _id: ANY_STAFF_MEMBER_ID,
251
+ name: 'Any staff member',
252
+ },
253
+ ],
254
+ });
255
+ selectionSignal.set({ ...currentSelections, staffMemberId });
256
+ return;
257
+ }
248
258
  const slot = currentSelections.slot;
249
259
  // Find all locations that have this staff member
250
260
  const locationsWithThisStaff = slot.staffByLocation.filter((loc) => loc.staffMembers.some((s) => s.id === staffMemberId));
@@ -312,7 +322,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
312
322
  fromLocalDate: toLocalDateString(startDateSignal.get()),
313
323
  toLocalDate: toLocalDateString(endDateSignal.get()),
314
324
  timeZone: timezoneSignal.get(),
315
- cursorPaging: { cursor },
325
+ cursor,
316
326
  viewMode: viewModeSignal.get(),
317
327
  ...filters,
318
328
  });
@@ -15,8 +15,6 @@ export interface FetchAvailabilityOptions {
15
15
  staffMemberIds?: string[];
16
16
  cursorPaging?: CursorPaging;
17
17
  viewMode?: ViewMode;
18
- /** Maximum slots to return per day (useful for calendar views) */
19
- slotsPerDay?: number;
20
18
  /** Filter by bookable status. If undefined, returns both bookable and non-bookable */
21
19
  bookable?: boolean;
22
20
  /** Filter by booking policy violations */
@@ -54,20 +52,20 @@ export interface FetchAvailabilityResponse {
54
52
  * // response.timeSlots are grouped by time
55
53
  * ```
56
54
  */
57
- export declare function fetchAvailability({ services: selectedServices, viewMode, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursorPaging, slotsPerDay, bookable, bookingPolicyViolations, }: {
55
+ export declare function fetchAvailability({ services: selectedServices, viewMode, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, }: {
58
56
  services: Service[];
59
57
  fromLocalDate: string;
60
58
  toLocalDate: string;
61
59
  timeZone?: string;
62
60
  locations?: Location[];
63
61
  staffMemberIds?: string[];
64
- cursorPaging?: CursorPaging;
62
+ cursor?: string;
65
63
  viewMode?: ViewMode;
66
- slotsPerDay?: number;
67
64
  bookable?: boolean;
68
65
  bookingPolicyViolations?: {
69
66
  tooEarlyToBook?: boolean;
70
67
  tooLateToBook?: boolean;
71
68
  bookOnlineDisabled?: boolean;
72
69
  };
70
+ slotsPerPage?: number;
73
71
  }): Promise<FetchAvailabilityResponse>;
@@ -5,6 +5,7 @@
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 { ANY_STAFF_MEMBER_ID } from '../../services/booking/booking.js';
8
9
  import { ViewMode, } from '../../services/time-slot-list/time-slot-list.def.js';
9
10
  // ============================================================================
10
11
  // Internal Types
@@ -15,6 +16,7 @@ var FlowType;
15
16
  FlowType["MULTI_SERVICE"] = "multi_service";
16
17
  FlowType["CLASS"] = "class";
17
18
  })(FlowType || (FlowType = {}));
19
+ const STAFF_RESOURCE_TYPE_ID = '1cd44cf8-756f-41c3-bd90-3e2ffcaf1155';
18
20
  // ============================================================================
19
21
  // Grouping Functions
20
22
  // ============================================================================
@@ -102,16 +104,15 @@ function detectFlow(bookingServices, viewMode) {
102
104
  * // response.timeSlots are grouped by time
103
105
  * ```
104
106
  */
105
- export async function fetchAvailability({ services: selectedServices, viewMode = ViewMode.CLASSIC, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursorPaging, slotsPerDay, bookable, bookingPolicyViolations, }) {
107
+ export async function fetchAvailability({ services: selectedServices, viewMode = ViewMode.CLASSIC, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, }) {
106
108
  const flow = detectFlow(selectedServices, viewMode);
107
109
  const serviceIds = selectedServices.map((s) => s._id);
108
110
  if (flow === FlowType.SINGLE_SERVICE) {
109
- // Build resourceTypes filter for staff members
110
- // Staff member resource type ID is 1cd44cf8-756f-41c3-bd90-3e2ffcaf1155
111
- const resourceTypes = staffMemberIds?.length
111
+ const isAnyStaffMemberSelected = staffMemberIds?.length === 1 && staffMemberIds[0] === ANY_STAFF_MEMBER_ID;
112
+ const resourceTypes = staffMemberIds?.length && !isAnyStaffMemberSelected
112
113
  ? [
113
114
  {
114
- resourceTypeId: '1cd44cf8-756f-41c3-bd90-3e2ffcaf1155',
115
+ resourceTypeId: STAFF_RESOURCE_TYPE_ID,
115
116
  resourceIds: staffMemberIds,
116
117
  },
117
118
  ]
@@ -122,11 +123,16 @@ export async function fetchAvailability({ services: selectedServices, viewMode =
122
123
  toLocalDate,
123
124
  timeZone,
124
125
  locations,
125
- cursorPaging,
126
+ cursorPaging: {
127
+ cursor,
128
+ limit: slotsPerPage,
129
+ },
126
130
  resourceTypes,
127
- timeSlotsPerDay: slotsPerDay,
128
131
  bookable,
129
132
  bookingPolicyViolations,
133
+ includeResourceTypeIds: isAnyStaffMemberSelected
134
+ ? undefined
135
+ : [STAFF_RESOURCE_TYPE_ID],
130
136
  });
131
137
  return {
132
138
  timeSlots: groupTimeSlotsByTime(response.timeSlots || []),
@@ -152,13 +158,12 @@ export async function fetchAvailability({ services: selectedServices, viewMode =
152
158
  toLocalDate,
153
159
  timeZone,
154
160
  serviceIds: serviceIds.length ? serviceIds : undefined,
155
- cursorPaging,
161
+ cursorPaging: {
162
+ cursor,
163
+ limit: slotsPerPage,
164
+ },
156
165
  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,
166
+ includeNonBookable: bookable ? !bookable : undefined,
162
167
  bookingPolicyViolations,
163
168
  });
164
169
  return {
@@ -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
package/dist/api/index.js CHANGED
@@ -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
@@ -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
@@ -202,12 +203,13 @@ export function Locations(props) {
202
203
  const selection = service.selection.get();
203
204
  const selectedLocationId = selection?.locationId ?? null;
204
205
  const selectedStaffMemberId = selection?.staffMemberId ?? null;
206
+ const isAnyStaffMemberSelected = selectedStaffMemberId === ANY_STAFF_MEMBER_ID;
205
207
  // Build locations array from staffByLocation (names already included)
206
208
  const locations = timeSlot.staffByLocation.map(({ location, staffMembers }) => {
207
209
  // Check if this location is selectable based on selected staff
208
210
  // If no staff selected, all locations are selectable
209
211
  // If staff selected, only locations where that staff works are selectable
210
- const isSelectable = selectedStaffMemberId
212
+ const isSelectable = !isAnyStaffMemberSelected && selectedStaffMemberId
211
213
  ? staffMembers.some((s) => s.id === selectedStaffMemberId)
212
214
  : true;
213
215
  return {
@@ -311,12 +313,18 @@ export function StaffMembers(props) {
311
313
  isSelectable: !selectedLocationId ||
312
314
  entries.some((e) => e.locationId === selectedLocationId),
313
315
  }));
316
+ const anyStaffOption = {
317
+ id: ANY_STAFF_MEMBER_ID,
318
+ name: 'Any staff member',
319
+ isSelected: selectedStaffMemberId === ANY_STAFF_MEMBER_ID,
320
+ isSelectable: true,
321
+ };
314
322
  // Return null if only 1 staff member - nothing to choose from
315
323
  if (staffMembers.length <= 1) {
316
324
  return null;
317
325
  }
318
326
  return props.children({
319
- staffMembers,
327
+ staffMembers: [anyStaffOption, ...staffMembers],
320
328
  selectStaffMember: service.actions.selectStaffMember,
321
329
  });
322
330
  }
@@ -5,7 +5,7 @@
5
5
  import React from 'react';
6
6
  import { ListVariant } from '@wix/headless-components/react';
7
7
  import { AsChildChildren } from '@wix/headless-utils/react';
8
- import type { TimeSlotListServiceConfig } from '../../services/time-slot-list/time-slot-list.def.js';
8
+ import type { TimeSlotListServiceConfig, TimeSlot as TimeSlotType } from '../../services/time-slot-list/time-slot-list.def.js';
9
9
  export type { StartDateProps as TimeSlotStartDateProps, EndDateProps as TimeSlotEndDateProps, DurationProps as TimeSlotDurationProps, SelectProps as TimeSlotSelectProps, LocationsProps as TimeSlotLocationsProps, LocationRepeaterProps as TimeSlotLocationRepeaterProps, LocationNameProps as TimeSlotLocationNameProps, SelectLocationProps as TimeSlotSelectLocationProps, StaffMembersProps as TimeSlotStaffMembersProps, StaffMemberRepeaterProps as TimeSlotStaffMemberRepeaterProps, StaffMemberNameProps as TimeSlotStaffMemberNameProps, SelectStaffMemberProps as TimeSlotSelectStaffMemberProps, } from './TimeSlot.js';
10
10
  /**
11
11
  * Render props for TimeSlotList.Timezone component
@@ -81,17 +81,23 @@ export declare const Root: React.ForwardRefExoticComponent<RootProps & React.Ref
81
81
  */
82
82
  export interface TimeSlotsProps {
83
83
  children: React.ReactNode;
84
+ /** Content to display when no time slots are available */
84
85
  emptyState?: React.ReactNode;
86
+ /** Content to display while time slots are loading */
87
+ loadingState?: React.ReactNode;
85
88
  className?: string;
86
89
  }
87
90
  /**
88
- * Container for the time slots list with empty state support.
91
+ * Container for the time slots list with empty state and loading state support.
89
92
  * Wraps GenericList.Items. Follows List Container Level pattern.
90
93
  *
91
94
  * @component
92
95
  * @example
93
96
  * ```tsx
94
- * <TimeSlotList.TimeSlots emptyState={<div>No slots available</div>}>
97
+ * <TimeSlotList.TimeSlots
98
+ * emptyState={<div>No slots available</div>}
99
+ * loadingState={<div>Loading...</div>}
100
+ * >
95
101
  * <TimeSlotList.TimeSlotRepeater>
96
102
  * {children}
97
103
  * </TimeSlotList.TimeSlotRepeater>
@@ -99,11 +105,32 @@ export interface TimeSlotsProps {
99
105
  * ```
100
106
  */
101
107
  export declare const TimeSlots: React.ForwardRefExoticComponent<TimeSlotsProps & React.RefAttributes<HTMLElement>>;
108
+ /**
109
+ * Data provided to TimeSlotRepeater function children
110
+ */
111
+ export interface TimeSlotRepeaterChildProps {
112
+ /** Whether the slot is currently selected */
113
+ isSelected: boolean;
114
+ /** Whether the slot can be booked */
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;
120
+ /** Duration in minutes */
121
+ durationInMinutes: number | null;
122
+ /** The raw time slot data */
123
+ timeSlot: TimeSlotType;
124
+ }
125
+ /**
126
+ * Children type for TimeSlotRepeater - can be ReactNode or function
127
+ */
128
+ type TimeSlotRepeaterChildren = React.ReactNode | ((props: TimeSlotRepeaterChildProps) => React.ReactNode);
102
129
  /**
103
130
  * Props for TimeSlotList.TimeSlotRepeater component
104
131
  */
105
132
  export interface TimeSlotRepeaterProps {
106
- children: React.ReactNode;
133
+ children: TimeSlotRepeaterChildren;
107
134
  }
108
135
  /**
109
136
  * Repeater component that renders each time slot.
@@ -113,11 +140,21 @@ export interface TimeSlotRepeaterProps {
113
140
  * @component
114
141
  * @example
115
142
  * ```tsx
143
+ * // Standard usage with nested components
116
144
  * <TimeSlotList.TimeSlotRepeater>
117
145
  * <TimeSlot.StartDate />
118
146
  * <TimeSlot.Duration />
119
147
  * <TimeSlot.Actions.Select />
120
148
  * </TimeSlotList.TimeSlotRepeater>
149
+ *
150
+ * // Function children pattern - all data available directly
151
+ * <TimeSlotList.TimeSlotRepeater>
152
+ * {({ isSelected, bookable, startDate }) => (
153
+ * <button disabled={!bookable} className={isSelected ? 'selected' : ''}>
154
+ * {formatTime(startDate)}
155
+ * </button>
156
+ * )}
157
+ * </TimeSlotList.TimeSlotRepeater>
121
158
  * ```
122
159
  */
123
160
  export declare const TimeSlotRepeater: React.ForwardRefExoticComponent<TimeSlotRepeaterProps & React.RefAttributes<HTMLElement>>;
@@ -81,13 +81,16 @@ const RootContent = React.forwardRef((props, ref) => {
81
81
  });
82
82
  RootContent.displayName = 'TimeSlotList.RootContent';
83
83
  /**
84
- * Container for the time slots list with empty state support.
84
+ * Container for the time slots list with empty state and loading state support.
85
85
  * Wraps GenericList.Items. Follows List Container Level pattern.
86
86
  *
87
87
  * @component
88
88
  * @example
89
89
  * ```tsx
90
- * <TimeSlotList.TimeSlots emptyState={<div>No slots available</div>}>
90
+ * <TimeSlotList.TimeSlots
91
+ * emptyState={<div>No slots available</div>}
92
+ * loadingState={<div>Loading...</div>}
93
+ * >
91
94
  * <TimeSlotList.TimeSlotRepeater>
92
95
  * {children}
93
96
  * </TimeSlotList.TimeSlotRepeater>
@@ -101,10 +104,12 @@ export const TimeSlots = React.forwardRef((props, ref) => {
101
104
  TimeSlots.displayName = 'TimeSlotList.TimeSlots';
102
105
  /**
103
106
  * Internal component that wraps each time slot item with context provider.
104
- * This is separate to allow using the service hook within the repeater.
107
+ * Supports both ReactNode and function children patterns.
105
108
  */
106
109
  const TimeSlotItemWrapper = ({ timeSlot, children, }) => {
107
- return (_jsx(TimeSlotProvider, { timeSlot: timeSlot, children: _jsx(CoreTimeSlotInfo, { children: ({ bookable, isSelected }) => (_jsx("div", { "data-testid": TestIds.timeSlotListTimeSlot, "data-slot-start": timeSlot.localStartDate, "data-slot-id": timeSlot.id, "data-bookable": bookable, "data-selected": isSelected, children: children })) }) }));
110
+ return (_jsx(TimeSlotProvider, { timeSlot: timeSlot, children: _jsx(CoreTimeSlotInfo, { children: (props) => {
111
+ return (_jsx("div", { "data-testid": TestIds.timeSlotListTimeSlot, "data-bookable": props.bookable, "data-selected": props.isSelected, children: typeof children === 'function' ? children(props) : children }));
112
+ } }) }));
108
113
  };
109
114
  /**
110
115
  * Repeater component that renders each time slot.
@@ -114,16 +119,26 @@ const TimeSlotItemWrapper = ({ timeSlot, children, }) => {
114
119
  * @component
115
120
  * @example
116
121
  * ```tsx
122
+ * // Standard usage with nested components
117
123
  * <TimeSlotList.TimeSlotRepeater>
118
124
  * <TimeSlot.StartDate />
119
125
  * <TimeSlot.Duration />
120
126
  * <TimeSlot.Actions.Select />
121
127
  * </TimeSlotList.TimeSlotRepeater>
128
+ *
129
+ * // Function children pattern - all data available directly
130
+ * <TimeSlotList.TimeSlotRepeater>
131
+ * {({ isSelected, bookable, startDate }) => (
132
+ * <button disabled={!bookable} className={isSelected ? 'selected' : ''}>
133
+ * {formatTime(startDate)}
134
+ * </button>
135
+ * )}
136
+ * </TimeSlotList.TimeSlotRepeater>
122
137
  * ```
123
138
  */
124
139
  export const TimeSlotRepeater = React.forwardRef((props, ref) => {
125
140
  const { children } = props;
126
- return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: ({ item: timeSlot, children: itemChildren }) => (_jsx(TimeSlotItemWrapper, { timeSlot: timeSlot, children: itemChildren }, timeSlot.id)), children: children }));
141
+ return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: ({ item: timeSlot }) => (_jsx(TimeSlotItemWrapper, { timeSlot: timeSlot, children: children }, timeSlot.id)), children: undefined }));
127
142
  });
128
143
  TimeSlotRepeater.displayName = 'TimeSlotList.TimeSlotRepeater';
129
144
  /**
@@ -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
  */
@@ -6,6 +6,10 @@
6
6
  import { defineService, implementService } from '@wix/services-definitions';
7
7
  import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
8
8
  // ============================================================================
9
+ // Constants
10
+ // ============================================================================
11
+ export const ANY_STAFF_MEMBER_ID = '__any_staff_member__';
12
+ // ============================================================================
9
13
  // Types
10
14
  // ============================================================================
11
15
  /**
@@ -51,8 +51,6 @@ export interface TimeSlotsFilters {
51
51
  locations?: Location[];
52
52
  /** Filter by specific staff member IDs */
53
53
  staffMemberIds?: string[];
54
- /** Maximum slots to return per day (useful for calendar views) */
55
- slotsPerDay?: number;
56
54
  /** Filter by bookable status. If undefined, returns both bookable and non-bookable */
57
55
  bookable?: boolean;
58
56
  /** Filter by booking policy violations */
@@ -61,6 +59,17 @@ export interface TimeSlotsFilters {
61
59
  tooLateToBook?: boolean;
62
60
  bookOnlineDisabled?: boolean;
63
61
  };
62
+ /**
63
+ * Number of time slots to load per request.
64
+ * Controls how many slots are fetched initially and on each "Load More" action.
65
+ * Default: 1000. Max: 1000.
66
+ * @example
67
+ * ```ts
68
+ * // Load 6 slots at a time
69
+ * filters: { slotsPerPage: 6 }
70
+ * ```
71
+ */
72
+ slotsPerPage?: number;
64
73
  }
65
74
  export interface TimeSlotListServiceConfig {
66
75
  /** Services to fetch time slots for */
@@ -4,9 +4,10 @@
4
4
  */
5
5
  import { implementService } from '@wix/services-definitions';
6
6
  import { SignalsServiceDefinition } from '@wix/services-definitions/core-services/signals';
7
+ import { format } from 'date-fns';
7
8
  import { TimeSlotListServiceDefinition, ViewMode, } from './time-slot-list.def.js';
8
- import { fetchAvailability } from '../../api/time-slot-list/index.js';
9
- import { BookingServiceDefinition, } from '../booking/booking.js';
9
+ import { fetchAvailability } from '../../api/fetch-availability/index.js';
10
+ import { BookingServiceDefinition, ANY_STAFF_MEMBER_ID, } from '../booking/booking.js';
10
11
  // ============================================================================
11
12
  // Helpers
12
13
  // ============================================================================
@@ -22,13 +23,8 @@ function getClientTimezone() {
22
23
  * Formats a Date to local ISO string (YYYY-MM-DDThh:mm:ss)
23
24
  */
24
25
  function toLocalDateString(date) {
25
- const year = date.getFullYear();
26
- const month = String(date.getMonth() + 1).padStart(2, '0');
27
- const day = String(date.getDate()).padStart(2, '0');
28
- const hours = String(date.getHours()).padStart(2, '0');
29
- const minutes = String(date.getMinutes()).padStart(2, '0');
30
- const seconds = String(date.getSeconds()).padStart(2, '0');
31
- return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`;
26
+ const pattern = "yyyy-MM-dd'T'HH:mm:ss";
27
+ return format(date, pattern);
32
28
  }
33
29
  /**
34
30
  * Merges new grouped slots with existing ones
@@ -88,8 +84,8 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
88
84
  const getFilters = () => {
89
85
  // Get BookingService selections (these take priority)
90
86
  const location = bookingService.location.get();
91
- const selections = bookingService.serviceSelections.get();
92
- const selectedStaffMemberIds = selections
87
+ const serviceSelections = bookingService.serviceSelections.get();
88
+ const selectedStaffMemberIds = serviceSelections
93
89
  .map(({ resources }) => resources.map((r) => r._id))
94
90
  .flat();
95
91
  const selectedLocation = location ? { _id: location.id } : null;
@@ -114,6 +110,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
114
110
  isLoadingSignal.set(true);
115
111
  errorSignal.set(null);
116
112
  cursorSignal.set(undefined);
113
+ timeSlotsSignal.set([]);
117
114
  try {
118
115
  const response = await fetchAvailability({
119
116
  services: selectedServices,
@@ -121,6 +118,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
121
118
  toLocalDate: toLocalDateString(endDateSignal.get()),
122
119
  timeZone: timezoneSignal.get(),
123
120
  viewMode: viewModeSignal.get(),
121
+ cursor: cursorSignal.get(),
124
122
  ...filters,
125
123
  });
126
124
  timeSlotsSignal.set(response.timeSlots);
@@ -245,6 +243,18 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
245
243
  const currentSelections = selectionSignal.get();
246
244
  if (!currentSelections?.slot)
247
245
  return;
246
+ if (staffMemberId === ANY_STAFF_MEMBER_ID) {
247
+ bookingService.actions.updateItem({
248
+ resources: [
249
+ {
250
+ _id: ANY_STAFF_MEMBER_ID,
251
+ name: 'Any staff member',
252
+ },
253
+ ],
254
+ });
255
+ selectionSignal.set({ ...currentSelections, staffMemberId });
256
+ return;
257
+ }
248
258
  const slot = currentSelections.slot;
249
259
  // Find all locations that have this staff member
250
260
  const locationsWithThisStaff = slot.staffByLocation.filter((loc) => loc.staffMembers.some((s) => s.id === staffMemberId));
@@ -312,7 +322,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
312
322
  fromLocalDate: toLocalDateString(startDateSignal.get()),
313
323
  toLocalDate: toLocalDateString(endDateSignal.get()),
314
324
  timeZone: timezoneSignal.get(),
315
- cursorPaging: { cursor },
325
+ cursor,
316
326
  viewMode: viewModeSignal.get(),
317
327
  ...filters,
318
328
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/headless-bookings",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -39,7 +39,8 @@
39
39
  "@wix/headless-media": "0.0.18",
40
40
  "@wix/headless-utils": "0.0.8",
41
41
  "@wix/services-definitions": "^0.1.4",
42
- "@wix/services-manager-react": "^0.1.26"
42
+ "@wix/services-manager-react": "^0.1.26",
43
+ "date-fns": "^4.1.0"
43
44
  },
44
45
  "devDependencies": {
45
46
  "@testing-library/dom": "^10.4.0",
@@ -69,5 +70,5 @@
69
70
  "groupId": "com.wixpress.headless-components"
70
71
  }
71
72
  },
72
- "falconPackageHash": "2a71ca796bb480604700e6cc7fde7a950ba7f71c92a189dbd0a2375a"
73
+ "falconPackageHash": "d2842c53f889bbbdfd049c74e533eef301d158412ec519b08c80c87c"
73
74
  }