@wix/headless-bookings 0.0.12 → 0.0.14
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/index.d.ts +1 -0
- package/cjs/dist/api/index.js +1 -0
- package/cjs/dist/api/query-services/index.d.ts +6 -7
- package/cjs/dist/api/query-services/index.js +4 -4
- package/cjs/dist/api/time-slot-list/index.d.ts +53 -0
- package/cjs/dist/api/time-slot-list/index.js +133 -0
- package/cjs/dist/react/core/booking/Booking.d.ts +2 -2
- package/cjs/dist/react/core/location/Location.d.ts +3 -3
- package/cjs/dist/react/core/location/Location.js +2 -2
- package/cjs/dist/react/core/service/Service.d.ts +8 -8
- package/cjs/dist/react/core/service-list/ServiceList.d.ts +2 -2
- package/cjs/dist/react/core/time-slot-list/TimeSlot.d.ts +368 -0
- package/cjs/dist/react/core/time-slot-list/TimeSlot.js +357 -0
- package/cjs/dist/react/core/time-slot-list/TimeSlotList.d.ts +84 -0
- package/cjs/dist/react/core/time-slot-list/TimeSlotList.js +68 -0
- package/cjs/dist/react/index.d.ts +1 -0
- package/cjs/dist/react/index.js +1 -0
- package/cjs/dist/react/location/Location.d.ts +3 -3
- package/cjs/dist/react/service/Service.d.ts +9 -9
- package/cjs/dist/react/service/Service.js +5 -5
- package/cjs/dist/react/service-list/ServiceList.d.ts +3 -3
- package/cjs/dist/react/time-slot-list/TimeSlot.d.ts +438 -0
- package/cjs/dist/react/time-slot-list/TimeSlot.js +427 -0
- package/cjs/dist/react/time-slot-list/TimeSlotList.d.ts +209 -0
- package/cjs/dist/react/time-slot-list/TimeSlotList.js +199 -0
- package/cjs/dist/services/booking/booking.d.ts +12 -11
- package/cjs/dist/services/booking/booking.js +5 -3
- package/cjs/dist/services/index.d.ts +1 -0
- package/cjs/dist/services/index.js +1 -0
- package/cjs/dist/services/service/service.d.ts +5 -5
- package/cjs/dist/services/service/service.js +8 -8
- package/cjs/dist/services/service-list/service-list.d.ts +3 -3
- package/cjs/dist/services/time-slot-list/index.d.ts +6 -0
- package/cjs/dist/services/time-slot-list/index.js +6 -0
- package/cjs/dist/services/time-slot-list/time-slot-list.d.ts +58 -0
- package/cjs/dist/services/time-slot-list/time-slot-list.def.d.ts +84 -0
- package/cjs/dist/services/time-slot-list/time-slot-list.def.js +17 -0
- package/cjs/dist/services/time-slot-list/time-slot-list.js +349 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -0
- package/dist/api/query-services/index.d.ts +6 -7
- package/dist/api/query-services/index.js +4 -4
- package/dist/api/time-slot-list/index.d.ts +53 -0
- package/dist/api/time-slot-list/index.js +133 -0
- package/dist/react/core/booking/Booking.d.ts +2 -2
- package/dist/react/core/location/Location.d.ts +3 -3
- package/dist/react/core/location/Location.js +2 -2
- package/dist/react/core/service/Service.d.ts +8 -8
- package/dist/react/core/service-list/ServiceList.d.ts +2 -2
- package/dist/react/core/time-slot-list/TimeSlot.d.ts +368 -0
- package/dist/react/core/time-slot-list/TimeSlot.js +357 -0
- package/dist/react/core/time-slot-list/TimeSlotList.d.ts +84 -0
- package/dist/react/core/time-slot-list/TimeSlotList.js +68 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.js +1 -0
- package/dist/react/location/Location.d.ts +3 -3
- package/dist/react/service/Service.d.ts +9 -9
- package/dist/react/service/Service.js +5 -5
- package/dist/react/service-list/ServiceList.d.ts +3 -3
- package/dist/react/time-slot-list/TimeSlot.d.ts +438 -0
- package/dist/react/time-slot-list/TimeSlot.js +427 -0
- package/dist/react/time-slot-list/TimeSlotList.d.ts +209 -0
- package/dist/react/time-slot-list/TimeSlotList.js +199 -0
- package/dist/services/booking/booking.d.ts +12 -11
- package/dist/services/booking/booking.js +5 -3
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/service/service.d.ts +5 -5
- package/dist/services/service/service.js +8 -8
- package/dist/services/service-list/service-list.d.ts +3 -3
- package/dist/services/time-slot-list/index.d.ts +6 -0
- package/dist/services/time-slot-list/index.js +6 -0
- package/dist/services/time-slot-list/time-slot-list.d.ts +58 -0
- package/dist/services/time-slot-list/time-slot-list.def.d.ts +84 -0
- package/dist/services/time-slot-list/time-slot-list.def.js +17 -0
- package/dist/services/time-slot-list/time-slot-list.js +349 -0
- package/package.json +2 -2
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* TimeSlot - Headless components for displaying time slot information within TimeSlotList
|
|
4
|
+
* Provides components for displaying start/end times, duration, and selection actions
|
|
5
|
+
*
|
|
6
|
+
* Note: These components must be used within TimeSlotList.TimeSlotRepeater which provides
|
|
7
|
+
* the necessary context. There is no public TimeSlot.Root - context is managed internally.
|
|
8
|
+
*/
|
|
9
|
+
import React from 'react';
|
|
10
|
+
import { GenericList } from '@wix/headless-components/react';
|
|
11
|
+
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
12
|
+
import * as CoreTimeSlot from '../core/time-slot-list/TimeSlot.js';
|
|
13
|
+
// Re-export TimeSlotProvider from core for use by TimeSlotRepeater
|
|
14
|
+
export { TimeSlotProvider } from '../core/time-slot-list/TimeSlot.js';
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// TestIds
|
|
17
|
+
// ============================================================================
|
|
18
|
+
var TestIds;
|
|
19
|
+
(function (TestIds) {
|
|
20
|
+
TestIds["timeSlotStartDate"] = "time-slot-start-date";
|
|
21
|
+
TestIds["timeSlotEndDate"] = "time-slot-end-date";
|
|
22
|
+
TestIds["timeSlotDuration"] = "time-slot-duration";
|
|
23
|
+
TestIds["timeSlotActionSelect"] = "time-slot-action-select";
|
|
24
|
+
TestIds["timeSlotActionClearPreferences"] = "time-slot-action-clear-preferences";
|
|
25
|
+
// Location components
|
|
26
|
+
TestIds["timeSlotLocations"] = "time-slot-locations";
|
|
27
|
+
TestIds["timeSlotLocation"] = "time-slot-location";
|
|
28
|
+
TestIds["timeSlotLocationName"] = "time-slot-location-name";
|
|
29
|
+
TestIds["timeSlotLocationActionSelect"] = "time-slot-location-action-select";
|
|
30
|
+
// StaffMember components
|
|
31
|
+
TestIds["timeSlotStaffMembers"] = "time-slot-staff-members";
|
|
32
|
+
TestIds["timeSlotStaffMember"] = "time-slot-staff-member";
|
|
33
|
+
TestIds["timeSlotStaffMemberName"] = "time-slot-staff-member-name";
|
|
34
|
+
TestIds["timeSlotStaffMemberActionSelect"] = "time-slot-staff-member-action-select";
|
|
35
|
+
})(TestIds || (TestIds = {}));
|
|
36
|
+
/**
|
|
37
|
+
* Displays the time slot start date/time as a raw string.
|
|
38
|
+
* Consumer is responsible for formatting.
|
|
39
|
+
*
|
|
40
|
+
* @component
|
|
41
|
+
* @example
|
|
42
|
+
* ```tsx
|
|
43
|
+
* // Default usage - displays raw localStartDate string
|
|
44
|
+
* <TimeSlot.StartDate className="text-foreground" />
|
|
45
|
+
*
|
|
46
|
+
* // With custom formatting
|
|
47
|
+
* <TimeSlot.StartDate asChild>
|
|
48
|
+
* {({ startDate }) => (
|
|
49
|
+
* <span>{formatTime(startDate)}</span>
|
|
50
|
+
* )}
|
|
51
|
+
* </TimeSlot.StartDate>
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export const StartDate = React.forwardRef((props, ref) => {
|
|
55
|
+
const { asChild, children, className } = props;
|
|
56
|
+
return (_jsx(CoreTimeSlot.Info, { children: ({ startDate }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotStartDate, customElement: children, customElementProps: { startDate }, children: _jsx("span", { children: startDate }) })) }));
|
|
57
|
+
});
|
|
58
|
+
StartDate.displayName = 'TimeSlot.StartDate';
|
|
59
|
+
/**
|
|
60
|
+
* Displays the time slot end date/time as a raw string.
|
|
61
|
+
* Consumer is responsible for formatting.
|
|
62
|
+
*
|
|
63
|
+
* @component
|
|
64
|
+
* @example
|
|
65
|
+
* ```tsx
|
|
66
|
+
* // Default usage - displays raw localEndDate string
|
|
67
|
+
* <TimeSlot.EndDate className="text-foreground" />
|
|
68
|
+
*
|
|
69
|
+
* // With custom formatting
|
|
70
|
+
* <TimeSlot.EndDate asChild>
|
|
71
|
+
* {({ endDate }) => (
|
|
72
|
+
* <span>{formatTime(endDate)}</span>
|
|
73
|
+
* )}
|
|
74
|
+
* </TimeSlot.EndDate>
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export const EndDate = React.forwardRef((props, ref) => {
|
|
78
|
+
const { asChild, children, className } = props;
|
|
79
|
+
return (_jsx(CoreTimeSlot.Info, { children: ({ endDate }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotEndDate, customElement: children, customElementProps: { endDate }, children: _jsx("span", { children: endDate }) })) }));
|
|
80
|
+
});
|
|
81
|
+
EndDate.displayName = 'TimeSlot.EndDate';
|
|
82
|
+
/**
|
|
83
|
+
* Calculates and displays the duration between start and end times in minutes.
|
|
84
|
+
* Returns null if start/end dates are not available.
|
|
85
|
+
*
|
|
86
|
+
* @component
|
|
87
|
+
* @example
|
|
88
|
+
* ```tsx
|
|
89
|
+
* // Default usage - displays raw minutes number
|
|
90
|
+
* <TimeSlot.Duration className="text-foreground" />
|
|
91
|
+
*
|
|
92
|
+
* // With custom formatting
|
|
93
|
+
* <TimeSlot.Duration asChild>
|
|
94
|
+
* {({ durationInMinutes }) => (
|
|
95
|
+
* <span>{durationInMinutes} min</span>
|
|
96
|
+
* )}
|
|
97
|
+
* </TimeSlot.Duration>
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export const Duration = React.forwardRef((props, ref) => {
|
|
101
|
+
const { asChild, children, className } = props;
|
|
102
|
+
return (_jsx(CoreTimeSlot.Info, { children: ({ durationInMinutes }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotDuration, customElement: children, customElementProps: { durationInMinutes }, children: durationInMinutes && _jsx("span", { children: durationInMinutes }) })) }));
|
|
103
|
+
});
|
|
104
|
+
Duration.displayName = 'TimeSlot.Duration';
|
|
105
|
+
/**
|
|
106
|
+
* Button to select this time slot.
|
|
107
|
+
*
|
|
108
|
+
* @component
|
|
109
|
+
* @example
|
|
110
|
+
* ```tsx
|
|
111
|
+
* // Default button
|
|
112
|
+
* <TimeSlot.Actions.Select label="Select" />
|
|
113
|
+
*
|
|
114
|
+
* // With asChild
|
|
115
|
+
* <TimeSlot.Actions.Select asChild>
|
|
116
|
+
* <button className="btn-primary">Book this slot</button>
|
|
117
|
+
* </TimeSlot.Actions.Select>
|
|
118
|
+
*
|
|
119
|
+
* // Using render prop pattern
|
|
120
|
+
* <TimeSlot.Actions.Select>
|
|
121
|
+
* {({ isSelected, bookable, onClick }) => (
|
|
122
|
+
* <button onClick={onClick} disabled={!bookable}>
|
|
123
|
+
* {isSelected ? 'Selected' : 'Select'}
|
|
124
|
+
* </button>
|
|
125
|
+
* )}
|
|
126
|
+
* </TimeSlot.Actions.Select>
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
export const Select = React.forwardRef((props, ref) => {
|
|
130
|
+
const { asChild, children, className, label } = props;
|
|
131
|
+
return (_jsx(CoreTimeSlot.Actions, { children: ({ selectSlot, isSelected, bookable }) => {
|
|
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,
|
|
134
|
+
disabled: !bookable,
|
|
135
|
+
isSelected,
|
|
136
|
+
bookable,
|
|
137
|
+
}, children: _jsx("button", { onClick: selectSlot, disabled: !bookable, children: label }) }));
|
|
138
|
+
} }));
|
|
139
|
+
});
|
|
140
|
+
Select.displayName = 'TimeSlot.Actions.Select';
|
|
141
|
+
/**
|
|
142
|
+
* Button to clear location and staff preferences while keeping the slot selected.
|
|
143
|
+
* Only renders when at least one preference is selected AND there are multiple options.
|
|
144
|
+
* If it renders, clicking it will clear the preferences.
|
|
145
|
+
*
|
|
146
|
+
* @component
|
|
147
|
+
* @example
|
|
148
|
+
* ```tsx
|
|
149
|
+
* // Default button - only shows when there's something to clear
|
|
150
|
+
* <TimeSlot.Actions.ClearPreferences label="Change" />
|
|
151
|
+
*
|
|
152
|
+
* // With asChild
|
|
153
|
+
* <TimeSlot.Actions.ClearPreferences asChild>
|
|
154
|
+
* <button className="btn-secondary">Clear preferences</button>
|
|
155
|
+
* </TimeSlot.Actions.ClearPreferences>
|
|
156
|
+
*
|
|
157
|
+
* // Using render prop pattern
|
|
158
|
+
* <TimeSlot.Actions.ClearPreferences>
|
|
159
|
+
* {({ onClick }) => <button onClick={onClick}>Change selection</button>}
|
|
160
|
+
* </TimeSlot.Actions.ClearPreferences>
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
export const ClearPreferences = React.forwardRef((props, ref) => {
|
|
164
|
+
const { asChild, children, className, label } = props;
|
|
165
|
+
return (_jsx(CoreTimeSlot.Actions, { children: ({ clearPreferences }) => {
|
|
166
|
+
if (!clearPreferences) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotActionClearPreferences, customElement: children, customElementProps: {
|
|
170
|
+
onClick: clearPreferences,
|
|
171
|
+
}, children: _jsx("button", { onClick: clearPreferences, children: label }) }));
|
|
172
|
+
} }));
|
|
173
|
+
});
|
|
174
|
+
ClearPreferences.displayName = 'TimeSlot.Actions.ClearPreferences';
|
|
175
|
+
/**
|
|
176
|
+
* Actions namespace for TimeSlot
|
|
177
|
+
*/
|
|
178
|
+
export const Actions = {
|
|
179
|
+
Select,
|
|
180
|
+
ClearPreferences,
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* Container for the locations list within a time slot.
|
|
184
|
+
* Uses GenericList.Root to manage the locations list.
|
|
185
|
+
*
|
|
186
|
+
* @component
|
|
187
|
+
* @example
|
|
188
|
+
* ```tsx
|
|
189
|
+
* <TimeSlot.Locations>
|
|
190
|
+
* <TimeSlot.LocationRepeater>
|
|
191
|
+
* <TimeSlot.Location.Name />
|
|
192
|
+
* <TimeSlot.Location.Actions.Select />
|
|
193
|
+
* </TimeSlot.LocationRepeater>
|
|
194
|
+
* </TimeSlot.Locations>
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
export const Locations = React.forwardRef((props, ref) => {
|
|
198
|
+
const { children, className } = props;
|
|
199
|
+
return (_jsx(CoreTimeSlot.Locations, { children: ({ locations }) => {
|
|
200
|
+
return (_jsx(GenericList.Root, { items: locations, children: _jsx("div", { ref: ref, className: className, "data-testid": TestIds.timeSlotLocations, children: children }) }));
|
|
201
|
+
} }));
|
|
202
|
+
});
|
|
203
|
+
Locations.displayName = 'TimeSlot.Locations';
|
|
204
|
+
/**
|
|
205
|
+
* Internal component that wraps each location item with context provider.
|
|
206
|
+
*/
|
|
207
|
+
const LocationItemWrapper = ({ location, children, }) => {
|
|
208
|
+
return (_jsx(CoreTimeSlot.LocationProvider, { location: location, children: _jsx("div", { "data-testid": TestIds.timeSlotLocation, "data-location-id": location.id, "data-selected": location.isSelected, "data-selectable": location.isSelectable, children: children }) }));
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* Repeater component that renders each location.
|
|
212
|
+
* Follows Repeater Level pattern and uses GenericList.Repeater for consistency.
|
|
213
|
+
* Automatically provides Location context to children.
|
|
214
|
+
*
|
|
215
|
+
* @component
|
|
216
|
+
* @example
|
|
217
|
+
* ```tsx
|
|
218
|
+
* <TimeSlot.LocationRepeater>
|
|
219
|
+
* <div className="data-[selectable=false]:opacity-50 data-[selected=true]:bg-primary">
|
|
220
|
+
* <TimeSlot.Location.Name />
|
|
221
|
+
* <TimeSlot.Location.Actions.Select />
|
|
222
|
+
* </div>
|
|
223
|
+
* </TimeSlot.LocationRepeater>
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
export const LocationRepeater = React.forwardRef((props, ref) => {
|
|
227
|
+
const { children } = props;
|
|
228
|
+
return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: ({ item: location, children: itemChildren }) => (_jsx(LocationItemWrapper, { location: location, children: itemChildren }, location.id)), children: children }));
|
|
229
|
+
});
|
|
230
|
+
LocationRepeater.displayName = 'TimeSlot.LocationRepeater';
|
|
231
|
+
/**
|
|
232
|
+
* Displays the location name.
|
|
233
|
+
*
|
|
234
|
+
* @component
|
|
235
|
+
* @example
|
|
236
|
+
* ```tsx
|
|
237
|
+
* // Default usage
|
|
238
|
+
* <TimeSlot.Location.Name className="text-foreground" />
|
|
239
|
+
*
|
|
240
|
+
* // With custom formatting
|
|
241
|
+
* <TimeSlot.Location.Name asChild>
|
|
242
|
+
* {({ name }) => (
|
|
243
|
+
* <span className="font-bold">{name || 'Unknown Location'}</span>
|
|
244
|
+
* )}
|
|
245
|
+
* </TimeSlot.Location.Name>
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
export const LocationName = React.forwardRef((props, ref) => {
|
|
249
|
+
const { asChild, children, className } = props;
|
|
250
|
+
return (_jsx(CoreTimeSlot.LocationInfo, { children: ({ name }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotLocationName, customElement: children, customElementProps: { name }, children: _jsx("span", { children: name }) })) }));
|
|
251
|
+
});
|
|
252
|
+
LocationName.displayName = 'TimeSlot.Location.Name';
|
|
253
|
+
/**
|
|
254
|
+
* Button to select this location.
|
|
255
|
+
*
|
|
256
|
+
* @component
|
|
257
|
+
* @example
|
|
258
|
+
* ```tsx
|
|
259
|
+
* // Default button
|
|
260
|
+
* <TimeSlot.Location.Actions.Select label="Select" />
|
|
261
|
+
*
|
|
262
|
+
* // With asChild
|
|
263
|
+
* <TimeSlot.Location.Actions.Select asChild>
|
|
264
|
+
* <button className="btn-primary">Choose Location</button>
|
|
265
|
+
* </TimeSlot.Location.Actions.Select>
|
|
266
|
+
*
|
|
267
|
+
* // Using render prop pattern
|
|
268
|
+
* <TimeSlot.Location.Actions.Select>
|
|
269
|
+
* {({ isSelected, isSelectable, onClick }) => (
|
|
270
|
+
* <button onClick={onClick} disabled={!isSelectable}>
|
|
271
|
+
* {isSelected ? 'Selected' : 'Select'}
|
|
272
|
+
* </button>
|
|
273
|
+
* )}
|
|
274
|
+
* </TimeSlot.Location.Actions.Select>
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
export const SelectLocation = React.forwardRef((props, ref) => {
|
|
278
|
+
const { asChild, children, className, label } = props;
|
|
279
|
+
return (_jsx(CoreTimeSlot.LocationActions, { children: ({ selectLocation, isSelected, isSelectable }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotLocationActionSelect, "data-selected": isSelected, "data-selectable": isSelectable, customElement: children, customElementProps: {
|
|
280
|
+
onClick: selectLocation,
|
|
281
|
+
disabled: !isSelectable,
|
|
282
|
+
isSelected,
|
|
283
|
+
isSelectable,
|
|
284
|
+
}, children: _jsx("button", { onClick: selectLocation, disabled: !isSelectable, children: label }) })) }));
|
|
285
|
+
});
|
|
286
|
+
SelectLocation.displayName = 'TimeSlot.Location.Actions.Select';
|
|
287
|
+
/**
|
|
288
|
+
* Location namespace containing components for displaying individual location data.
|
|
289
|
+
* These components must be used within TimeSlot.LocationRepeater.
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* ```tsx
|
|
293
|
+
* <TimeSlot.LocationRepeater>
|
|
294
|
+
* <TimeSlot.Location.Name />
|
|
295
|
+
* <TimeSlot.Location.Actions.Select />
|
|
296
|
+
* </TimeSlot.LocationRepeater>
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
export const Location = {
|
|
300
|
+
Name: LocationName,
|
|
301
|
+
Actions: {
|
|
302
|
+
Select: SelectLocation,
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
/**
|
|
306
|
+
* Container for the staff members list within a time slot.
|
|
307
|
+
* Uses GenericList.Root to manage the staff members list.
|
|
308
|
+
*
|
|
309
|
+
* @component
|
|
310
|
+
* @example
|
|
311
|
+
* ```tsx
|
|
312
|
+
* <TimeSlot.StaffMembers>
|
|
313
|
+
* <TimeSlot.StaffMemberRepeater>
|
|
314
|
+
* <TimeSlot.StaffMember.Name />
|
|
315
|
+
* <TimeSlot.StaffMember.Actions.Select />
|
|
316
|
+
* </TimeSlot.StaffMemberRepeater>
|
|
317
|
+
* </TimeSlot.StaffMembers>
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
export const StaffMembers = React.forwardRef((props, ref) => {
|
|
321
|
+
const { children, className } = props;
|
|
322
|
+
return (_jsx(CoreTimeSlot.StaffMembers, { children: ({ staffMembers }) => {
|
|
323
|
+
return (_jsx(GenericList.Root, { items: staffMembers, children: _jsx("div", { ref: ref, className: className, "data-testid": TestIds.timeSlotStaffMembers, children: children }) }));
|
|
324
|
+
} }));
|
|
325
|
+
});
|
|
326
|
+
StaffMembers.displayName = 'TimeSlot.StaffMembers';
|
|
327
|
+
/**
|
|
328
|
+
* Internal component that wraps each staff member item with context provider.
|
|
329
|
+
*/
|
|
330
|
+
const StaffMemberItemWrapper = ({ staffMember, children, }) => {
|
|
331
|
+
return (_jsx(CoreTimeSlot.StaffMemberProvider, { staffMember: staffMember, children: _jsx("div", { "data-testid": TestIds.timeSlotStaffMember, "data-staff-member-id": staffMember.id, "data-selected": staffMember.isSelected, "data-selectable": staffMember.isSelectable, children: children }) }));
|
|
332
|
+
};
|
|
333
|
+
/**
|
|
334
|
+
* Repeater component that renders each staff member.
|
|
335
|
+
* Follows Repeater Level pattern and uses GenericList.Repeater for consistency.
|
|
336
|
+
* Automatically provides StaffMember context to children.
|
|
337
|
+
*
|
|
338
|
+
* @component
|
|
339
|
+
* @example
|
|
340
|
+
* ```tsx
|
|
341
|
+
* <TimeSlot.StaffMemberRepeater>
|
|
342
|
+
* <div className="data-[selectable=false]:opacity-50 data-[selected=true]:bg-primary">
|
|
343
|
+
* <TimeSlot.StaffMember.Name />
|
|
344
|
+
* <TimeSlot.StaffMember.Actions.Select />
|
|
345
|
+
* </div>
|
|
346
|
+
* </TimeSlot.StaffMemberRepeater>
|
|
347
|
+
* ```
|
|
348
|
+
*/
|
|
349
|
+
export const StaffMemberRepeater = React.forwardRef((props, ref) => {
|
|
350
|
+
const { children } = props;
|
|
351
|
+
return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: ({ item: staffMember, children: itemChildren }) => (_jsx(StaffMemberItemWrapper, { staffMember: staffMember, children: itemChildren }, staffMember.id)), children: children }));
|
|
352
|
+
});
|
|
353
|
+
StaffMemberRepeater.displayName = 'TimeSlot.StaffMemberRepeater';
|
|
354
|
+
/**
|
|
355
|
+
* Displays the staff member name.
|
|
356
|
+
*
|
|
357
|
+
* @component
|
|
358
|
+
* @example
|
|
359
|
+
* ```tsx
|
|
360
|
+
* // Default usage
|
|
361
|
+
* <TimeSlot.StaffMember.Name className="text-foreground" />
|
|
362
|
+
*
|
|
363
|
+
* // With custom formatting
|
|
364
|
+
* <TimeSlot.StaffMember.Name asChild>
|
|
365
|
+
* {({ name }) => (
|
|
366
|
+
* <span className="font-bold">{name || 'Any Staff'}</span>
|
|
367
|
+
* )}
|
|
368
|
+
* </TimeSlot.StaffMember.Name>
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
export const StaffMemberName = React.forwardRef((props, ref) => {
|
|
372
|
+
const { asChild, children, className } = props;
|
|
373
|
+
return (_jsx(CoreTimeSlot.StaffMemberInfo, { children: ({ name }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotStaffMemberName, customElement: children, customElementProps: { name }, children: _jsx("span", { children: name }) })) }));
|
|
374
|
+
});
|
|
375
|
+
StaffMemberName.displayName = 'TimeSlot.StaffMember.Name';
|
|
376
|
+
/**
|
|
377
|
+
* Button to select this staff member.
|
|
378
|
+
*
|
|
379
|
+
* @component
|
|
380
|
+
* @example
|
|
381
|
+
* ```tsx
|
|
382
|
+
* // Default button
|
|
383
|
+
* <TimeSlot.StaffMember.Actions.Select label="Select" />
|
|
384
|
+
*
|
|
385
|
+
* // With asChild
|
|
386
|
+
* <TimeSlot.StaffMember.Actions.Select asChild>
|
|
387
|
+
* <button className="btn-primary">Choose Staff</button>
|
|
388
|
+
* </TimeSlot.StaffMember.Actions.Select>
|
|
389
|
+
*
|
|
390
|
+
* // Using render prop pattern
|
|
391
|
+
* <TimeSlot.StaffMember.Actions.Select>
|
|
392
|
+
* {({ isSelected, isSelectable, onClick }) => (
|
|
393
|
+
* <button onClick={onClick} disabled={!isSelectable}>
|
|
394
|
+
* {isSelected ? 'Selected' : 'Select'}
|
|
395
|
+
* </button>
|
|
396
|
+
* )}
|
|
397
|
+
* </TimeSlot.StaffMember.Actions.Select>
|
|
398
|
+
* ```
|
|
399
|
+
*/
|
|
400
|
+
export const SelectStaffMember = React.forwardRef((props, ref) => {
|
|
401
|
+
const { asChild, children, className, label } = props;
|
|
402
|
+
return (_jsx(CoreTimeSlot.StaffMemberActions, { children: ({ selectStaffMember, isSelected, isSelectable }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotStaffMemberActionSelect, "data-selected": isSelected, "data-selectable": isSelectable, customElement: children, customElementProps: {
|
|
403
|
+
onClick: selectStaffMember,
|
|
404
|
+
disabled: !isSelectable,
|
|
405
|
+
isSelected,
|
|
406
|
+
isSelectable,
|
|
407
|
+
}, children: _jsx("button", { onClick: selectStaffMember, disabled: !isSelectable, children: label }) })) }));
|
|
408
|
+
});
|
|
409
|
+
SelectStaffMember.displayName = 'TimeSlot.StaffMember.Actions.Select';
|
|
410
|
+
/**
|
|
411
|
+
* StaffMember namespace containing components for displaying individual staff member data.
|
|
412
|
+
* These components must be used within TimeSlot.StaffMemberRepeater.
|
|
413
|
+
*
|
|
414
|
+
* @example
|
|
415
|
+
* ```tsx
|
|
416
|
+
* <TimeSlot.StaffMemberRepeater>
|
|
417
|
+
* <TimeSlot.StaffMember.Name />
|
|
418
|
+
* <TimeSlot.StaffMember.Actions.Select />
|
|
419
|
+
* </TimeSlot.StaffMemberRepeater>
|
|
420
|
+
* ```
|
|
421
|
+
*/
|
|
422
|
+
export const StaffMember = {
|
|
423
|
+
Name: StaffMemberName,
|
|
424
|
+
Actions: {
|
|
425
|
+
Select: SelectStaffMember,
|
|
426
|
+
},
|
|
427
|
+
};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TimeSlotList - High-level component for displaying time slot list information
|
|
3
|
+
* Provides components for displaying timezone and time slot data
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { ListVariant } from '@wix/headless-components/react';
|
|
7
|
+
import { AsChildChildren } from '@wix/headless-utils/react';
|
|
8
|
+
import type { TimeSlotListServiceConfig } from '../../services/time-slot-list/time-slot-list.def.js';
|
|
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
|
+
* Props for TimeSlotList.Timezone component
|
|
12
|
+
*/
|
|
13
|
+
export interface TimezoneProps {
|
|
14
|
+
asChild?: boolean;
|
|
15
|
+
children?: AsChildChildren<{
|
|
16
|
+
timezone: string | undefined;
|
|
17
|
+
}>;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Displays the current timezone with customizable rendering.
|
|
22
|
+
*
|
|
23
|
+
* @component
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* // Default usage
|
|
27
|
+
* <TimeSlotList.Timezone className="text-sm text-gray-600" />
|
|
28
|
+
*
|
|
29
|
+
* // asChild with primitive
|
|
30
|
+
* <TimeSlotList.Timezone asChild>
|
|
31
|
+
* <span className="font-medium" />
|
|
32
|
+
* </TimeSlotList.Timezone>
|
|
33
|
+
*
|
|
34
|
+
* // asChild with render function
|
|
35
|
+
* <TimeSlotList.Timezone asChild>
|
|
36
|
+
* {({ timezone }) => (
|
|
37
|
+
* <span className="text-sm">
|
|
38
|
+
* Timezone: {timezone || 'Not set'}
|
|
39
|
+
* </span>
|
|
40
|
+
* )}
|
|
41
|
+
* </TimeSlotList.Timezone>
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare const Timezone: React.ForwardRefExoticComponent<TimezoneProps & React.RefAttributes<HTMLElement>>;
|
|
45
|
+
/**
|
|
46
|
+
* Props for TimeSlotList.Root component
|
|
47
|
+
*/
|
|
48
|
+
export interface RootProps {
|
|
49
|
+
children: React.ReactNode;
|
|
50
|
+
config?: TimeSlotListServiceConfig;
|
|
51
|
+
className?: string;
|
|
52
|
+
variant?: ListVariant;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Root component that provides the TimeSlotList service context.
|
|
56
|
+
*
|
|
57
|
+
* @order 1
|
|
58
|
+
* @component
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* import { TimeSlotList } from '@wix/bookings/components';
|
|
62
|
+
*
|
|
63
|
+
* function TimeSlotsPage({ config }) {
|
|
64
|
+
* return (
|
|
65
|
+
* <TimeSlotList.Root config={config}>
|
|
66
|
+
* <TimeSlotList.TimeSlots>
|
|
67
|
+
* <TimeSlotList.TimeSlotRepeater>
|
|
68
|
+
* {children}
|
|
69
|
+
* </TimeSlotList.TimeSlotRepeater>
|
|
70
|
+
* </TimeSlotList.TimeSlots>
|
|
71
|
+
* </TimeSlotList.Root>
|
|
72
|
+
* );
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare const Root: React.ForwardRefExoticComponent<RootProps & React.RefAttributes<HTMLElement>>;
|
|
77
|
+
/**
|
|
78
|
+
* Props for TimeSlotList.TimeSlots component
|
|
79
|
+
*/
|
|
80
|
+
export interface TimeSlotsProps {
|
|
81
|
+
children: React.ReactNode;
|
|
82
|
+
emptyState?: React.ReactNode;
|
|
83
|
+
className?: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Container for the time slots list with empty state support.
|
|
87
|
+
* Wraps GenericList.Items. Follows List Container Level pattern.
|
|
88
|
+
*
|
|
89
|
+
* @component
|
|
90
|
+
* @example
|
|
91
|
+
* ```tsx
|
|
92
|
+
* <TimeSlotList.TimeSlots emptyState={<div>No slots available</div>}>
|
|
93
|
+
* <TimeSlotList.TimeSlotRepeater>
|
|
94
|
+
* {children}
|
|
95
|
+
* </TimeSlotList.TimeSlotRepeater>
|
|
96
|
+
* </TimeSlotList.TimeSlots>
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export declare const TimeSlots: React.ForwardRefExoticComponent<TimeSlotsProps & React.RefAttributes<HTMLElement>>;
|
|
100
|
+
/**
|
|
101
|
+
* Props for TimeSlotList.TimeSlotRepeater component
|
|
102
|
+
*/
|
|
103
|
+
export interface TimeSlotRepeaterProps {
|
|
104
|
+
children: React.ReactNode;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Repeater component that renders each time slot.
|
|
108
|
+
* Follows Repeater Level pattern and uses GenericList.Repeater for consistency.
|
|
109
|
+
* Automatically provides TimeSlot context to children.
|
|
110
|
+
*
|
|
111
|
+
* @component
|
|
112
|
+
* @example
|
|
113
|
+
* ```tsx
|
|
114
|
+
* <TimeSlotList.TimeSlotRepeater>
|
|
115
|
+
* <TimeSlot.StartDate />
|
|
116
|
+
* <TimeSlot.Duration />
|
|
117
|
+
* <TimeSlot.Actions.Select />
|
|
118
|
+
* </TimeSlotList.TimeSlotRepeater>
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export declare const TimeSlotRepeater: React.ForwardRefExoticComponent<TimeSlotRepeaterProps & React.RefAttributes<HTMLElement>>;
|
|
122
|
+
/**
|
|
123
|
+
* Props for TimeSlotList.Actions.LoadMore component
|
|
124
|
+
*/
|
|
125
|
+
export interface LoadMoreProps {
|
|
126
|
+
/** Children content */
|
|
127
|
+
children?: React.ReactNode;
|
|
128
|
+
/** Whether to render as a child component */
|
|
129
|
+
asChild?: boolean;
|
|
130
|
+
/** CSS classes to apply to the button */
|
|
131
|
+
className?: string;
|
|
132
|
+
/** The label to display inside the button */
|
|
133
|
+
label?: string;
|
|
134
|
+
/** The loading state to display inside the button */
|
|
135
|
+
loadingState?: React.ReactNode;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Displays a button to load more time slots. Not rendered if no more slots are left to load.
|
|
139
|
+
* Follows the architecture rules - does not support asChild as it's a simple trigger component.
|
|
140
|
+
*
|
|
141
|
+
* @component
|
|
142
|
+
* @example
|
|
143
|
+
* ```tsx
|
|
144
|
+
* <TimeSlotList.Actions.LoadMore asChild>
|
|
145
|
+
* <button>Load More</button>
|
|
146
|
+
* </TimeSlotList.Actions.LoadMore>
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export declare const LoadMore: React.ForwardRefExoticComponent<LoadMoreProps & React.RefAttributes<HTMLButtonElement>>;
|
|
150
|
+
/**
|
|
151
|
+
* Actions namespace for TimeSlotList
|
|
152
|
+
*/
|
|
153
|
+
export declare const Actions: {
|
|
154
|
+
LoadMore: React.ForwardRefExoticComponent<LoadMoreProps & React.RefAttributes<HTMLButtonElement>>;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* TimeSlot namespace containing components for displaying individual time slot data.
|
|
158
|
+
* These components must be used within TimeSlotList.TimeSlotRepeater.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```tsx
|
|
162
|
+
* <TimeSlotList.TimeSlotRepeater>
|
|
163
|
+
* <TimeSlot.StartDate />
|
|
164
|
+
* <TimeSlot.Duration />
|
|
165
|
+
* <TimeSlot.Actions.Select />
|
|
166
|
+
*
|
|
167
|
+
* // Location selection - visible when slot is selected
|
|
168
|
+
* <TimeSlot.Locations>
|
|
169
|
+
* <TimeSlot.LocationRepeater>
|
|
170
|
+
* <TimeSlot.Location.Name />
|
|
171
|
+
* <TimeSlot.Location.Actions.Select />
|
|
172
|
+
* </TimeSlot.LocationRepeater>
|
|
173
|
+
* </TimeSlot.Locations>
|
|
174
|
+
*
|
|
175
|
+
* // Staff member selection - visible when slot is selected
|
|
176
|
+
* <TimeSlot.StaffMembers>
|
|
177
|
+
* <TimeSlot.StaffMemberRepeater>
|
|
178
|
+
* <TimeSlot.StaffMember.Name />
|
|
179
|
+
* <TimeSlot.StaffMember.Actions.Select />
|
|
180
|
+
* </TimeSlot.StaffMemberRepeater>
|
|
181
|
+
* </TimeSlot.StaffMembers>
|
|
182
|
+
* </TimeSlotList.TimeSlotRepeater>
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
export declare const TimeSlot: {
|
|
186
|
+
StartDate: React.ForwardRefExoticComponent<import("./TimeSlot.js").StartDateProps & React.RefAttributes<HTMLElement>>;
|
|
187
|
+
EndDate: React.ForwardRefExoticComponent<import("./TimeSlot.js").EndDateProps & React.RefAttributes<HTMLElement>>;
|
|
188
|
+
Duration: React.ForwardRefExoticComponent<import("./TimeSlot.js").DurationProps & React.RefAttributes<HTMLElement>>;
|
|
189
|
+
Actions: {
|
|
190
|
+
Select: React.ForwardRefExoticComponent<import("./TimeSlot.js").SelectProps & React.RefAttributes<HTMLButtonElement>>;
|
|
191
|
+
ClearPreferences: React.ForwardRefExoticComponent<import("./TimeSlot.js").ClearPreferencesProps & React.RefAttributes<HTMLButtonElement>>;
|
|
192
|
+
};
|
|
193
|
+
Locations: React.ForwardRefExoticComponent<import("./TimeSlot.js").LocationsProps & React.RefAttributes<HTMLElement>>;
|
|
194
|
+
LocationRepeater: React.ForwardRefExoticComponent<import("./TimeSlot.js").LocationRepeaterProps & React.RefAttributes<HTMLElement>>;
|
|
195
|
+
Location: {
|
|
196
|
+
Name: React.ForwardRefExoticComponent<import("./TimeSlot.js").LocationNameProps & React.RefAttributes<HTMLElement>>;
|
|
197
|
+
Actions: {
|
|
198
|
+
Select: React.ForwardRefExoticComponent<import("./TimeSlot.js").SelectLocationProps & React.RefAttributes<HTMLButtonElement>>;
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
StaffMembers: React.ForwardRefExoticComponent<import("./TimeSlot.js").StaffMembersProps & React.RefAttributes<HTMLElement>>;
|
|
202
|
+
StaffMemberRepeater: React.ForwardRefExoticComponent<import("./TimeSlot.js").StaffMemberRepeaterProps & React.RefAttributes<HTMLElement>>;
|
|
203
|
+
StaffMember: {
|
|
204
|
+
Name: React.ForwardRefExoticComponent<import("./TimeSlot.js").StaffMemberNameProps & React.RefAttributes<HTMLElement>>;
|
|
205
|
+
Actions: {
|
|
206
|
+
Select: React.ForwardRefExoticComponent<import("./TimeSlot.js").SelectStaffMemberProps & React.RefAttributes<HTMLButtonElement>>;
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
};
|