@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,199 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* TimeSlotList - High-level component for displaying time slot list information
|
|
4
|
+
* Provides components for displaying timezone and time slot data
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { GenericList } from '@wix/headless-components/react';
|
|
8
|
+
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
9
|
+
import * as CoreTimeSlotList from '../core/time-slot-list/TimeSlotList.js';
|
|
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';
|
|
12
|
+
/**
|
|
13
|
+
* TimeSlot with required id field for GenericList
|
|
14
|
+
*/
|
|
15
|
+
var TestIds;
|
|
16
|
+
(function (TestIds) {
|
|
17
|
+
TestIds["timeSlotListRoot"] = "time-slot-list-root";
|
|
18
|
+
TestIds["timeSlotListTimeSlots"] = "time-slot-list-time-slots";
|
|
19
|
+
TestIds["timeSlotListTimeSlot"] = "time-slot-list-time-slot";
|
|
20
|
+
TestIds["timeSlotListTimezone"] = "time-slot-list-timezone";
|
|
21
|
+
TestIds["timeSlotListLoadMore"] = "time-slot-list-load-more";
|
|
22
|
+
})(TestIds || (TestIds = {}));
|
|
23
|
+
/**
|
|
24
|
+
* Displays the current timezone with customizable rendering.
|
|
25
|
+
*
|
|
26
|
+
* @component
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* // Default usage
|
|
30
|
+
* <TimeSlotList.Timezone className="text-sm text-gray-600" />
|
|
31
|
+
*
|
|
32
|
+
* // asChild with primitive
|
|
33
|
+
* <TimeSlotList.Timezone asChild>
|
|
34
|
+
* <span className="font-medium" />
|
|
35
|
+
* </TimeSlotList.Timezone>
|
|
36
|
+
*
|
|
37
|
+
* // asChild with render function
|
|
38
|
+
* <TimeSlotList.Timezone asChild>
|
|
39
|
+
* {({ timezone }) => (
|
|
40
|
+
* <span className="text-sm">
|
|
41
|
+
* Timezone: {timezone || 'Not set'}
|
|
42
|
+
* </span>
|
|
43
|
+
* )}
|
|
44
|
+
* </TimeSlotList.Timezone>
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export const Timezone = React.forwardRef((props, ref) => {
|
|
48
|
+
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: timezone }) })) }));
|
|
50
|
+
});
|
|
51
|
+
Timezone.displayName = 'TimeSlotList.Timezone';
|
|
52
|
+
/**
|
|
53
|
+
* Root component that provides the TimeSlotList service context.
|
|
54
|
+
*
|
|
55
|
+
* @order 1
|
|
56
|
+
* @component
|
|
57
|
+
* @example
|
|
58
|
+
* ```tsx
|
|
59
|
+
* import { TimeSlotList } from '@wix/bookings/components';
|
|
60
|
+
*
|
|
61
|
+
* function TimeSlotsPage({ config }) {
|
|
62
|
+
* return (
|
|
63
|
+
* <TimeSlotList.Root config={config}>
|
|
64
|
+
* <TimeSlotList.TimeSlots>
|
|
65
|
+
* <TimeSlotList.TimeSlotRepeater>
|
|
66
|
+
* {children}
|
|
67
|
+
* </TimeSlotList.TimeSlotRepeater>
|
|
68
|
+
* </TimeSlotList.TimeSlots>
|
|
69
|
+
* </TimeSlotList.Root>
|
|
70
|
+
* );
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export const Root = React.forwardRef((props, ref) => {
|
|
75
|
+
const { children, config, className, variant } = props;
|
|
76
|
+
return (_jsx(CoreTimeSlotList.Root, { config: config, children: _jsx(RootContent, { className: className, ref: ref, variant: variant, children: children }) }));
|
|
77
|
+
});
|
|
78
|
+
Root.displayName = 'TimeSlotList.Root';
|
|
79
|
+
/**
|
|
80
|
+
* Internal component to handle the Root content with core layer access
|
|
81
|
+
*/
|
|
82
|
+
const RootContent = React.forwardRef((props, ref) => {
|
|
83
|
+
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 })) }));
|
|
85
|
+
});
|
|
86
|
+
RootContent.displayName = 'TimeSlotList.RootContent';
|
|
87
|
+
/**
|
|
88
|
+
* Container for the time slots list with empty state support.
|
|
89
|
+
* Wraps GenericList.Items. Follows List Container Level pattern.
|
|
90
|
+
*
|
|
91
|
+
* @component
|
|
92
|
+
* @example
|
|
93
|
+
* ```tsx
|
|
94
|
+
* <TimeSlotList.TimeSlots emptyState={<div>No slots available</div>}>
|
|
95
|
+
* <TimeSlotList.TimeSlotRepeater>
|
|
96
|
+
* {children}
|
|
97
|
+
* </TimeSlotList.TimeSlotRepeater>
|
|
98
|
+
* </TimeSlotList.TimeSlots>
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export const TimeSlots = React.forwardRef((props, ref) => {
|
|
102
|
+
const { children, ...otherProps } = props;
|
|
103
|
+
return (_jsx(GenericList.Items, { ref: ref, "data-testid": TestIds.timeSlotListTimeSlots, ...otherProps, children: children }));
|
|
104
|
+
});
|
|
105
|
+
TimeSlots.displayName = 'TimeSlotList.TimeSlots';
|
|
106
|
+
/**
|
|
107
|
+
* Internal component that wraps each time slot item with context provider.
|
|
108
|
+
* This is separate to allow using the service hook within the repeater.
|
|
109
|
+
*/
|
|
110
|
+
const TimeSlotItemWrapper = ({ slot, children, }) => {
|
|
111
|
+
return (_jsx(TimeSlotProvider, { slot: slot, children: _jsx(CoreTimeSlotInfo, { children: ({ bookable, isSelected }) => (_jsx("div", { "data-testid": TestIds.timeSlotListTimeSlot, "data-slot-start": slot.localStartDate, "data-slot-id": slot.id, "data-bookable": bookable, "data-selected": isSelected, children: children })) }) }));
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Repeater component that renders each time slot.
|
|
115
|
+
* Follows Repeater Level pattern and uses GenericList.Repeater for consistency.
|
|
116
|
+
* Automatically provides TimeSlot context to children.
|
|
117
|
+
*
|
|
118
|
+
* @component
|
|
119
|
+
* @example
|
|
120
|
+
* ```tsx
|
|
121
|
+
* <TimeSlotList.TimeSlotRepeater>
|
|
122
|
+
* <TimeSlot.StartDate />
|
|
123
|
+
* <TimeSlot.Duration />
|
|
124
|
+
* <TimeSlot.Actions.Select />
|
|
125
|
+
* </TimeSlotList.TimeSlotRepeater>
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export const TimeSlotRepeater = React.forwardRef((props, ref) => {
|
|
129
|
+
const { children } = props;
|
|
130
|
+
return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: ({ item: slot, children: itemChildren }) => (_jsx(TimeSlotItemWrapper, { slot: slot, children: itemChildren }, slot.id)), children: children }));
|
|
131
|
+
});
|
|
132
|
+
TimeSlotRepeater.displayName = 'TimeSlotList.TimeSlotRepeater';
|
|
133
|
+
/**
|
|
134
|
+
* Displays a button to load more time slots. Not rendered if no more slots are left to load.
|
|
135
|
+
* Follows the architecture rules - does not support asChild as it's a simple trigger component.
|
|
136
|
+
*
|
|
137
|
+
* @component
|
|
138
|
+
* @example
|
|
139
|
+
* ```tsx
|
|
140
|
+
* <TimeSlotList.Actions.LoadMore asChild>
|
|
141
|
+
* <button>Load More</button>
|
|
142
|
+
* </TimeSlotList.Actions.LoadMore>
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
export const LoadMore = React.forwardRef((props, ref) => {
|
|
146
|
+
const { children = _jsx("button", {}), ...otherProps } = props;
|
|
147
|
+
return (_jsx(GenericList.Actions.LoadMore, { ref: ref, "data-testid": TestIds.timeSlotListLoadMore, ...otherProps, children: children }));
|
|
148
|
+
});
|
|
149
|
+
LoadMore.displayName = 'TimeSlotList.Actions.LoadMore';
|
|
150
|
+
/**
|
|
151
|
+
* Actions namespace for TimeSlotList
|
|
152
|
+
*/
|
|
153
|
+
export const Actions = {
|
|
154
|
+
LoadMore,
|
|
155
|
+
};
|
|
156
|
+
// ============================================================================
|
|
157
|
+
// TimeSlot Entity Components (re-exported)
|
|
158
|
+
// ============================================================================
|
|
159
|
+
/**
|
|
160
|
+
* TimeSlot namespace containing components for displaying individual time slot data.
|
|
161
|
+
* These components must be used within TimeSlotList.TimeSlotRepeater.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```tsx
|
|
165
|
+
* <TimeSlotList.TimeSlotRepeater>
|
|
166
|
+
* <TimeSlot.StartDate />
|
|
167
|
+
* <TimeSlot.Duration />
|
|
168
|
+
* <TimeSlot.Actions.Select />
|
|
169
|
+
*
|
|
170
|
+
* // Location selection - visible when slot is selected
|
|
171
|
+
* <TimeSlot.Locations>
|
|
172
|
+
* <TimeSlot.LocationRepeater>
|
|
173
|
+
* <TimeSlot.Location.Name />
|
|
174
|
+
* <TimeSlot.Location.Actions.Select />
|
|
175
|
+
* </TimeSlot.LocationRepeater>
|
|
176
|
+
* </TimeSlot.Locations>
|
|
177
|
+
*
|
|
178
|
+
* // Staff member selection - visible when slot is selected
|
|
179
|
+
* <TimeSlot.StaffMembers>
|
|
180
|
+
* <TimeSlot.StaffMemberRepeater>
|
|
181
|
+
* <TimeSlot.StaffMember.Name />
|
|
182
|
+
* <TimeSlot.StaffMember.Actions.Select />
|
|
183
|
+
* </TimeSlot.StaffMemberRepeater>
|
|
184
|
+
* </TimeSlot.StaffMembers>
|
|
185
|
+
* </TimeSlotList.TimeSlotRepeater>
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
export const TimeSlot = {
|
|
189
|
+
StartDate,
|
|
190
|
+
EndDate,
|
|
191
|
+
Duration,
|
|
192
|
+
Actions: TimeSlotActions,
|
|
193
|
+
Locations,
|
|
194
|
+
LocationRepeater,
|
|
195
|
+
Location,
|
|
196
|
+
StaffMembers,
|
|
197
|
+
StaffMemberRepeater,
|
|
198
|
+
StaffMember,
|
|
199
|
+
};
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Persists across page navigation in SPA until page refresh
|
|
5
5
|
*/
|
|
6
6
|
import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
7
|
-
import type {
|
|
7
|
+
import type { Service } from '@wix/auto_sdk_bookings_services';
|
|
8
|
+
import type { TimeSlot, Resource, NestedTimeSlot } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
8
9
|
import type { FormValues } from '@wix/form-public';
|
|
9
10
|
/**
|
|
10
11
|
* BookingSelection contains the service AND its related selections
|
|
@@ -12,11 +13,11 @@ import type { FormValues } from '@wix/form-public';
|
|
|
12
13
|
export interface BookingSelection {
|
|
13
14
|
/** Unique identifier for this booking instance (allows same service multiple times) */
|
|
14
15
|
instanceId: string;
|
|
15
|
-
service:
|
|
16
|
+
service: Service;
|
|
16
17
|
/** Selected resources (staff members, rooms, etc.) */
|
|
17
|
-
staff?:
|
|
18
|
+
staff?: Resource;
|
|
18
19
|
/** Per-service slot data from nested slots (for multi-service bookings) */
|
|
19
|
-
nestedSlotData?:
|
|
20
|
+
nestedSlotData?: NestedTimeSlot;
|
|
20
21
|
}
|
|
21
22
|
export interface Location {
|
|
22
23
|
id: string;
|
|
@@ -30,12 +31,12 @@ export interface BookingServiceActions {
|
|
|
30
31
|
setService(service: Omit<BookingSelection, 'instanceId'>): string;
|
|
31
32
|
/** Adds a service and returns the generated instanceId */
|
|
32
33
|
addService(service: Omit<BookingSelection, 'instanceId'>): string;
|
|
33
|
-
/** Updates a booking selection
|
|
34
|
-
|
|
35
|
-
/** Removes a
|
|
36
|
-
|
|
34
|
+
/** Updates a booking selection. If no instanceId provided, updates the first selection. */
|
|
35
|
+
updateBookingSelection(updates: Partial<Omit<BookingSelection, 'instanceId'>>, instanceId?: string): void;
|
|
36
|
+
/** Removes a booking selection. If no instanceId provided, removes the first selection. */
|
|
37
|
+
removeBookingSelection(instanceId?: string): void;
|
|
37
38
|
clearServices(): void;
|
|
38
|
-
setTimeSlot(slot:
|
|
39
|
+
setTimeSlot(slot: TimeSlot | null): void;
|
|
39
40
|
clearTimeSlot(): void;
|
|
40
41
|
setLocation(location: Location | null): void;
|
|
41
42
|
clearLocation(): void;
|
|
@@ -51,7 +52,7 @@ export interface BookingService {
|
|
|
51
52
|
/** Signal containing the booking selections (services with their related data) */
|
|
52
53
|
bookingSelections: Signal<BookingSelection[]>;
|
|
53
54
|
/** Signal containing the currently selected time slot */
|
|
54
|
-
timeSlot: Signal<
|
|
55
|
+
timeSlot: Signal<TimeSlot | null>;
|
|
55
56
|
/** Signal containing the selected location (derived from timeSlot) */
|
|
56
57
|
location: Signal<Location | null>;
|
|
57
58
|
/** Signal containing the form values */
|
|
@@ -75,7 +76,7 @@ export interface BookingServiceConfig {
|
|
|
75
76
|
/** Optional initial booking selections to pre-populate */
|
|
76
77
|
initialBookingSelections?: BookingSelection[];
|
|
77
78
|
/** Optional initial time slot to pre-populate */
|
|
78
|
-
initialTimeSlot?:
|
|
79
|
+
initialTimeSlot?: TimeSlot | null;
|
|
79
80
|
/** Optional initial form values */
|
|
80
81
|
initialFormValues?: FormValues | null;
|
|
81
82
|
}
|
|
@@ -82,12 +82,14 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
|
|
|
82
82
|
bookingSelectionsSignal.set([...current, newSelection]);
|
|
83
83
|
return instanceId;
|
|
84
84
|
},
|
|
85
|
-
|
|
85
|
+
updateBookingSelection(updates, instanceId) {
|
|
86
86
|
const current = bookingSelectionsSignal.get();
|
|
87
|
-
|
|
87
|
+
// If no instanceId provided, update the first selection (index 0)
|
|
88
|
+
const targetId = instanceId ?? current[0]?.instanceId;
|
|
89
|
+
const updated = current.map((s) => s.instanceId === targetId ? { ...s, ...updates } : s);
|
|
88
90
|
bookingSelectionsSignal.set(updated);
|
|
89
91
|
},
|
|
90
|
-
|
|
92
|
+
removeBookingSelection(instanceId) {
|
|
91
93
|
const current = bookingSelectionsSignal.get();
|
|
92
94
|
if (!instanceId) {
|
|
93
95
|
// Remove first selection if no instanceId provided
|
|
@@ -4,4 +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 BookingSelection, 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';
|
|
7
8
|
export { ServiceListService, ServiceListServiceDefinition, type ServiceListServiceAPI, type ServiceListServiceConfig, type ServiceListActions, type QueryOptions, loadServiceListServiceInitialData, type SuccessServiceListServiceConfigResult, type ErrorServiceListServiceConfigResult, } from './service-list/service-list.js';
|
|
@@ -4,4 +4,5 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export { ServiceService, ServiceServiceDefinition, loadServiceServiceInitialData, } from './service/service.js';
|
|
6
6
|
export { BookingService, BookingServiceDefinition, } from './booking/booking.js';
|
|
7
|
+
export { TimeSlotListService, TimeSlotListServiceDefinition, ViewMode, loadTimeSlotListConfig, } from './time-slot-list/index.js';
|
|
7
8
|
export { ServiceListService, ServiceListServiceDefinition, loadServiceListServiceInitialData, } from './service-list/service-list.js';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Handles loading and managing a single service's data, loading state, and errors.
|
|
4
4
|
*/
|
|
5
5
|
import { type Signal, type ReadOnlySignal } from '@wix/services-definitions/core-services/signals';
|
|
6
|
-
import {
|
|
6
|
+
import { type Service, type Payment } from '@wix/auto_sdk_bookings_services';
|
|
7
7
|
import type { MoneyData } from '@wix/headless-components/react';
|
|
8
8
|
/**
|
|
9
9
|
* Actions object for service selection
|
|
@@ -23,9 +23,9 @@ export interface ServiceActions {
|
|
|
23
23
|
*/
|
|
24
24
|
export interface ServicePaymentData {
|
|
25
25
|
/** The service payment information from the service */
|
|
26
|
-
servicePayment:
|
|
26
|
+
servicePayment: Payment | undefined;
|
|
27
27
|
/** The rate type of the service (FIXED, VARIED, CUSTOM, NO_FEE, etc.) */
|
|
28
|
-
rateType:
|
|
28
|
+
rateType: Payment['rateType'] | undefined;
|
|
29
29
|
/** Primary price (used for FIXED or VARIED default) */
|
|
30
30
|
money: MoneyData | null;
|
|
31
31
|
/** Minimum price (used for VARIED) */
|
|
@@ -46,7 +46,7 @@ export interface ServicePaymentData {
|
|
|
46
46
|
*/
|
|
47
47
|
export interface ServiceServiceAPI {
|
|
48
48
|
/** Reactive signal containing the current service data */
|
|
49
|
-
serviceSignal: Signal<
|
|
49
|
+
serviceSignal: Signal<Service>;
|
|
50
50
|
/** Reactive signal indicating if a service is currently being loaded */
|
|
51
51
|
isLoadingSignal: Signal<boolean>;
|
|
52
52
|
/** Reactive signal containing any error message, or null if no error */
|
|
@@ -83,7 +83,7 @@ export declare const ServiceServiceDefinition: string & {
|
|
|
83
83
|
*/
|
|
84
84
|
export interface ServiceServiceConfig {
|
|
85
85
|
/** The initial service data to configure the service with */
|
|
86
|
-
service?:
|
|
86
|
+
service?: Service;
|
|
87
87
|
/** The service ID to load if no initial service is provided */
|
|
88
88
|
serviceId?: string;
|
|
89
89
|
/** The service slug to load if no initial service is provided */
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
6
6
|
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
7
|
-
import {
|
|
7
|
+
import { ServiceType, RateType, } from '@wix/auto_sdk_bookings_services';
|
|
8
8
|
import { getServiceById, getServiceBySlug, } from '../../api/query-services/index.js';
|
|
9
9
|
import { BookingServiceDefinition } from '../booking/booking.js';
|
|
10
10
|
import { convertToMoneyData } from '../../utils/money.js';
|
|
@@ -88,8 +88,8 @@ export const ServiceService = implementService.withConfig()(ServiceServiceDefini
|
|
|
88
88
|
const requiresAvailabilitySignal = signalsService.computed(() => {
|
|
89
89
|
const currentService = serviceSignal.get();
|
|
90
90
|
const serviceType = currentService.type;
|
|
91
|
-
return (serviceType ===
|
|
92
|
-
serviceType ===
|
|
91
|
+
return (serviceType === ServiceType.APPOINTMENT ||
|
|
92
|
+
serviceType === ServiceType.CLASS);
|
|
93
93
|
});
|
|
94
94
|
// paymentData signal - computed payment data from service
|
|
95
95
|
const paymentDataSignal = signalsService.computed(() => {
|
|
@@ -104,21 +104,21 @@ export const ServiceService = implementService.withConfig()(ServiceServiceDefini
|
|
|
104
104
|
// Extract pricing based on rate type
|
|
105
105
|
if (payment) {
|
|
106
106
|
switch (rateType) {
|
|
107
|
-
case
|
|
107
|
+
case RateType.FIXED:
|
|
108
108
|
// FIXED: Use payment.fixed.price
|
|
109
109
|
money = convertToMoneyData(payment.fixed?.price);
|
|
110
110
|
break;
|
|
111
|
-
case
|
|
111
|
+
case RateType.VARIED:
|
|
112
112
|
// VARIED: Use defaultPrice as money, plus min/max for range
|
|
113
113
|
money = convertToMoneyData(payment.varied?.defaultPrice);
|
|
114
114
|
minPrice = convertToMoneyData(payment.varied?.minPrice);
|
|
115
115
|
maxPrice = convertToMoneyData(payment.varied?.maxPrice);
|
|
116
116
|
break;
|
|
117
|
-
case
|
|
117
|
+
case RateType.CUSTOM:
|
|
118
118
|
// CUSTOM: Use description text (no numeric price)
|
|
119
119
|
priceDescription = payment.custom?.description || null;
|
|
120
120
|
break;
|
|
121
|
-
case
|
|
121
|
+
case RateType.NO_FEE:
|
|
122
122
|
// NO_FEE: Free service (amount = 0)
|
|
123
123
|
money = { amount: 0, currency: 'USD' };
|
|
124
124
|
break;
|
|
@@ -203,7 +203,7 @@ export const ServiceService = implementService.withConfig()(ServiceServiceDefini
|
|
|
203
203
|
.filter((s) => s.service._id === currentService._id)
|
|
204
204
|
.map((s) => s.instanceId);
|
|
205
205
|
instancesToRemove.forEach((instanceId) => {
|
|
206
|
-
bookingService.actions.
|
|
206
|
+
bookingService.actions.removeBookingSelection(instanceId);
|
|
207
207
|
});
|
|
208
208
|
},
|
|
209
209
|
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Handles querying and pagination of services list (NO selection management)
|
|
4
4
|
*/
|
|
5
5
|
import { type Signal, type ReadOnlySignal } from '@wix/services-definitions/core-services/signals';
|
|
6
|
-
import {
|
|
6
|
+
import type { Service } from '@wix/auto_sdk_bookings_services';
|
|
7
7
|
import type { QueryServicesRequest, PagingMetadata } from '../../api/query-services/index.js';
|
|
8
8
|
export type { ServiceListFilters } from '../../api/query-services/index.js';
|
|
9
9
|
/**
|
|
@@ -15,7 +15,7 @@ export type QueryOptions = Omit<QueryServicesRequest, 'pagingMetadata'>;
|
|
|
15
15
|
* Configuration for the ServiceList service
|
|
16
16
|
*/
|
|
17
17
|
export interface ServiceListServiceConfig {
|
|
18
|
-
services?:
|
|
18
|
+
services?: Service[];
|
|
19
19
|
options?: QueryServicesRequest;
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
@@ -30,7 +30,7 @@ export interface ServiceListActions {
|
|
|
30
30
|
*/
|
|
31
31
|
export interface ServiceListServiceAPI {
|
|
32
32
|
/** Reactive signal containing the list of services */
|
|
33
|
-
servicesSignal: Signal<
|
|
33
|
+
servicesSignal: Signal<Service[]>;
|
|
34
34
|
/** Reactive signal containing current query options (appId, filters, sort) - changes trigger re-fetch */
|
|
35
35
|
queryOptionsSignal: Signal<QueryOptions>;
|
|
36
36
|
/** Reactive signal containing pagination metadata (limit, offset, count, hasNext) - updated after fetches */
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TimeSlotList Service
|
|
3
|
+
* Main export file for time slot list service
|
|
4
|
+
*/
|
|
5
|
+
export { TimeSlotListServiceDefinition, ViewMode, type TimeSlot, type TimeSlotListServiceAPI, type TimeSlotListServiceActions, type TimeSlotListServiceConfig, type SlotSelection, } from './time-slot-list.def.js';
|
|
6
|
+
export { TimeSlotListService, loadTimeSlotListConfig, type LoadTimeSlotListConfigOptions, type LoadTimeSlotListConfigResult, } from './time-slot-list.js';
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TimeSlotList Service Implementation
|
|
3
|
+
* Manages time slot fetching, selection, and state
|
|
4
|
+
*/
|
|
5
|
+
import type { Service } from '@wix/auto_sdk_bookings_services';
|
|
6
|
+
import { type TimeSlotListServiceConfig, ViewMode } from './time-slot-list.def.js';
|
|
7
|
+
export declare const TimeSlotListService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
8
|
+
__api: import("./time-slot-list.def.js").TimeSlotListServiceAPI;
|
|
9
|
+
__config: {};
|
|
10
|
+
isServiceDefinition?: boolean;
|
|
11
|
+
} & import("./time-slot-list.def.js").TimeSlotListServiceAPI, TimeSlotListServiceConfig>;
|
|
12
|
+
/**
|
|
13
|
+
* Options for loading time slots configuration on the server
|
|
14
|
+
*/
|
|
15
|
+
export interface LoadTimeSlotListConfigOptions {
|
|
16
|
+
/** Services to fetch time slots for */
|
|
17
|
+
services?: Service[];
|
|
18
|
+
/** Start date for the time range (defaults to current date) */
|
|
19
|
+
startDate?: Date;
|
|
20
|
+
/** End date for the time range (defaults to 7 days from start) */
|
|
21
|
+
endDate?: Date;
|
|
22
|
+
/** Timezone for formatting (defaults to UTC) */
|
|
23
|
+
timezone?: string;
|
|
24
|
+
/** View mode (defaults to CLASSIC) */
|
|
25
|
+
viewMode?: ViewMode;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Result type for SSR loader - either success with config or error
|
|
29
|
+
*/
|
|
30
|
+
export type LoadTimeSlotListConfigResult = {
|
|
31
|
+
type: 'success';
|
|
32
|
+
config: TimeSlotListServiceConfig;
|
|
33
|
+
} | {
|
|
34
|
+
type: 'error';
|
|
35
|
+
error: string;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* SSR Loader: Pre-fetches time slots for server-side rendering
|
|
39
|
+
* Use this in Astro/Next.js getServerSideProps or page loaders
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* // In Astro page
|
|
44
|
+
* const loadResult = await loadTimeSlotListConfig({
|
|
45
|
+
* services: bookingServices,
|
|
46
|
+
* startDate: new Date(),
|
|
47
|
+
* endDate: addDays(new Date(), 7),
|
|
48
|
+
* timezone: 'America/New_York',
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* if (loadResult.type === 'error') {
|
|
52
|
+
* // Handle error
|
|
53
|
+
* }
|
|
54
|
+
*
|
|
55
|
+
* const timeSlotListConfig = loadResult.config;
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare function loadTimeSlotListConfig(options: LoadTimeSlotListConfigOptions): Promise<LoadTimeSlotListConfigResult>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TimeSlotList Service Definition
|
|
3
|
+
* Defines interfaces and service contract for time slot management
|
|
4
|
+
*/
|
|
5
|
+
import type { Signal } from '@wix/services-definitions/core-services/signals';
|
|
6
|
+
import type { TimeSlot as ApiTimeSlot } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
7
|
+
import type { Service } from '@wix/auto_sdk_bookings_services';
|
|
8
|
+
export declare enum ViewMode {
|
|
9
|
+
CLASSIC = "classic",
|
|
10
|
+
AGENDA = "agenda"
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Maps a location to its available staff members
|
|
14
|
+
*/
|
|
15
|
+
export interface StaffByLocation {
|
|
16
|
+
location: {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
};
|
|
20
|
+
staffMembers: {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
}[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Grouped time slot that represents a unique time with all available locations/staff
|
|
27
|
+
* Extends the API TimeSlot type but replaces location-specific fields with aggregated data
|
|
28
|
+
*/
|
|
29
|
+
export interface TimeSlot extends Omit<ApiTimeSlot, 'location' | 'availableResources'> {
|
|
30
|
+
/** Maps each location to its available staff members */
|
|
31
|
+
staffByLocation: StaffByLocation[];
|
|
32
|
+
/** Original API slots for this time (needed for booking service) */
|
|
33
|
+
originalSlots: ApiTimeSlot[];
|
|
34
|
+
/** Unique identifier for the time slot */
|
|
35
|
+
id: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* User's selection state
|
|
39
|
+
*/
|
|
40
|
+
export interface SlotSelection {
|
|
41
|
+
slot: TimeSlot;
|
|
42
|
+
locationId: string | null;
|
|
43
|
+
staffMemberId: string | null;
|
|
44
|
+
}
|
|
45
|
+
export interface TimeSlotListServiceConfig {
|
|
46
|
+
/** Services to fetch time slots for */
|
|
47
|
+
services?: Service[];
|
|
48
|
+
/** Pre-loaded time slots (from SSR) - already grouped by time */
|
|
49
|
+
timeSlots?: TimeSlot[];
|
|
50
|
+
/** Start date for the time range */
|
|
51
|
+
startDate?: Date;
|
|
52
|
+
/** End date for the time range */
|
|
53
|
+
endDate?: Date;
|
|
54
|
+
/** Timezone for formatting */
|
|
55
|
+
timezone?: string;
|
|
56
|
+
/** View mode */
|
|
57
|
+
viewMode?: ViewMode;
|
|
58
|
+
}
|
|
59
|
+
export interface TimeSlotListServiceActions {
|
|
60
|
+
selectSlot: (slot: TimeSlot) => void;
|
|
61
|
+
selectLocation: (locationId: string) => void;
|
|
62
|
+
selectStaffMember: (staffMemberId: string) => void;
|
|
63
|
+
clearPreferences: () => void;
|
|
64
|
+
loadMore: () => Promise<void>;
|
|
65
|
+
setDateRange: (start: Date, end: Date) => void;
|
|
66
|
+
setTimezone: (tz: string) => void;
|
|
67
|
+
}
|
|
68
|
+
export interface TimeSlotListServiceAPI {
|
|
69
|
+
timeSlots: Signal<TimeSlot[]>;
|
|
70
|
+
selection: Signal<SlotSelection | null>;
|
|
71
|
+
isLoading: Signal<boolean>;
|
|
72
|
+
error: Signal<string | null>;
|
|
73
|
+
hasMore: Signal<boolean>;
|
|
74
|
+
viewMode: Signal<ViewMode>;
|
|
75
|
+
startDate: Signal<Date>;
|
|
76
|
+
endDate: Signal<Date>;
|
|
77
|
+
timezone: Signal<string | undefined>;
|
|
78
|
+
actions: TimeSlotListServiceActions;
|
|
79
|
+
}
|
|
80
|
+
export declare const TimeSlotListServiceDefinition: string & {
|
|
81
|
+
__api: TimeSlotListServiceAPI;
|
|
82
|
+
__config: {};
|
|
83
|
+
isServiceDefinition?: boolean;
|
|
84
|
+
} & TimeSlotListServiceAPI;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TimeSlotList Service Definition
|
|
3
|
+
* Defines interfaces and service contract for time slot management
|
|
4
|
+
*/
|
|
5
|
+
import { defineService } from '@wix/services-definitions';
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Enums
|
|
8
|
+
// ============================================================================
|
|
9
|
+
export var ViewMode;
|
|
10
|
+
(function (ViewMode) {
|
|
11
|
+
ViewMode["CLASSIC"] = "classic";
|
|
12
|
+
ViewMode["AGENDA"] = "agenda";
|
|
13
|
+
})(ViewMode || (ViewMode = {}));
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// Service Definition
|
|
16
|
+
// ============================================================================
|
|
17
|
+
export const TimeSlotListServiceDefinition = defineService('time-slot-list');
|