@wix/headless-bookings 0.0.50 → 0.0.51
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/react/booking/Booking.d.ts +213 -2
- package/cjs/dist/react/booking/Booking.js +221 -0
- package/cjs/dist/react/core/booking/Booking.d.ts +139 -11
- package/cjs/dist/react/core/booking/Booking.js +208 -1
- package/dist/react/booking/Booking.d.ts +213 -2
- package/dist/react/booking/Booking.js +221 -0
- package/dist/react/core/booking/Booking.d.ts +139 -11
- package/dist/react/core/booking/Booking.js +208 -1
- package/package.json +2 -2
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import { type BookingServiceConfig, type ServiceSelection, type BookingServiceActions } from '../../../services/booking/booking.js';
|
|
7
7
|
import type { FormValues } from '@wix/form-public';
|
|
8
|
-
import type {
|
|
8
|
+
import type { TimeSlot, Resource } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
9
|
+
import type { Service, Location as ServiceLocationType } from '@wix/auto_sdk_bookings_services';
|
|
10
|
+
import type { SlotService } from '../../../services/payment/payment.js';
|
|
9
11
|
/**
|
|
10
12
|
* Props for Booking.Root component
|
|
11
13
|
*/
|
|
@@ -35,7 +37,7 @@ export declare function Root(props: RootProps): React.ReactNode;
|
|
|
35
37
|
*/
|
|
36
38
|
export interface BookingData {
|
|
37
39
|
serviceSelections: ServiceSelection[];
|
|
38
|
-
location:
|
|
40
|
+
location: ServiceLocationType | null;
|
|
39
41
|
timezone: string | undefined;
|
|
40
42
|
formSubmission: FormValues | null;
|
|
41
43
|
actions: BookingServiceActions;
|
|
@@ -46,22 +48,148 @@ export interface BookingData {
|
|
|
46
48
|
export interface DataProps {
|
|
47
49
|
children: (data: BookingData) => React.ReactNode;
|
|
48
50
|
}
|
|
51
|
+
export declare function Data(props: DataProps): React.ReactNode;
|
|
52
|
+
/**
|
|
53
|
+
* Unified data object for a single booking item.
|
|
54
|
+
* Contains resolved data ready for use - no raw serviceSelection duplication.
|
|
55
|
+
*/
|
|
56
|
+
export interface BookingItem {
|
|
57
|
+
/** SDK Service object */
|
|
58
|
+
service: Service;
|
|
59
|
+
/** Adapted SDK TimeSlot (or null if no time slot selected) */
|
|
60
|
+
timeSlot: TimeSlot | null;
|
|
61
|
+
/** Resolved staff: timeSlot.resources ?? selection.resources, or null if none */
|
|
62
|
+
staff: Resource[] | null;
|
|
63
|
+
/** Unique identifier for this booking instance */
|
|
64
|
+
instanceId: string;
|
|
65
|
+
/** Position in the serviceSelections array */
|
|
66
|
+
index: number;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Hook to access the current BookingItem from context.
|
|
70
|
+
* Must be used within BookingItemProvider.
|
|
71
|
+
*
|
|
72
|
+
* @throws Error if used outside of BookingItemProvider context
|
|
73
|
+
*/
|
|
74
|
+
export declare function useBookingItemContext(): BookingItem;
|
|
75
|
+
/**
|
|
76
|
+
* Props for BookingItemProvider
|
|
77
|
+
*/
|
|
78
|
+
export interface BookingItemProviderProps {
|
|
79
|
+
children: React.ReactNode;
|
|
80
|
+
item: BookingItem;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Provider component used by repeaters to provide BookingItem context.
|
|
84
|
+
* Can be used by core consumers to create their own repeater.
|
|
85
|
+
*
|
|
86
|
+
* @component
|
|
87
|
+
* @example
|
|
88
|
+
* ```tsx
|
|
89
|
+
* {items.map((item) => (
|
|
90
|
+
* <BookingItemProvider key={item.instanceId} item={item}>
|
|
91
|
+
* {children}
|
|
92
|
+
* </BookingItemProvider>
|
|
93
|
+
* ))}
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare function BookingItemProvider(props: BookingItemProviderProps): React.ReactNode;
|
|
97
|
+
/**
|
|
98
|
+
* Props for BookingItemInfo render prop component
|
|
99
|
+
*/
|
|
100
|
+
export interface BookingItemInfoProps {
|
|
101
|
+
children: (data: {
|
|
102
|
+
/** SDK Service object */
|
|
103
|
+
service: Service;
|
|
104
|
+
/** Adapted SDK TimeSlot (or null if no time slot selected) */
|
|
105
|
+
timeSlot: TimeSlot | null;
|
|
106
|
+
/** First staff member's name, empty string if none */
|
|
107
|
+
staffName: string;
|
|
108
|
+
/** Unique identifier for this booking instance */
|
|
109
|
+
instanceId: string;
|
|
110
|
+
/** Position in the serviceSelections array */
|
|
111
|
+
index: number;
|
|
112
|
+
/** The raw BookingItem object */
|
|
113
|
+
item: BookingItem;
|
|
114
|
+
}) => React.ReactNode;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Core component that provides access to booking item info via render props.
|
|
118
|
+
* Must be used within BookingItemProvider.
|
|
119
|
+
*
|
|
120
|
+
* @component
|
|
121
|
+
* @example
|
|
122
|
+
* ```tsx
|
|
123
|
+
* <BookingItemInfo>
|
|
124
|
+
* {({ service, timeSlot, staffName }) => (
|
|
125
|
+
* <div>
|
|
126
|
+
* <span>{service.name}</span>
|
|
127
|
+
* <span>{staffName}</span>
|
|
128
|
+
* </div>
|
|
129
|
+
* )}
|
|
130
|
+
* </BookingItemInfo>
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export declare function BookingItemInfo(props: BookingItemInfoProps): React.ReactNode;
|
|
134
|
+
/**
|
|
135
|
+
* Data exposed by ItemsData render prop
|
|
136
|
+
*/
|
|
137
|
+
export interface ItemsDataRenderProps {
|
|
138
|
+
/** Array of BookingItem objects */
|
|
139
|
+
items: BookingItem[];
|
|
140
|
+
}
|
|
49
141
|
/**
|
|
50
|
-
*
|
|
51
|
-
|
|
142
|
+
* Props for ItemsData render prop component
|
|
143
|
+
*/
|
|
144
|
+
export interface ItemsDataProps {
|
|
145
|
+
children: (data: ItemsDataRenderProps) => React.ReactNode;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Core component that provides access to booking items array via render props.
|
|
149
|
+
* Transforms serviceSelections into BookingItem objects.
|
|
52
150
|
*
|
|
53
151
|
* @component
|
|
54
152
|
* @example
|
|
55
153
|
* ```tsx
|
|
56
|
-
* <Booking.
|
|
57
|
-
* {({
|
|
58
|
-
*
|
|
59
|
-
* <div>{
|
|
154
|
+
* <Booking.ItemsData>
|
|
155
|
+
* {({ items }) => (
|
|
156
|
+
* items.length > 0 ? (
|
|
157
|
+
* <div>{items.length} bookings</div>
|
|
60
158
|
* ) : (
|
|
61
|
-
* <div>No
|
|
159
|
+
* <div>No bookings</div>
|
|
62
160
|
* )
|
|
63
161
|
* )}
|
|
64
|
-
* </Booking.
|
|
162
|
+
* </Booking.ItemsData>
|
|
65
163
|
* ```
|
|
66
164
|
*/
|
|
67
|
-
export declare function
|
|
165
|
+
export declare function ItemsData(props: ItemsDataProps): React.ReactNode;
|
|
166
|
+
/**
|
|
167
|
+
* Data exposed by PaymentData render prop
|
|
168
|
+
*/
|
|
169
|
+
export interface PaymentDataRenderProps {
|
|
170
|
+
/** SlotServices array for Payment.Root */
|
|
171
|
+
slotServices: SlotService[];
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Props for PaymentData render prop component
|
|
175
|
+
*/
|
|
176
|
+
export interface PaymentDataProps {
|
|
177
|
+
children: (data: PaymentDataRenderProps) => React.ReactNode;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Core component that provides payment data via render props.
|
|
181
|
+
* Computes slotServices from serviceSelections.
|
|
182
|
+
*
|
|
183
|
+
* @component
|
|
184
|
+
* @example
|
|
185
|
+
* ```tsx
|
|
186
|
+
* <Booking.PaymentData>
|
|
187
|
+
* {({ slotServices }) => (
|
|
188
|
+
* <Payment.Root slotServices={slotServices}>
|
|
189
|
+
* <Payment.TotalPrice />
|
|
190
|
+
* </Payment.Root>
|
|
191
|
+
* )}
|
|
192
|
+
* </Booking.PaymentData>
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
export declare function PaymentData(props: PaymentDataProps): React.ReactNode;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Core Booking Components
|
|
4
|
+
* Provides low-level access to BookingService via render props and service setup
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
2
7
|
import { WixServices, useService } from '@wix/services-manager-react';
|
|
3
8
|
import { createServicesMap } from '@wix/services-manager';
|
|
4
9
|
import { BookingServiceDefinition, BookingService, } from '../../../services/booking/booking.js';
|
|
@@ -39,14 +44,42 @@ export function Root(props) {
|
|
|
39
44
|
* </Booking.Data>
|
|
40
45
|
* ```
|
|
41
46
|
*/
|
|
47
|
+
/**
|
|
48
|
+
* Maps a TimeSlotLocationType to ServiceLocationType.
|
|
49
|
+
* These types are structurally similar but have subtle differences
|
|
50
|
+
* (e.g., _id being string | null | undefined vs string | undefined).
|
|
51
|
+
*/
|
|
52
|
+
function mapTimeSlotLocationToServiceLocation(timeSlotLocation) {
|
|
53
|
+
return {
|
|
54
|
+
...timeSlotLocation,
|
|
55
|
+
_id: timeSlotLocation._id ?? undefined,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolves the location with fallback logic:
|
|
60
|
+
* 1. First, use the explicitly set booking location
|
|
61
|
+
* 2. If not set, fall back to the first service selection's slot location
|
|
62
|
+
*/
|
|
63
|
+
function resolveLocation(bookingLocation, serviceSelections) {
|
|
64
|
+
if (bookingLocation) {
|
|
65
|
+
return bookingLocation;
|
|
66
|
+
}
|
|
67
|
+
// Fallback to first slot's location
|
|
68
|
+
const firstSlotLocation = serviceSelections[0]?.timeSlot?.location;
|
|
69
|
+
if (firstSlotLocation) {
|
|
70
|
+
return mapTimeSlotLocationToServiceLocation(firstSlotLocation);
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
42
74
|
export function Data(props) {
|
|
43
75
|
const { children } = props;
|
|
44
76
|
const bookingService = useService(BookingServiceDefinition);
|
|
45
77
|
const serviceSelections = bookingService.serviceSelections.get();
|
|
46
|
-
const
|
|
78
|
+
const bookingLocation = bookingService.location.get();
|
|
47
79
|
const timezone = bookingService.timezone.get();
|
|
48
80
|
const formSubmission = bookingService.formSubmission.get();
|
|
49
81
|
const { actions } = bookingService;
|
|
82
|
+
const location = resolveLocation(bookingLocation, serviceSelections);
|
|
50
83
|
return children({
|
|
51
84
|
serviceSelections,
|
|
52
85
|
location,
|
|
@@ -55,3 +88,177 @@ export function Data(props) {
|
|
|
55
88
|
actions,
|
|
56
89
|
});
|
|
57
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Context for the current BookingItem
|
|
93
|
+
*/
|
|
94
|
+
const BookingItemContext = React.createContext(null);
|
|
95
|
+
/**
|
|
96
|
+
* Hook to access the current BookingItem from context.
|
|
97
|
+
* Must be used within BookingItemProvider.
|
|
98
|
+
*
|
|
99
|
+
* @throws Error if used outside of BookingItemProvider context
|
|
100
|
+
*/
|
|
101
|
+
export function useBookingItemContext() {
|
|
102
|
+
const context = React.useContext(BookingItemContext);
|
|
103
|
+
if (!context) {
|
|
104
|
+
throw new Error('BookingItem components must be used within BookingItemProvider');
|
|
105
|
+
}
|
|
106
|
+
return context;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Provider component used by repeaters to provide BookingItem context.
|
|
110
|
+
* Can be used by core consumers to create their own repeater.
|
|
111
|
+
*
|
|
112
|
+
* @component
|
|
113
|
+
* @example
|
|
114
|
+
* ```tsx
|
|
115
|
+
* {items.map((item) => (
|
|
116
|
+
* <BookingItemProvider key={item.instanceId} item={item}>
|
|
117
|
+
* {children}
|
|
118
|
+
* </BookingItemProvider>
|
|
119
|
+
* ))}
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export function BookingItemProvider(props) {
|
|
123
|
+
const { children, item } = props;
|
|
124
|
+
return (_jsx(BookingItemContext.Provider, { value: item, children: children }));
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Core component that provides access to booking item info via render props.
|
|
128
|
+
* Must be used within BookingItemProvider.
|
|
129
|
+
*
|
|
130
|
+
* @component
|
|
131
|
+
* @example
|
|
132
|
+
* ```tsx
|
|
133
|
+
* <BookingItemInfo>
|
|
134
|
+
* {({ service, timeSlot, staffName }) => (
|
|
135
|
+
* <div>
|
|
136
|
+
* <span>{service.name}</span>
|
|
137
|
+
* <span>{staffName}</span>
|
|
138
|
+
* </div>
|
|
139
|
+
* )}
|
|
140
|
+
* </BookingItemInfo>
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
export function BookingItemInfo(props) {
|
|
144
|
+
const item = useBookingItemContext();
|
|
145
|
+
const staffName = item.staff?.[0]?.name || '';
|
|
146
|
+
return props.children({
|
|
147
|
+
service: item.service,
|
|
148
|
+
timeSlot: item.timeSlot,
|
|
149
|
+
staffName,
|
|
150
|
+
instanceId: item.instanceId,
|
|
151
|
+
index: item.index,
|
|
152
|
+
item,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
// ============================================================================
|
|
156
|
+
// Helper: Convert ServiceSelectionTimeSlot to SDK TimeSlot
|
|
157
|
+
// ============================================================================
|
|
158
|
+
/**
|
|
159
|
+
* Converts a ServiceSelectionTimeSlot to SDK TimeSlot format
|
|
160
|
+
* for compatibility with TimeSlot.Root component.
|
|
161
|
+
*/
|
|
162
|
+
function mapSelectionTimeSlotToTimeSlot(serviceSelectionTimeSlot) {
|
|
163
|
+
if (!serviceSelectionTimeSlot) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
const availableResources = serviceSelectionTimeSlot.resources?.length
|
|
167
|
+
? [{ resources: serviceSelectionTimeSlot.resources }]
|
|
168
|
+
: undefined;
|
|
169
|
+
return {
|
|
170
|
+
localStartDate: serviceSelectionTimeSlot.startDate,
|
|
171
|
+
localEndDate: serviceSelectionTimeSlot.endDate,
|
|
172
|
+
bookable: true,
|
|
173
|
+
totalCapacity: serviceSelectionTimeSlot.totalCapacity,
|
|
174
|
+
remainingCapacity: serviceSelectionTimeSlot.remainingCapacity,
|
|
175
|
+
scheduleId: serviceSelectionTimeSlot.scheduleId,
|
|
176
|
+
eventInfo: serviceSelectionTimeSlot.eventInfo,
|
|
177
|
+
location: serviceSelectionTimeSlot.location,
|
|
178
|
+
availableResources,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
// ============================================================================
|
|
182
|
+
// Helper: Resolve Staff with Priority Logic
|
|
183
|
+
// ============================================================================
|
|
184
|
+
/**
|
|
185
|
+
* Gets selected staff resources with priority:
|
|
186
|
+
* 1. From selected time slot (if resources exist)
|
|
187
|
+
* 2. From service selection resources
|
|
188
|
+
* Returns null if no staff is chosen
|
|
189
|
+
*/
|
|
190
|
+
function getSelectedStaff(serviceSelection) {
|
|
191
|
+
// Priority 1: From selected time slot
|
|
192
|
+
if (serviceSelection.timeSlot?.resources?.length) {
|
|
193
|
+
return serviceSelection.timeSlot.resources;
|
|
194
|
+
}
|
|
195
|
+
// Priority 2: From service selection
|
|
196
|
+
if (serviceSelection.resources?.length) {
|
|
197
|
+
return serviceSelection.resources;
|
|
198
|
+
}
|
|
199
|
+
// No staff chosen
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Creates a BookingItem from a ServiceSelection
|
|
204
|
+
*/
|
|
205
|
+
function createBookingItem(serviceSelection, index) {
|
|
206
|
+
return {
|
|
207
|
+
service: serviceSelection.service,
|
|
208
|
+
timeSlot: mapSelectionTimeSlotToTimeSlot(serviceSelection.timeSlot),
|
|
209
|
+
staff: getSelectedStaff(serviceSelection),
|
|
210
|
+
instanceId: serviceSelection.instanceId,
|
|
211
|
+
index,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Core component that provides access to booking items array via render props.
|
|
216
|
+
* Transforms serviceSelections into BookingItem objects.
|
|
217
|
+
*
|
|
218
|
+
* @component
|
|
219
|
+
* @example
|
|
220
|
+
* ```tsx
|
|
221
|
+
* <Booking.ItemsData>
|
|
222
|
+
* {({ items }) => (
|
|
223
|
+
* items.length > 0 ? (
|
|
224
|
+
* <div>{items.length} bookings</div>
|
|
225
|
+
* ) : (
|
|
226
|
+
* <div>No bookings</div>
|
|
227
|
+
* )
|
|
228
|
+
* )}
|
|
229
|
+
* </Booking.ItemsData>
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
export function ItemsData(props) {
|
|
233
|
+
const { children } = props;
|
|
234
|
+
const bookingService = useService(BookingServiceDefinition);
|
|
235
|
+
const serviceSelections = bookingService.serviceSelections.get();
|
|
236
|
+
const items = serviceSelections.map((selection, index) => createBookingItem(selection, index));
|
|
237
|
+
return children({ items });
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Core component that provides payment data via render props.
|
|
241
|
+
* Computes slotServices from serviceSelections.
|
|
242
|
+
*
|
|
243
|
+
* @component
|
|
244
|
+
* @example
|
|
245
|
+
* ```tsx
|
|
246
|
+
* <Booking.PaymentData>
|
|
247
|
+
* {({ slotServices }) => (
|
|
248
|
+
* <Payment.Root slotServices={slotServices}>
|
|
249
|
+
* <Payment.TotalPrice />
|
|
250
|
+
* </Payment.Root>
|
|
251
|
+
* )}
|
|
252
|
+
* </Booking.PaymentData>
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
export function PaymentData(props) {
|
|
256
|
+
const { children } = props;
|
|
257
|
+
const bookingService = useService(BookingServiceDefinition);
|
|
258
|
+
const serviceSelections = bookingService.serviceSelections.get();
|
|
259
|
+
const slotServices = serviceSelections.map((selection) => ({
|
|
260
|
+
service: selection.service,
|
|
261
|
+
lineItemId: selection.instanceId,
|
|
262
|
+
}));
|
|
263
|
+
return children({ slotServices });
|
|
264
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/headless-bookings",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.51",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"groupId": "com.wixpress.headless-components"
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
|
-
"falconPackageHash": "
|
|
75
|
+
"falconPackageHash": "ef1225253b65e6a7c3e1ea15bc390bb4afebcfad2ef8f5c0d7337bde"
|
|
76
76
|
}
|