@wix/headless-bookings 0.0.18 → 0.0.20
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 +3 -5
- package/cjs/dist/api/time-slot-list/index.js +13 -12
- package/cjs/dist/react/core/booking/Booking.d.ts +6 -7
- package/cjs/dist/react/core/booking/Booking.js +7 -9
- package/cjs/dist/react/time-slot-list/TimeSlotList.d.ts +41 -4
- package/cjs/dist/react/time-slot-list/TimeSlotList.js +20 -5
- package/cjs/dist/services/booking/booking.d.ts +29 -32
- package/cjs/dist/services/booking/booking.js +29 -36
- package/cjs/dist/services/index.d.ts +1 -1
- package/cjs/dist/services/service/service.js +4 -4
- package/cjs/dist/services/time-slot-list/time-slot-list.def.d.ts +11 -2
- package/cjs/dist/services/time-slot-list/time-slot-list.js +8 -10
- package/dist/api/time-slot-list/index.d.ts +3 -5
- package/dist/api/time-slot-list/index.js +13 -12
- package/dist/react/core/booking/Booking.d.ts +6 -7
- package/dist/react/core/booking/Booking.js +7 -9
- package/dist/react/time-slot-list/TimeSlotList.d.ts +41 -4
- package/dist/react/time-slot-list/TimeSlotList.js +20 -5
- package/dist/services/booking/booking.d.ts +29 -32
- package/dist/services/booking/booking.js +29 -36
- package/dist/services/index.d.ts +1 -1
- package/dist/services/service/service.js +4 -4
- package/dist/services/time-slot-list/time-slot-list.def.d.ts +11 -2
- package/dist/services/time-slot-list/time-slot-list.js +8 -10
- package/package.json +4 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Booking Service - Global booking store
|
|
3
|
-
* Manages booking flow state (selected services, time slot, location, form
|
|
3
|
+
* Manages booking flow state (selected services, time slot, location, form submission)
|
|
4
4
|
* Persists across page navigation in SPA until page refresh
|
|
5
5
|
*/
|
|
6
6
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
@@ -9,7 +9,7 @@ import { SignalsServiceDefinition, } from '@wix/services-definitions/core-servic
|
|
|
9
9
|
// Types
|
|
10
10
|
// ============================================================================
|
|
11
11
|
/**
|
|
12
|
-
* Generates a unique instance ID for
|
|
12
|
+
* Generates a unique instance ID for service selections
|
|
13
13
|
*/
|
|
14
14
|
function generateInstanceId() {
|
|
15
15
|
return crypto.randomUUID();
|
|
@@ -39,8 +39,8 @@ export const BookingServiceDefinition = defineService('booking');
|
|
|
39
39
|
*
|
|
40
40
|
* // In any page - access booking data
|
|
41
41
|
* <Booking.Data>
|
|
42
|
-
* {({
|
|
43
|
-
* <div>{
|
|
42
|
+
* {({ serviceSelections, location, formSubmission, actions }) => (
|
|
43
|
+
* <div>{serviceSelections.map(item => item.service.name).join(', ')}</div>
|
|
44
44
|
* )}
|
|
45
45
|
* </Booking.Data>
|
|
46
46
|
* ```
|
|
@@ -48,15 +48,14 @@ export const BookingServiceDefinition = defineService('booking');
|
|
|
48
48
|
export const BookingService = implementService.withConfig()(BookingServiceDefinition, ({ getService, config }) => {
|
|
49
49
|
const signalsService = getService(SignalsServiceDefinition);
|
|
50
50
|
// Initialize signals with config values
|
|
51
|
-
// Ensure all initial
|
|
52
|
-
const initialItemsWithIds = (config.
|
|
51
|
+
// Ensure all initial service selections have instanceIds
|
|
52
|
+
const initialItemsWithIds = (config.serviceSelections || []).map((item) => ({
|
|
53
53
|
...item,
|
|
54
54
|
instanceId: item.instanceId || generateInstanceId(),
|
|
55
55
|
}));
|
|
56
|
-
const
|
|
56
|
+
const serviceSelectionsSignal = signalsService.signal(initialItemsWithIds);
|
|
57
57
|
const locationSignal = signalsService.signal(config.location || null);
|
|
58
|
-
const
|
|
59
|
-
const numberOfParticipantsSignal = signalsService.signal(config.numberOfParticipants ?? 1);
|
|
58
|
+
const formSubmissionSignal = signalsService.signal(config.formSubmission || null);
|
|
60
59
|
// ========================================================================
|
|
61
60
|
// Actions Implementation
|
|
62
61
|
// ========================================================================
|
|
@@ -68,43 +67,43 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
|
|
|
68
67
|
...item,
|
|
69
68
|
instanceId,
|
|
70
69
|
};
|
|
71
|
-
|
|
70
|
+
serviceSelectionsSignal.set([newItem]);
|
|
72
71
|
return instanceId;
|
|
73
72
|
},
|
|
74
73
|
addItem(item) {
|
|
75
74
|
const instanceId = generateInstanceId();
|
|
76
|
-
const current =
|
|
75
|
+
const current = serviceSelectionsSignal.get();
|
|
77
76
|
const newItem = {
|
|
78
77
|
...item,
|
|
79
78
|
instanceId,
|
|
80
79
|
};
|
|
81
|
-
|
|
80
|
+
serviceSelectionsSignal.set([...current, newItem]);
|
|
82
81
|
return instanceId;
|
|
83
82
|
},
|
|
84
83
|
updateItem(updates, instanceId) {
|
|
85
|
-
const current =
|
|
84
|
+
const current = serviceSelectionsSignal.get();
|
|
86
85
|
// If no instanceId provided, update the first item (index 0)
|
|
87
86
|
const targetId = instanceId ?? current[0]?.instanceId;
|
|
88
87
|
const updated = current.map((item) => item.instanceId === targetId ? { ...item, ...updates } : item);
|
|
89
|
-
|
|
88
|
+
serviceSelectionsSignal.set(updated);
|
|
90
89
|
},
|
|
91
90
|
removeItem(instanceId) {
|
|
92
|
-
const current =
|
|
91
|
+
const current = serviceSelectionsSignal.get();
|
|
93
92
|
if (!instanceId) {
|
|
94
93
|
// Remove first item if no instanceId provided
|
|
95
|
-
|
|
94
|
+
serviceSelectionsSignal.set(current.slice(1));
|
|
96
95
|
}
|
|
97
96
|
else {
|
|
98
97
|
const filtered = current.filter((item) => item.instanceId !== instanceId);
|
|
99
|
-
|
|
98
|
+
serviceSelectionsSignal.set(filtered);
|
|
100
99
|
}
|
|
101
100
|
},
|
|
102
101
|
clearItems() {
|
|
103
|
-
|
|
102
|
+
serviceSelectionsSignal.set([]);
|
|
104
103
|
},
|
|
105
104
|
// Resource helpers
|
|
106
105
|
setResourceById(resourceId, resource, instanceId) {
|
|
107
|
-
const current =
|
|
106
|
+
const current = serviceSelectionsSignal.get();
|
|
108
107
|
// If no instanceId provided, use the first item
|
|
109
108
|
const targetId = instanceId ?? current[0]?.instanceId;
|
|
110
109
|
if (!targetId)
|
|
@@ -123,10 +122,10 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
|
|
|
123
122
|
}
|
|
124
123
|
return { ...item, resources: newResources };
|
|
125
124
|
});
|
|
126
|
-
|
|
125
|
+
serviceSelectionsSignal.set(updated);
|
|
127
126
|
},
|
|
128
127
|
getResourceById(resourceId, instanceId) {
|
|
129
|
-
const current =
|
|
128
|
+
const current = serviceSelectionsSignal.get();
|
|
130
129
|
// If no instanceId provided, use the first item
|
|
131
130
|
const targetId = instanceId ?? current[0]?.instanceId;
|
|
132
131
|
if (!targetId)
|
|
@@ -143,30 +142,24 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
|
|
|
143
142
|
clearLocation() {
|
|
144
143
|
locationSignal.set(null);
|
|
145
144
|
},
|
|
146
|
-
// Form
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
// Form Submission actions
|
|
146
|
+
setFormSubmission(values) {
|
|
147
|
+
formSubmissionSignal.set(values);
|
|
149
148
|
},
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
},
|
|
153
|
-
// Number of Participants actions
|
|
154
|
-
setNumberOfParticipants(count) {
|
|
155
|
-
numberOfParticipantsSignal.set(count);
|
|
149
|
+
clearFormSubmission() {
|
|
150
|
+
formSubmissionSignal.set(null);
|
|
156
151
|
},
|
|
157
152
|
// Clear all
|
|
158
153
|
clearAll() {
|
|
159
|
-
|
|
154
|
+
serviceSelectionsSignal.set([]);
|
|
160
155
|
locationSignal.set(null);
|
|
161
|
-
|
|
162
|
-
numberOfParticipantsSignal.set(1);
|
|
156
|
+
formSubmissionSignal.set(null);
|
|
163
157
|
},
|
|
164
158
|
};
|
|
165
159
|
return {
|
|
166
|
-
|
|
160
|
+
serviceSelections: serviceSelectionsSignal,
|
|
167
161
|
location: locationSignal,
|
|
168
|
-
|
|
169
|
-
numberOfParticipants: numberOfParticipantsSignal,
|
|
162
|
+
formSubmission: formSubmissionSignal,
|
|
170
163
|
actions,
|
|
171
164
|
};
|
|
172
165
|
});
|
package/dist/services/index.d.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
* Main export file for all service definitions and implementations
|
|
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
|
-
export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type Location, type BookingServiceActions, } from './booking/booking.js';
|
|
6
|
+
export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type Location, type BookingServiceActions, type ServiceSelection, type ServiceSelectionTimeSlot, } from './booking/booking.js';
|
|
7
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
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';
|
|
@@ -81,8 +81,8 @@ export const ServiceService = implementService.withConfig()(ServiceServiceDefini
|
|
|
81
81
|
const currentService = serviceSignal.get();
|
|
82
82
|
if (!currentService._id)
|
|
83
83
|
return false;
|
|
84
|
-
const
|
|
85
|
-
return
|
|
84
|
+
const serviceSelections = bookingService.serviceSelections.get();
|
|
85
|
+
return serviceSelections.some(({ service }) => service._id === currentService._id);
|
|
86
86
|
});
|
|
87
87
|
// requiresAvailability signal - true for APPOINTMENT and CLASS types
|
|
88
88
|
const requiresAvailabilitySignal = signalsService.computed(() => {
|
|
@@ -201,8 +201,8 @@ export const ServiceService = implementService.withConfig()(ServiceServiceDefini
|
|
|
201
201
|
return;
|
|
202
202
|
const currentService = serviceSignal.get();
|
|
203
203
|
// Remove all instances of this service (by serviceId)
|
|
204
|
-
const
|
|
205
|
-
const instancesToRemove =
|
|
204
|
+
const serviceSelections = bookingService.serviceSelections.get();
|
|
205
|
+
const instancesToRemove = serviceSelections
|
|
206
206
|
.filter((s) => s.service._id === currentService._id)
|
|
207
207
|
.map((s) => s.instanceId);
|
|
208
208
|
instancesToRemove.forEach((instanceId) => {
|
|
@@ -51,8 +51,6 @@ export interface TimeSlotsFilters {
|
|
|
51
51
|
locations?: Location[];
|
|
52
52
|
/** Filter by specific staff member IDs */
|
|
53
53
|
staffMemberIds?: string[];
|
|
54
|
-
/** Maximum slots to return per day (useful for calendar views) */
|
|
55
|
-
slotsPerDay?: number;
|
|
56
54
|
/** Filter by bookable status. If undefined, returns both bookable and non-bookable */
|
|
57
55
|
bookable?: boolean;
|
|
58
56
|
/** Filter by booking policy violations */
|
|
@@ -61,6 +59,17 @@ export interface TimeSlotsFilters {
|
|
|
61
59
|
tooLateToBook?: boolean;
|
|
62
60
|
bookOnlineDisabled?: boolean;
|
|
63
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* Number of time slots to load per request.
|
|
64
|
+
* Controls how many slots are fetched initially and on each "Load More" action.
|
|
65
|
+
* Default: 1000. Max: 1000.
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* // Load 6 slots at a time
|
|
69
|
+
* filters: { slotsPerPage: 6 }
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
slotsPerPage?: number;
|
|
64
73
|
}
|
|
65
74
|
export interface TimeSlotListServiceConfig {
|
|
66
75
|
/** Services to fetch time slots for */
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { implementService } from '@wix/services-definitions';
|
|
6
6
|
import { SignalsServiceDefinition } from '@wix/services-definitions/core-services/signals';
|
|
7
|
+
import { format } from 'date-fns';
|
|
7
8
|
import { TimeSlotListServiceDefinition, ViewMode, } from './time-slot-list.def.js';
|
|
8
9
|
import { fetchAvailability } from '../../api/time-slot-list/index.js';
|
|
9
10
|
import { BookingServiceDefinition, } from '../booking/booking.js';
|
|
@@ -22,13 +23,8 @@ function getClientTimezone() {
|
|
|
22
23
|
* Formats a Date to local ISO string (YYYY-MM-DDThh:mm:ss)
|
|
23
24
|
*/
|
|
24
25
|
function toLocalDateString(date) {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
const day = String(date.getDate()).padStart(2, '0');
|
|
28
|
-
const hours = String(date.getHours()).padStart(2, '0');
|
|
29
|
-
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
30
|
-
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
31
|
-
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`;
|
|
26
|
+
const pattern = "yyyy-MM-dd'T'HH:mm:ss";
|
|
27
|
+
return format(date, pattern);
|
|
32
28
|
}
|
|
33
29
|
/**
|
|
34
30
|
* Merges new grouped slots with existing ones
|
|
@@ -80,7 +76,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
|
|
|
80
76
|
const getServices = () => {
|
|
81
77
|
if (config.services?.length)
|
|
82
78
|
return config.services;
|
|
83
|
-
return bookingService.
|
|
79
|
+
return bookingService.serviceSelections.get().map((s) => s.service);
|
|
84
80
|
};
|
|
85
81
|
/**
|
|
86
82
|
* Helper: Get filters from config or BookingService
|
|
@@ -88,7 +84,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
|
|
|
88
84
|
const getFilters = () => {
|
|
89
85
|
// Get BookingService selections (these take priority)
|
|
90
86
|
const location = bookingService.location.get();
|
|
91
|
-
const selections = bookingService.
|
|
87
|
+
const selections = bookingService.serviceSelections.get();
|
|
92
88
|
const selectedStaffMemberIds = selections
|
|
93
89
|
.map(({ resources }) => resources.map((r) => r._id))
|
|
94
90
|
.flat();
|
|
@@ -114,6 +110,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
|
|
|
114
110
|
isLoadingSignal.set(true);
|
|
115
111
|
errorSignal.set(null);
|
|
116
112
|
cursorSignal.set(undefined);
|
|
113
|
+
timeSlotsSignal.set([]);
|
|
117
114
|
try {
|
|
118
115
|
const response = await fetchAvailability({
|
|
119
116
|
services: selectedServices,
|
|
@@ -121,6 +118,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
|
|
|
121
118
|
toLocalDate: toLocalDateString(endDateSignal.get()),
|
|
122
119
|
timeZone: timezoneSignal.get(),
|
|
123
120
|
viewMode: viewModeSignal.get(),
|
|
121
|
+
cursor: cursorSignal.get(),
|
|
124
122
|
...filters,
|
|
125
123
|
});
|
|
126
124
|
timeSlotsSignal.set(response.timeSlots);
|
|
@@ -312,7 +310,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
|
|
|
312
310
|
fromLocalDate: toLocalDateString(startDateSignal.get()),
|
|
313
311
|
toLocalDate: toLocalDateString(endDateSignal.get()),
|
|
314
312
|
timeZone: timezoneSignal.get(),
|
|
315
|
-
|
|
313
|
+
cursor,
|
|
316
314
|
viewMode: viewModeSignal.get(),
|
|
317
315
|
...filters,
|
|
318
316
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/headless-bookings",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
"@wix/headless-media": "0.0.18",
|
|
40
40
|
"@wix/headless-utils": "0.0.8",
|
|
41
41
|
"@wix/services-definitions": "^0.1.4",
|
|
42
|
-
"@wix/services-manager-react": "^0.1.26"
|
|
42
|
+
"@wix/services-manager-react": "^0.1.26",
|
|
43
|
+
"date-fns": "^4.1.0"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"@testing-library/dom": "^10.4.0",
|
|
@@ -69,5 +70,5 @@
|
|
|
69
70
|
"groupId": "com.wixpress.headless-components"
|
|
70
71
|
}
|
|
71
72
|
},
|
|
72
|
-
"falconPackageHash": "
|
|
73
|
+
"falconPackageHash": "25ba2b137a6e9ae4a9d267c7eeede1474665fe843f2999d663f593e4"
|
|
73
74
|
}
|