@wix/headless-bookings 0.0.16 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/dist/api/time-slot-list/index.d.ts +21 -1
- package/cjs/dist/api/time-slot-list/index.js +46 -8
- package/cjs/dist/react/core/time-slot-list/TimeSlot.d.ts +22 -18
- package/cjs/dist/react/core/time-slot-list/TimeSlot.js +41 -28
- package/cjs/dist/react/core/time-slot-list/TimeSlotList.d.ts +39 -7
- package/cjs/dist/react/core/time-slot-list/TimeSlotList.js +56 -11
- package/cjs/dist/react/time-slot-list/TimeSlot.js +3 -3
- package/cjs/dist/react/time-slot-list/TimeSlotList.d.ts +55 -12
- package/cjs/dist/react/time-slot-list/TimeSlotList.js +48 -18
- package/cjs/dist/services/index.d.ts +2 -2
- package/cjs/dist/services/time-slot-list/index.d.ts +1 -1
- package/cjs/dist/services/time-slot-list/time-slot-list.d.ts +3 -3
- package/cjs/dist/services/time-slot-list/time-slot-list.def.d.ts +23 -4
- package/cjs/dist/services/time-slot-list/time-slot-list.js +37 -9
- package/dist/api/time-slot-list/index.d.ts +21 -1
- package/dist/api/time-slot-list/index.js +46 -8
- package/dist/react/core/time-slot-list/TimeSlot.d.ts +22 -18
- package/dist/react/core/time-slot-list/TimeSlot.js +41 -28
- package/dist/react/core/time-slot-list/TimeSlotList.d.ts +39 -7
- package/dist/react/core/time-slot-list/TimeSlotList.js +56 -11
- package/dist/react/time-slot-list/TimeSlot.js +3 -3
- package/dist/react/time-slot-list/TimeSlotList.d.ts +55 -12
- package/dist/react/time-slot-list/TimeSlotList.js +48 -18
- package/dist/services/index.d.ts +2 -2
- package/dist/services/time-slot-list/index.d.ts +1 -1
- package/dist/services/time-slot-list/time-slot-list.d.ts +3 -3
- package/dist/services/time-slot-list/time-slot-list.def.d.ts +23 -4
- package/dist/services/time-slot-list/time-slot-list.js +37 -9
- package/package.json +3 -2
|
@@ -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 {
|
|
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,
|
|
29
|
-
const service =
|
|
29
|
+
const { children, timeSlot } = props;
|
|
30
|
+
const service = useService(TimeSlotListServiceDefinition);
|
|
30
31
|
const selection = service.selection.get();
|
|
31
|
-
const isSelected = selection?.slot?.id ===
|
|
32
|
-
const
|
|
33
|
-
service.actions.selectSlot(
|
|
32
|
+
const isSelected = selection?.slot?.id === timeSlot.id;
|
|
33
|
+
const selectTimeSlot = () => {
|
|
34
|
+
service.actions.selectSlot(timeSlot);
|
|
34
35
|
};
|
|
35
36
|
const contextValue = {
|
|
36
|
-
|
|
37
|
+
timeSlot,
|
|
37
38
|
isSelected,
|
|
38
|
-
|
|
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 =
|
|
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 =
|
|
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 {
|
|
117
|
-
const startDate =
|
|
118
|
-
const endDate =
|
|
119
|
-
const bookable =
|
|
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
|
-
|
|
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 {
|
|
158
|
-
const service =
|
|
158
|
+
const { selectTimeSlot, timeSlot, isSelected } = useTimeSlotContext();
|
|
159
|
+
const service = useService(TimeSlotListServiceDefinition);
|
|
159
160
|
const selection = service.selection.get();
|
|
160
|
-
const bookable =
|
|
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 =
|
|
165
|
-
const staffCount = new Set(
|
|
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
|
-
|
|
173
|
+
selectTimeSlot,
|
|
173
174
|
clearPreferences,
|
|
174
|
-
|
|
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 {
|
|
198
|
-
const service =
|
|
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 =
|
|
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 {
|
|
289
|
-
const service =
|
|
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 =
|
|
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
|
|
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>{
|
|
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>{
|
|
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 =
|
|
57
|
+
const service = useService(TimeSlotListServiceDefinition);
|
|
40
58
|
const timezone = service.timezone.get();
|
|
41
|
-
|
|
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 =
|
|
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: ({
|
|
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:
|
|
133
|
+
onClick: selectTimeSlot,
|
|
134
134
|
disabled: !bookable,
|
|
135
135
|
isSelected,
|
|
136
136
|
bookable,
|
|
137
|
-
}, children: _jsx("button", { onClick:
|
|
137
|
+
}, children: _jsx("button", { onClick: selectTimeSlot, disabled: !bookable, children: label }) }));
|
|
138
138
|
} }));
|
|
139
139
|
});
|
|
140
140
|
Select.displayName = 'TimeSlot.Actions.Select';
|
|
@@ -7,14 +7,21 @@ import { ListVariant } from '@wix/headless-components/react';
|
|
|
7
7
|
import { AsChildChildren } from '@wix/headless-utils/react';
|
|
8
8
|
import type { TimeSlotListServiceConfig } 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
|
+
/**
|
|
11
|
+
* Render props for TimeSlotList.Timezone component
|
|
12
|
+
*/
|
|
13
|
+
export interface TimezoneRenderProps {
|
|
14
|
+
/** Raw IANA timezone string (e.g., "America/New_York") */
|
|
15
|
+
timezone: string | undefined;
|
|
16
|
+
/** User-friendly display name (e.g., "Eastern Standard Time") */
|
|
17
|
+
displayName: string;
|
|
18
|
+
}
|
|
10
19
|
/**
|
|
11
20
|
* Props for TimeSlotList.Timezone component
|
|
12
21
|
*/
|
|
13
22
|
export interface TimezoneProps {
|
|
14
23
|
asChild?: boolean;
|
|
15
|
-
children?: AsChildChildren<
|
|
16
|
-
timezone: string | undefined;
|
|
17
|
-
}>;
|
|
24
|
+
children?: AsChildChildren<TimezoneRenderProps>;
|
|
18
25
|
className?: string;
|
|
19
26
|
}
|
|
20
27
|
/**
|
|
@@ -23,19 +30,14 @@ export interface TimezoneProps {
|
|
|
23
30
|
* @component
|
|
24
31
|
* @example
|
|
25
32
|
* ```tsx
|
|
26
|
-
* // Default usage
|
|
33
|
+
* // Default usage - shows display name
|
|
27
34
|
* <TimeSlotList.Timezone className="text-sm text-gray-600" />
|
|
28
35
|
*
|
|
29
|
-
* // asChild with
|
|
30
|
-
* <TimeSlotList.Timezone asChild>
|
|
31
|
-
* <span className="font-medium" />
|
|
32
|
-
* </TimeSlotList.Timezone>
|
|
33
|
-
*
|
|
34
|
-
* // asChild with render function
|
|
36
|
+
* // asChild with render function for custom formatting
|
|
35
37
|
* <TimeSlotList.Timezone asChild>
|
|
36
|
-
* {({ timezone }) => (
|
|
38
|
+
* {({ timezone, displayName }) => (
|
|
37
39
|
* <span className="text-sm">
|
|
38
|
-
*
|
|
40
|
+
* {displayName} // "Eastern Standard Time"
|
|
39
41
|
* </span>
|
|
40
42
|
* )}
|
|
41
43
|
* </TimeSlotList.Timezone>
|
|
@@ -153,6 +155,47 @@ export declare const LoadMore: React.ForwardRefExoticComponent<LoadMoreProps & R
|
|
|
153
155
|
export declare const Actions: {
|
|
154
156
|
LoadMore: React.ForwardRefExoticComponent<LoadMoreProps & React.RefAttributes<HTMLButtonElement>>;
|
|
155
157
|
};
|
|
158
|
+
/**
|
|
159
|
+
* Props for DateRange.Input component
|
|
160
|
+
*/
|
|
161
|
+
export interface DateRangeInputProps {
|
|
162
|
+
/** Whether to render as a child component */
|
|
163
|
+
asChild?: boolean;
|
|
164
|
+
/** Children for custom rendering */
|
|
165
|
+
children?: AsChildChildren<{
|
|
166
|
+
startDate: Date;
|
|
167
|
+
endDate: Date;
|
|
168
|
+
onChange: (start: Date, end: Date) => void;
|
|
169
|
+
}>;
|
|
170
|
+
/** CSS classes to apply to the container */
|
|
171
|
+
className?: string;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Date range input for setting the start and end date filter.
|
|
175
|
+
* Uses the core DateRange component to access service data.
|
|
176
|
+
* Both dates are set together and trigger a single fetch.
|
|
177
|
+
*
|
|
178
|
+
* @component
|
|
179
|
+
* @example
|
|
180
|
+
* ```tsx
|
|
181
|
+
* <TimeSlotList.DateRange.Input asChild>
|
|
182
|
+
* {({ startDate, endDate, onChange }) => (
|
|
183
|
+
* <MyDateRangePicker
|
|
184
|
+
* start={startDate}
|
|
185
|
+
* end={endDate}
|
|
186
|
+
* onRangeChange={(start, end) => onChange(start, end)}
|
|
187
|
+
* />
|
|
188
|
+
* )}
|
|
189
|
+
* </TimeSlotList.DateRange.Input>
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
export declare const DateRangeInput: React.ForwardRefExoticComponent<DateRangeInputProps & React.RefAttributes<HTMLElement>>;
|
|
193
|
+
/**
|
|
194
|
+
* DateRange namespace for TimeSlotList date range filter
|
|
195
|
+
*/
|
|
196
|
+
export declare const DateRange: {
|
|
197
|
+
Input: React.ForwardRefExoticComponent<DateRangeInputProps & React.RefAttributes<HTMLElement>>;
|
|
198
|
+
};
|
|
156
199
|
/**
|
|
157
200
|
* TimeSlot namespace containing components for displaying individual time slot data.
|
|
158
201
|
* These components must be used within TimeSlotList.TimeSlotRepeater.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* TimeSlotList - High-level component for displaying time slot list information
|
|
4
4
|
* Provides components for displaying timezone and time slot data
|
|
@@ -8,7 +8,7 @@ import { GenericList } from '@wix/headless-components/react';
|
|
|
8
8
|
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
9
9
|
import * as CoreTimeSlotList from '../core/time-slot-list/TimeSlotList.js';
|
|
10
10
|
import { TimeSlotProvider, Info as CoreTimeSlotInfo, } from '../core/time-slot-list/TimeSlot.js';
|
|
11
|
-
import { StartDate, EndDate, Duration, Actions as TimeSlotActions, Locations, LocationRepeater, Location, StaffMembers, StaffMemberRepeater, StaffMember, } from './TimeSlot.js';
|
|
11
|
+
import { StartDate as TimeSlotStartDate, EndDate as TimeSlotEndDate, Duration, Actions as TimeSlotActions, Locations, LocationRepeater, Location, StaffMembers, StaffMemberRepeater, StaffMember, } from './TimeSlot.js';
|
|
12
12
|
/**
|
|
13
13
|
* TimeSlot with required id field for GenericList
|
|
14
14
|
*/
|
|
@@ -19,6 +19,7 @@ var TestIds;
|
|
|
19
19
|
TestIds["timeSlotListTimeSlot"] = "time-slot-list-time-slot";
|
|
20
20
|
TestIds["timeSlotListTimezone"] = "time-slot-list-timezone";
|
|
21
21
|
TestIds["timeSlotListLoadMore"] = "time-slot-list-load-more";
|
|
22
|
+
TestIds["timeSlotListDateRangeInput"] = "time-slot-list-date-range-input";
|
|
22
23
|
})(TestIds || (TestIds = {}));
|
|
23
24
|
/**
|
|
24
25
|
* Displays the current timezone with customizable rendering.
|
|
@@ -26,19 +27,14 @@ var TestIds;
|
|
|
26
27
|
* @component
|
|
27
28
|
* @example
|
|
28
29
|
* ```tsx
|
|
29
|
-
* // Default usage
|
|
30
|
+
* // Default usage - shows display name
|
|
30
31
|
* <TimeSlotList.Timezone className="text-sm text-gray-600" />
|
|
31
32
|
*
|
|
32
|
-
* // asChild with
|
|
33
|
+
* // asChild with render function for custom formatting
|
|
33
34
|
* <TimeSlotList.Timezone asChild>
|
|
34
|
-
*
|
|
35
|
-
* </TimeSlotList.Timezone>
|
|
36
|
-
*
|
|
37
|
-
* // asChild with render function
|
|
38
|
-
* <TimeSlotList.Timezone asChild>
|
|
39
|
-
* {({ timezone }) => (
|
|
35
|
+
* {({ timezone, displayName }) => (
|
|
40
36
|
* <span className="text-sm">
|
|
41
|
-
*
|
|
37
|
+
* {displayName} // "Eastern Standard Time"
|
|
42
38
|
* </span>
|
|
43
39
|
* )}
|
|
44
40
|
* </TimeSlotList.Timezone>
|
|
@@ -46,7 +42,7 @@ var TestIds;
|
|
|
46
42
|
*/
|
|
47
43
|
export const Timezone = React.forwardRef((props, ref) => {
|
|
48
44
|
const { asChild, children, className } = props;
|
|
49
|
-
return (_jsx(CoreTimeSlotList.Timezone, { children: ({ timezone }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotListTimezone, customElement: children, customElementProps: { timezone }, children: _jsx("span", { children:
|
|
45
|
+
return (_jsx(CoreTimeSlotList.Timezone, { children: ({ timezone, displayName }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotListTimezone, customElement: children, customElementProps: { timezone, displayName }, children: _jsx("span", { children: displayName }) })) }));
|
|
50
46
|
});
|
|
51
47
|
Timezone.displayName = 'TimeSlotList.Timezone';
|
|
52
48
|
/**
|
|
@@ -81,7 +77,7 @@ Root.displayName = 'TimeSlotList.Root';
|
|
|
81
77
|
*/
|
|
82
78
|
const RootContent = React.forwardRef((props, ref) => {
|
|
83
79
|
const { children, className, variant } = props;
|
|
84
|
-
return (_jsx(CoreTimeSlotList.ListData, { children: ({ timeSlots, hasMore, isLoading, loadMore }) => (_jsx(GenericList.Root, { items: timeSlots, loadMore: loadMore, hasMore: hasMore, isLoading: isLoading, className: className, ref: ref, "data-testid": TestIds.timeSlotListRoot, variant: variant, children: children })) }));
|
|
80
|
+
return (_jsx(CoreTimeSlotList.ListData, { children: ({ timeSlots, hasMore, isLoading, error, loadMore }) => (_jsx(GenericList.Root, { items: timeSlots, loadMore: loadMore, hasMore: hasMore, isLoading: isLoading, error: error, className: className, ref: ref, "data-testid": TestIds.timeSlotListRoot, variant: variant, children: children })) }));
|
|
85
81
|
});
|
|
86
82
|
RootContent.displayName = 'TimeSlotList.RootContent';
|
|
87
83
|
/**
|
|
@@ -107,8 +103,8 @@ TimeSlots.displayName = 'TimeSlotList.TimeSlots';
|
|
|
107
103
|
* Internal component that wraps each time slot item with context provider.
|
|
108
104
|
* This is separate to allow using the service hook within the repeater.
|
|
109
105
|
*/
|
|
110
|
-
const TimeSlotItemWrapper = ({
|
|
111
|
-
return (_jsx(TimeSlotProvider, {
|
|
106
|
+
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 })) }) }));
|
|
112
108
|
};
|
|
113
109
|
/**
|
|
114
110
|
* Repeater component that renders each time slot.
|
|
@@ -127,7 +123,7 @@ const TimeSlotItemWrapper = ({ slot, children, }) => {
|
|
|
127
123
|
*/
|
|
128
124
|
export const TimeSlotRepeater = React.forwardRef((props, ref) => {
|
|
129
125
|
const { children } = props;
|
|
130
|
-
return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: ({ item:
|
|
126
|
+
return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: ({ item: timeSlot, children: itemChildren }) => (_jsx(TimeSlotItemWrapper, { timeSlot: timeSlot, children: itemChildren }, timeSlot.id)), children: children }));
|
|
131
127
|
});
|
|
132
128
|
TimeSlotRepeater.displayName = 'TimeSlotList.TimeSlotRepeater';
|
|
133
129
|
/**
|
|
@@ -153,6 +149,40 @@ LoadMore.displayName = 'TimeSlotList.Actions.LoadMore';
|
|
|
153
149
|
export const Actions = {
|
|
154
150
|
LoadMore,
|
|
155
151
|
};
|
|
152
|
+
/**
|
|
153
|
+
* Date range input for setting the start and end date filter.
|
|
154
|
+
* Uses the core DateRange component to access service data.
|
|
155
|
+
* Both dates are set together and trigger a single fetch.
|
|
156
|
+
*
|
|
157
|
+
* @component
|
|
158
|
+
* @example
|
|
159
|
+
* ```tsx
|
|
160
|
+
* <TimeSlotList.DateRange.Input asChild>
|
|
161
|
+
* {({ startDate, endDate, onChange }) => (
|
|
162
|
+
* <MyDateRangePicker
|
|
163
|
+
* start={startDate}
|
|
164
|
+
* end={endDate}
|
|
165
|
+
* onRangeChange={(start, end) => onChange(start, end)}
|
|
166
|
+
* />
|
|
167
|
+
* )}
|
|
168
|
+
* </TimeSlotList.DateRange.Input>
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
export const DateRangeInput = React.forwardRef((props, ref) => {
|
|
172
|
+
const { asChild, children, className, ...otherProps } = props;
|
|
173
|
+
return (_jsx(CoreTimeSlotList.DateRange, { children: ({ startDate, endDate, setDateRange }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotListDateRangeInput, customElement: children, customElementProps: {
|
|
174
|
+
startDate,
|
|
175
|
+
endDate,
|
|
176
|
+
onChange: setDateRange,
|
|
177
|
+
}, ...otherProps, children: _jsxs("div", { children: [startDate.toLocaleDateString(), " - ", endDate.toLocaleDateString()] }) })) }));
|
|
178
|
+
});
|
|
179
|
+
DateRangeInput.displayName = 'TimeSlotList.DateRange.Input';
|
|
180
|
+
/**
|
|
181
|
+
* DateRange namespace for TimeSlotList date range filter
|
|
182
|
+
*/
|
|
183
|
+
export const DateRange = {
|
|
184
|
+
Input: DateRangeInput,
|
|
185
|
+
};
|
|
156
186
|
// ============================================================================
|
|
157
187
|
// TimeSlot Entity Components (re-exported)
|
|
158
188
|
// ============================================================================
|
|
@@ -186,8 +216,8 @@ export const Actions = {
|
|
|
186
216
|
* ```
|
|
187
217
|
*/
|
|
188
218
|
export const TimeSlot = {
|
|
189
|
-
StartDate,
|
|
190
|
-
EndDate,
|
|
219
|
+
StartDate: TimeSlotStartDate,
|
|
220
|
+
EndDate: TimeSlotEndDate,
|
|
191
221
|
Duration,
|
|
192
222
|
Actions: TimeSlotActions,
|
|
193
223
|
Locations,
|
package/dist/services/index.d.ts
CHANGED
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export { ServiceService, ServiceServiceDefinition, type ServiceServiceAPI, type ServiceServiceConfig, type ServiceActions, type ServicePaymentData, loadServiceServiceInitialData, type SuccessServiceServiceConfigResult, type NotFoundServiceServiceConfigResult, } from './service/service.js';
|
|
6
6
|
export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type Location, type BookingServiceActions, } from './booking/booking.js';
|
|
7
|
-
export { TimeSlotListService, TimeSlotListServiceDefinition, ViewMode, loadTimeSlotListConfig, type TimeSlotListServiceAPI, type TimeSlotListServiceActions, type TimeSlotListServiceConfig, type SlotSelection, type LoadTimeSlotListConfigOptions, type LoadTimeSlotListConfigResult, } from './time-slot-list/index.js';
|
|
8
|
-
export { ServiceListService, ServiceListServiceDefinition, type ServiceListServiceAPI, type ServiceListServiceConfig, type ServiceListActions, type QueryOptions, loadServiceListServiceInitialData, type SuccessServiceListServiceConfigResult, type ErrorServiceListServiceConfigResult, } from './service-list/service-list.js';
|
|
7
|
+
export { TimeSlotListService, TimeSlotListServiceDefinition, ViewMode, loadTimeSlotListConfig, type TimeSlotListServiceAPI, type TimeSlotListServiceActions, type TimeSlotListServiceConfig, type SlotSelection, type TimeSlot, type LoadTimeSlotListConfigOptions, type LoadTimeSlotListConfigResult, } from './time-slot-list/index.js';
|
|
8
|
+
export { ServiceListService, ServiceListServiceDefinition, type ServiceListServiceAPI, type ServiceListServiceConfig, type ServiceListFilters, type ServiceListActions, type QueryOptions, loadServiceListServiceInitialData, type SuccessServiceListServiceConfigResult, type ErrorServiceListServiceConfigResult, } from './service-list/service-list.js';
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* TimeSlotList Service
|
|
3
3
|
* Main export file for time slot list service
|
|
4
4
|
*/
|
|
5
|
-
export { TimeSlotListServiceDefinition, ViewMode, type TimeSlot, type TimeSlotListServiceAPI, type TimeSlotListServiceActions, type TimeSlotListServiceConfig, type SlotSelection, } from './time-slot-list.def.js';
|
|
5
|
+
export { TimeSlotListServiceDefinition, ViewMode, type TimeSlot, type TimeSlotListServiceAPI, type TimeSlotListServiceActions, type TimeSlotListServiceConfig, type TimeSlotsFilters, type SlotSelection, } from './time-slot-list.def.js';
|
|
6
6
|
export { TimeSlotListService, loadTimeSlotListConfig, type LoadTimeSlotListConfigOptions, type LoadTimeSlotListConfigResult, } from './time-slot-list.js';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Manages time slot fetching, selection, and state
|
|
4
4
|
*/
|
|
5
5
|
import type { Service } from '@wix/auto_sdk_bookings_services';
|
|
6
|
-
import { type TimeSlotListServiceConfig,
|
|
6
|
+
import { type TimeSlotListServiceConfig, type TimeSlotsFilters } from './time-slot-list.def.js';
|
|
7
7
|
export declare const TimeSlotListService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
8
8
|
__api: import("./time-slot-list.def.js").TimeSlotListServiceAPI;
|
|
9
9
|
__config: {};
|
|
@@ -21,8 +21,8 @@ export interface LoadTimeSlotListConfigOptions {
|
|
|
21
21
|
endDate?: Date;
|
|
22
22
|
/** Timezone for formatting (defaults to UTC) */
|
|
23
23
|
timezone?: string;
|
|
24
|
-
/**
|
|
25
|
-
|
|
24
|
+
/** Filters for narrowing down time slots */
|
|
25
|
+
filters?: TimeSlotsFilters;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
28
|
* Result type for SSR loader - either success with config or error
|