@wix/headless-bookings 0.0.20 → 0.0.22
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 → fetch-availability}/index.d.ts +4 -3
- package/cjs/dist/api/{time-slot-list → fetch-availability}/index.js +36 -15
- package/cjs/dist/api/index.d.ts +1 -1
- package/cjs/dist/api/index.js +1 -1
- package/cjs/dist/react/booking/Booking.d.ts +2 -1
- package/cjs/dist/react/booking/Booking.js +1 -1
- package/cjs/dist/react/core/booking/Booking.d.ts +3 -2
- package/cjs/dist/react/core/booking/Booking.js +5 -2
- package/cjs/dist/react/core/time-slot-list/TimeSlot.d.ts +4 -4
- package/cjs/dist/react/core/time-slot-list/TimeSlot.js +17 -7
- package/cjs/dist/react/core/time-slot-list/TimeSlotList.js +3 -2
- package/cjs/dist/react/time-slot-list/TimeSlot.d.ts +6 -6
- package/cjs/dist/react/time-slot-list/TimeSlot.js +6 -6
- package/cjs/dist/react/time-slot-list/TimeSlotList.d.ts +4 -4
- package/cjs/dist/services/booking/booking.d.ts +6 -0
- package/cjs/dist/services/booking/booking.js +21 -1
- package/cjs/dist/services/time-slot-list/time-slot-list.def.d.ts +12 -4
- package/cjs/dist/services/time-slot-list/time-slot-list.js +37 -34
- package/dist/api/{time-slot-list → fetch-availability}/index.d.ts +4 -3
- package/dist/api/{time-slot-list → fetch-availability}/index.js +36 -15
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.js +1 -1
- package/dist/react/booking/Booking.d.ts +2 -1
- package/dist/react/booking/Booking.js +1 -1
- package/dist/react/core/booking/Booking.d.ts +3 -2
- package/dist/react/core/booking/Booking.js +5 -2
- package/dist/react/core/time-slot-list/TimeSlot.d.ts +4 -4
- package/dist/react/core/time-slot-list/TimeSlot.js +17 -7
- package/dist/react/core/time-slot-list/TimeSlotList.js +3 -2
- package/dist/react/time-slot-list/TimeSlot.d.ts +6 -6
- package/dist/react/time-slot-list/TimeSlot.js +6 -6
- package/dist/react/time-slot-list/TimeSlotList.d.ts +4 -4
- package/dist/services/booking/booking.d.ts +6 -0
- package/dist/services/booking/booking.js +21 -1
- package/dist/services/time-slot-list/time-slot-list.def.d.ts +12 -4
- package/dist/services/time-slot-list/time-slot-list.js +37 -34
- package/package.json +2 -2
|
@@ -52,10 +52,10 @@ export interface FetchAvailabilityResponse {
|
|
|
52
52
|
* // response.timeSlots are grouped by time
|
|
53
53
|
* ```
|
|
54
54
|
*/
|
|
55
|
-
export declare function fetchAvailability({ services: selectedServices, viewMode, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, }: {
|
|
55
|
+
export declare function fetchAvailability({ services: selectedServices, viewMode, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, timeSlotsPerDay, }: {
|
|
56
56
|
services: Service[];
|
|
57
|
-
fromLocalDate:
|
|
58
|
-
toLocalDate:
|
|
57
|
+
fromLocalDate: Date;
|
|
58
|
+
toLocalDate: Date;
|
|
59
59
|
timeZone?: string;
|
|
60
60
|
locations?: Location[];
|
|
61
61
|
staffMemberIds?: string[];
|
|
@@ -68,4 +68,5 @@ export declare function fetchAvailability({ services: selectedServices, viewMode
|
|
|
68
68
|
bookOnlineDisabled?: boolean;
|
|
69
69
|
};
|
|
70
70
|
slotsPerPage?: number;
|
|
71
|
+
timeSlotsPerDay?: number;
|
|
71
72
|
}): Promise<FetchAvailabilityResponse>;
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
import { listAvailabilityTimeSlots, } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
6
6
|
import { listEventTimeSlots } from '@wix/auto_sdk_bookings_event-time-slots';
|
|
7
7
|
import { ServiceType } from '@wix/auto_sdk_bookings_services';
|
|
8
|
+
import { format } from 'date-fns';
|
|
9
|
+
import { ANY_STAFF_MEMBER_ID } from '../../services/booking/booking.js';
|
|
8
10
|
import { ViewMode, } from '../../services/time-slot-list/time-slot-list.def.js';
|
|
9
11
|
// ============================================================================
|
|
10
12
|
// Internal Types
|
|
@@ -17,6 +19,16 @@ var FlowType;
|
|
|
17
19
|
})(FlowType || (FlowType = {}));
|
|
18
20
|
const STAFF_RESOURCE_TYPE_ID = '1cd44cf8-756f-41c3-bd90-3e2ffcaf1155';
|
|
19
21
|
// ============================================================================
|
|
22
|
+
// Helpers
|
|
23
|
+
// ============================================================================
|
|
24
|
+
/**
|
|
25
|
+
* Formats a Date to local ISO string (YYYY-MM-DDThh:mm:ss)
|
|
26
|
+
*/
|
|
27
|
+
function toLocalDateString(date) {
|
|
28
|
+
const pattern = "yyyy-MM-dd'T'HH:mm:ss";
|
|
29
|
+
return format(date, pattern);
|
|
30
|
+
}
|
|
31
|
+
// ============================================================================
|
|
20
32
|
// Grouping Functions
|
|
21
33
|
// ============================================================================
|
|
22
34
|
/**
|
|
@@ -103,11 +115,22 @@ function detectFlow(bookingServices, viewMode) {
|
|
|
103
115
|
* // response.timeSlots are grouped by time
|
|
104
116
|
* ```
|
|
105
117
|
*/
|
|
106
|
-
export async function fetchAvailability({ services: selectedServices, viewMode = ViewMode.CLASSIC, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, }) {
|
|
118
|
+
export async function fetchAvailability({ services: selectedServices, viewMode = ViewMode.CLASSIC, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, timeSlotsPerDay, }) {
|
|
107
119
|
const flow = detectFlow(selectedServices, viewMode);
|
|
108
120
|
const serviceIds = selectedServices.map((s) => s._id);
|
|
121
|
+
// Convert Date objects to local ISO strings
|
|
122
|
+
const fromLocalDateStr = toLocalDateString(fromLocalDate);
|
|
123
|
+
const toLocalDateStr = toLocalDateString(toLocalDate);
|
|
124
|
+
const isFetchAvailabileDays = timeSlotsPerDay === 1;
|
|
125
|
+
const cursorPaging = isFetchAvailabileDays
|
|
126
|
+
? undefined
|
|
127
|
+
: {
|
|
128
|
+
cursor,
|
|
129
|
+
limit: slotsPerPage,
|
|
130
|
+
};
|
|
109
131
|
if (flow === FlowType.SINGLE_SERVICE) {
|
|
110
|
-
const
|
|
132
|
+
const isAnyStaffMemberSelected = staffMemberIds?.length === 1 && staffMemberIds[0] === ANY_STAFF_MEMBER_ID;
|
|
133
|
+
const resourceTypes = staffMemberIds?.length && !isAnyStaffMemberSelected
|
|
111
134
|
? [
|
|
112
135
|
{
|
|
113
136
|
resourceTypeId: STAFF_RESOURCE_TYPE_ID,
|
|
@@ -117,18 +140,18 @@ export async function fetchAvailability({ services: selectedServices, viewMode =
|
|
|
117
140
|
: undefined;
|
|
118
141
|
const response = await listAvailabilityTimeSlots({
|
|
119
142
|
serviceId: serviceIds[0],
|
|
120
|
-
fromLocalDate,
|
|
121
|
-
toLocalDate,
|
|
143
|
+
fromLocalDate: fromLocalDateStr,
|
|
144
|
+
toLocalDate: toLocalDateStr,
|
|
122
145
|
timeZone,
|
|
123
146
|
locations,
|
|
124
|
-
cursorPaging
|
|
125
|
-
cursor,
|
|
126
|
-
limit: slotsPerPage,
|
|
127
|
-
},
|
|
147
|
+
cursorPaging,
|
|
128
148
|
resourceTypes,
|
|
129
149
|
bookable,
|
|
130
150
|
bookingPolicyViolations,
|
|
131
|
-
includeResourceTypeIds:
|
|
151
|
+
includeResourceTypeIds: isAnyStaffMemberSelected || isFetchAvailabileDays
|
|
152
|
+
? undefined
|
|
153
|
+
: [STAFF_RESOURCE_TYPE_ID],
|
|
154
|
+
timeSlotsPerDay,
|
|
132
155
|
});
|
|
133
156
|
return {
|
|
134
157
|
timeSlots: groupTimeSlotsByTime(response.timeSlots || []),
|
|
@@ -150,17 +173,15 @@ export async function fetchAvailability({ services: selectedServices, viewMode =
|
|
|
150
173
|
eventFilter['resources.id'] = { $hasSome: staffMemberIds };
|
|
151
174
|
}
|
|
152
175
|
const response = await listEventTimeSlots({
|
|
153
|
-
fromLocalDate,
|
|
154
|
-
toLocalDate,
|
|
176
|
+
fromLocalDate: fromLocalDateStr,
|
|
177
|
+
toLocalDate: toLocalDateStr,
|
|
155
178
|
timeZone,
|
|
156
179
|
serviceIds: serviceIds.length ? serviceIds : undefined,
|
|
157
|
-
cursorPaging
|
|
158
|
-
cursor,
|
|
159
|
-
limit: slotsPerPage,
|
|
160
|
-
},
|
|
180
|
+
cursorPaging,
|
|
161
181
|
eventFilter: Object.keys(eventFilter).length ? eventFilter : undefined,
|
|
162
182
|
includeNonBookable: bookable ? !bookable : undefined,
|
|
163
183
|
bookingPolicyViolations,
|
|
184
|
+
maxSlotsPerDay: timeSlotsPerDay,
|
|
164
185
|
});
|
|
165
186
|
return {
|
|
166
187
|
timeSlots: groupTimeSlotsByTime(response.timeSlots || []),
|
package/cjs/dist/api/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @module API
|
|
6
6
|
*/
|
|
7
7
|
export { getServiceById, getServiceBySlug, queryServices, type PagingMetadata, type ServiceListFilters, type QueryServicesRequest, } from './query-services/index.js';
|
|
8
|
-
export { fetchAvailability } from './
|
|
8
|
+
export { fetchAvailability } from './fetch-availability/index.js';
|
|
9
9
|
/**
|
|
10
10
|
* PagingMetadata includes:
|
|
11
11
|
* - limit: Number of items per page
|
package/cjs/dist/api/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @module API
|
|
6
6
|
*/
|
|
7
7
|
export { getServiceById, getServiceBySlug, queryServices, } from './query-services/index.js';
|
|
8
|
-
export { fetchAvailability } from './
|
|
8
|
+
export { fetchAvailability } from './fetch-availability/index.js';
|
|
9
9
|
/**
|
|
10
10
|
* PagingMetadata includes:
|
|
11
11
|
* - limit: Number of items per page
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import type { BookingServiceConfig } from '../../services/booking/booking.js';
|
|
7
|
+
export type { BookingData, DataProps } from '../core/booking/Booking.js';
|
|
7
8
|
/**
|
|
8
9
|
* Props for Booking.Root component
|
|
9
10
|
*/
|
|
10
11
|
export interface BookingRootProps {
|
|
11
12
|
children: React.ReactNode;
|
|
12
|
-
bookingServiceConfig
|
|
13
|
+
bookingServiceConfig?: BookingServiceConfig;
|
|
13
14
|
}
|
|
14
15
|
/**
|
|
15
16
|
* Root component that provides booking context to the entire app.
|
|
@@ -19,7 +19,7 @@ import * as CoreBooking from '../core/booking/Booking.js';
|
|
|
19
19
|
* ```
|
|
20
20
|
*/
|
|
21
21
|
export const Root = (props) => {
|
|
22
|
-
const { children, bookingServiceConfig } = props;
|
|
22
|
+
const { children, bookingServiceConfig = {} } = props;
|
|
23
23
|
return (_jsx(CoreBooking.Root, { bookingServiceConfig: bookingServiceConfig, children: children }));
|
|
24
24
|
};
|
|
25
25
|
Root.displayName = 'Booking.Root';
|
|
@@ -10,7 +10,7 @@ import type { FormValues } from '@wix/form-public';
|
|
|
10
10
|
*/
|
|
11
11
|
export interface RootProps {
|
|
12
12
|
children: React.ReactNode;
|
|
13
|
-
bookingServiceConfig
|
|
13
|
+
bookingServiceConfig?: BookingServiceConfig;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* Root component that provides booking context to the entire app.
|
|
@@ -35,6 +35,7 @@ export declare function Root(props: RootProps): React.ReactNode;
|
|
|
35
35
|
export interface BookingData {
|
|
36
36
|
serviceSelections: ServiceSelection[];
|
|
37
37
|
location: Location | null;
|
|
38
|
+
timezone: string | undefined;
|
|
38
39
|
formSubmission: FormValues | null;
|
|
39
40
|
actions: BookingServiceActions;
|
|
40
41
|
}
|
|
@@ -52,7 +53,7 @@ export interface DataProps {
|
|
|
52
53
|
* @example
|
|
53
54
|
* ```tsx
|
|
54
55
|
* <Booking.Data>
|
|
55
|
-
* {({ serviceSelections, location, formSubmission, actions }) => (
|
|
56
|
+
* {({ serviceSelections, location, timezone, formSubmission, actions }) => (
|
|
56
57
|
* serviceSelections.length > 0 ? (
|
|
57
58
|
* <div>{serviceSelections.map(item => item.service.name).join(', ')}</div>
|
|
58
59
|
* ) : (
|
|
@@ -18,7 +18,8 @@ import { BookingServiceDefinition, BookingService, } from '../../../services/boo
|
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
20
|
export function Root(props) {
|
|
21
|
-
|
|
21
|
+
const { bookingServiceConfig = {}, children } = props;
|
|
22
|
+
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(BookingServiceDefinition, BookingService, bookingServiceConfig), children: children }));
|
|
22
23
|
}
|
|
23
24
|
/**
|
|
24
25
|
* Core component that provides access to booking data via render props.
|
|
@@ -28,7 +29,7 @@ export function Root(props) {
|
|
|
28
29
|
* @example
|
|
29
30
|
* ```tsx
|
|
30
31
|
* <Booking.Data>
|
|
31
|
-
* {({ serviceSelections, location, formSubmission, actions }) => (
|
|
32
|
+
* {({ serviceSelections, location, timezone, formSubmission, actions }) => (
|
|
32
33
|
* serviceSelections.length > 0 ? (
|
|
33
34
|
* <div>{serviceSelections.map(item => item.service.name).join(', ')}</div>
|
|
34
35
|
* ) : (
|
|
@@ -43,11 +44,13 @@ export function Data(props) {
|
|
|
43
44
|
const bookingService = useService(BookingServiceDefinition);
|
|
44
45
|
const serviceSelections = bookingService.serviceSelections.get();
|
|
45
46
|
const location = bookingService.location.get();
|
|
47
|
+
const timezone = bookingService.timezone.get();
|
|
46
48
|
const formSubmission = bookingService.formSubmission.get();
|
|
47
49
|
const { actions } = bookingService;
|
|
48
50
|
return children({
|
|
49
51
|
serviceSelections,
|
|
50
52
|
location,
|
|
53
|
+
timezone,
|
|
51
54
|
formSubmission,
|
|
52
55
|
actions,
|
|
53
56
|
});
|
|
@@ -88,10 +88,10 @@ export declare function StaffMemberProvider(props: StaffMemberProviderProps): Re
|
|
|
88
88
|
*/
|
|
89
89
|
export interface InfoProps {
|
|
90
90
|
children: (data: {
|
|
91
|
-
/**
|
|
92
|
-
startDate:
|
|
93
|
-
/**
|
|
94
|
-
endDate:
|
|
91
|
+
/** Parsed localStartDate as Date (constructed from the raw localStartDate string) */
|
|
92
|
+
startDate: Date | undefined;
|
|
93
|
+
/** Parsed localEndDate as Date (constructed from the raw localEndDate string) */
|
|
94
|
+
endDate: Date | undefined;
|
|
95
95
|
/** Calculated duration in minutes (null if dates unavailable) */
|
|
96
96
|
durationInMinutes: number | null;
|
|
97
97
|
/** Whether the timeSlot is bookable */
|
|
@@ -9,6 +9,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
9
9
|
import React from 'react';
|
|
10
10
|
import { useService } from '@wix/services-manager-react';
|
|
11
11
|
import { TimeSlotListServiceDefinition, } from '../../../services/time-slot-list/time-slot-list.def.js';
|
|
12
|
+
import { ANY_STAFF_MEMBER_ID } from '../../../services/booking/booking.js';
|
|
12
13
|
const TimeSlotContext = React.createContext(null);
|
|
13
14
|
/**
|
|
14
15
|
* Hook to access TimeSlot context
|
|
@@ -115,15 +116,17 @@ export function StaffMemberProvider(props) {
|
|
|
115
116
|
*/
|
|
116
117
|
export function Info(props) {
|
|
117
118
|
const { timeSlot, isSelected } = useTimeSlotContext();
|
|
118
|
-
const startDate = timeSlot.localStartDate
|
|
119
|
-
|
|
119
|
+
const startDate = timeSlot.localStartDate
|
|
120
|
+
? new Date(timeSlot.localStartDate)
|
|
121
|
+
: undefined;
|
|
122
|
+
const endDate = timeSlot.localEndDate
|
|
123
|
+
? new Date(timeSlot.localEndDate)
|
|
124
|
+
: undefined;
|
|
120
125
|
const bookable = timeSlot.bookable ?? false;
|
|
121
126
|
// Calculate duration from start and end dates
|
|
122
127
|
let durationInMinutes = null;
|
|
123
128
|
if (startDate && endDate) {
|
|
124
|
-
|
|
125
|
-
const endTime = new Date(endDate).getTime();
|
|
126
|
-
durationInMinutes = Math.round((endTime - startTime) / (1000 * 60));
|
|
129
|
+
durationInMinutes = Math.round((endDate.getTime() - startDate.getTime()) / (1000 * 60));
|
|
127
130
|
}
|
|
128
131
|
return props.children({
|
|
129
132
|
startDate,
|
|
@@ -202,12 +205,13 @@ export function Locations(props) {
|
|
|
202
205
|
const selection = service.selection.get();
|
|
203
206
|
const selectedLocationId = selection?.locationId ?? null;
|
|
204
207
|
const selectedStaffMemberId = selection?.staffMemberId ?? null;
|
|
208
|
+
const isAnyStaffMemberSelected = selectedStaffMemberId === ANY_STAFF_MEMBER_ID;
|
|
205
209
|
// Build locations array from staffByLocation (names already included)
|
|
206
210
|
const locations = timeSlot.staffByLocation.map(({ location, staffMembers }) => {
|
|
207
211
|
// Check if this location is selectable based on selected staff
|
|
208
212
|
// If no staff selected, all locations are selectable
|
|
209
213
|
// If staff selected, only locations where that staff works are selectable
|
|
210
|
-
const isSelectable = selectedStaffMemberId
|
|
214
|
+
const isSelectable = !isAnyStaffMemberSelected && selectedStaffMemberId
|
|
211
215
|
? staffMembers.some((s) => s.id === selectedStaffMemberId)
|
|
212
216
|
: true;
|
|
213
217
|
return {
|
|
@@ -311,12 +315,18 @@ export function StaffMembers(props) {
|
|
|
311
315
|
isSelectable: !selectedLocationId ||
|
|
312
316
|
entries.some((e) => e.locationId === selectedLocationId),
|
|
313
317
|
}));
|
|
318
|
+
const anyStaffOption = {
|
|
319
|
+
id: ANY_STAFF_MEMBER_ID,
|
|
320
|
+
name: 'Any staff member',
|
|
321
|
+
isSelected: selectedStaffMemberId === ANY_STAFF_MEMBER_ID,
|
|
322
|
+
isSelectable: true,
|
|
323
|
+
};
|
|
314
324
|
// Return null if only 1 staff member - nothing to choose from
|
|
315
325
|
if (staffMembers.length <= 1) {
|
|
316
326
|
return null;
|
|
317
327
|
}
|
|
318
328
|
return props.children({
|
|
319
|
-
staffMembers,
|
|
329
|
+
staffMembers: [anyStaffOption, ...staffMembers],
|
|
320
330
|
selectStaffMember: service.actions.selectStaffMember,
|
|
321
331
|
});
|
|
322
332
|
}
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useService, WixServices } from '@wix/services-manager-react';
|
|
3
3
|
import { createServicesMap } from '@wix/services-manager';
|
|
4
4
|
import { TimeSlotListServiceDefinition, TimeSlotListService, } from '../../../services/time-slot-list/index.js';
|
|
5
|
+
import { BookingServiceDefinition } from '../../../services/booking/booking.js';
|
|
5
6
|
/**
|
|
6
7
|
* Root component that provides TimeSlotListService context to its children.
|
|
7
8
|
*
|
|
@@ -54,8 +55,8 @@ function getTimezoneDisplayName(timezone) {
|
|
|
54
55
|
* ```
|
|
55
56
|
*/
|
|
56
57
|
export function Timezone(props) {
|
|
57
|
-
const
|
|
58
|
-
const timezone =
|
|
58
|
+
const bookingService = useService(BookingServiceDefinition);
|
|
59
|
+
const timezone = bookingService.timezone.get();
|
|
59
60
|
const displayName = getTimezoneDisplayName(timezone);
|
|
60
61
|
return props.children({ timezone, displayName });
|
|
61
62
|
}
|
|
@@ -16,18 +16,18 @@ export type { LocationData, StaffMemberData, } from '../core/time-slot-list/Time
|
|
|
16
16
|
export interface StartDateProps {
|
|
17
17
|
asChild?: boolean;
|
|
18
18
|
children?: AsChildChildren<{
|
|
19
|
-
startDate:
|
|
19
|
+
startDate: Date | undefined;
|
|
20
20
|
}>;
|
|
21
21
|
className?: string;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
-
* Displays the time slot start date/time as a
|
|
24
|
+
* Displays the time slot start date/time as a Date.
|
|
25
25
|
* Consumer is responsible for formatting.
|
|
26
26
|
*
|
|
27
27
|
* @component
|
|
28
28
|
* @example
|
|
29
29
|
* ```tsx
|
|
30
|
-
* // Default usage - displays
|
|
30
|
+
* // Default usage - displays Date.toString()
|
|
31
31
|
* <TimeSlot.StartDate className="text-foreground" />
|
|
32
32
|
*
|
|
33
33
|
* // With custom formatting
|
|
@@ -45,18 +45,18 @@ export declare const StartDate: React.ForwardRefExoticComponent<StartDateProps &
|
|
|
45
45
|
export interface EndDateProps {
|
|
46
46
|
asChild?: boolean;
|
|
47
47
|
children?: AsChildChildren<{
|
|
48
|
-
endDate:
|
|
48
|
+
endDate: Date | undefined;
|
|
49
49
|
}>;
|
|
50
50
|
className?: string;
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
|
-
* Displays the time slot end date/time as a
|
|
53
|
+
* Displays the time slot end date/time as a Date.
|
|
54
54
|
* Consumer is responsible for formatting.
|
|
55
55
|
*
|
|
56
56
|
* @component
|
|
57
57
|
* @example
|
|
58
58
|
* ```tsx
|
|
59
|
-
* // Default usage - displays
|
|
59
|
+
* // Default usage - displays Date.toString()
|
|
60
60
|
* <TimeSlot.EndDate className="text-foreground" />
|
|
61
61
|
*
|
|
62
62
|
* // With custom formatting
|
|
@@ -34,13 +34,13 @@ var TestIds;
|
|
|
34
34
|
TestIds["timeSlotStaffMemberActionSelect"] = "time-slot-staff-member-action-select";
|
|
35
35
|
})(TestIds || (TestIds = {}));
|
|
36
36
|
/**
|
|
37
|
-
* Displays the time slot start date/time as a
|
|
37
|
+
* Displays the time slot start date/time as a Date.
|
|
38
38
|
* Consumer is responsible for formatting.
|
|
39
39
|
*
|
|
40
40
|
* @component
|
|
41
41
|
* @example
|
|
42
42
|
* ```tsx
|
|
43
|
-
* // Default usage - displays
|
|
43
|
+
* // Default usage - displays Date.toString()
|
|
44
44
|
* <TimeSlot.StartDate className="text-foreground" />
|
|
45
45
|
*
|
|
46
46
|
* // With custom formatting
|
|
@@ -53,17 +53,17 @@ var TestIds;
|
|
|
53
53
|
*/
|
|
54
54
|
export const StartDate = React.forwardRef((props, ref) => {
|
|
55
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 }) })) }));
|
|
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?.toString() }) })) }));
|
|
57
57
|
});
|
|
58
58
|
StartDate.displayName = 'TimeSlot.StartDate';
|
|
59
59
|
/**
|
|
60
|
-
* Displays the time slot end date/time as a
|
|
60
|
+
* Displays the time slot end date/time as a Date.
|
|
61
61
|
* Consumer is responsible for formatting.
|
|
62
62
|
*
|
|
63
63
|
* @component
|
|
64
64
|
* @example
|
|
65
65
|
* ```tsx
|
|
66
|
-
* // Default usage - displays
|
|
66
|
+
* // Default usage - displays Date.toString()
|
|
67
67
|
* <TimeSlot.EndDate className="text-foreground" />
|
|
68
68
|
*
|
|
69
69
|
* // With custom formatting
|
|
@@ -76,7 +76,7 @@ StartDate.displayName = 'TimeSlot.StartDate';
|
|
|
76
76
|
*/
|
|
77
77
|
export const EndDate = React.forwardRef((props, ref) => {
|
|
78
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 }) })) }));
|
|
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?.toString() }) })) }));
|
|
80
80
|
});
|
|
81
81
|
EndDate.displayName = 'TimeSlot.EndDate';
|
|
82
82
|
/**
|
|
@@ -113,10 +113,10 @@ export interface TimeSlotRepeaterChildProps {
|
|
|
113
113
|
isSelected: boolean;
|
|
114
114
|
/** Whether the slot can be booked */
|
|
115
115
|
bookable: boolean;
|
|
116
|
-
/** Start date/time as
|
|
117
|
-
startDate:
|
|
118
|
-
/** End date/time as
|
|
119
|
-
endDate:
|
|
116
|
+
/** Start date/time as Date (constructed from the raw localStartDate string) */
|
|
117
|
+
startDate: Date | undefined;
|
|
118
|
+
/** End date/time as Date (constructed from the raw localEndDate string) */
|
|
119
|
+
endDate: Date | undefined;
|
|
120
120
|
/** Duration in minutes */
|
|
121
121
|
durationInMinutes: number | null;
|
|
122
122
|
/** The raw time slot data */
|
|
@@ -7,6 +7,7 @@ import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
|
7
7
|
import type { Service } from '@wix/auto_sdk_bookings_services';
|
|
8
8
|
import type { Resource, EventInfo } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
9
9
|
import type { FormValues } from '@wix/form-public';
|
|
10
|
+
export declare const ANY_STAFF_MEMBER_ID = "__any_staff_member__";
|
|
10
11
|
/**
|
|
11
12
|
* Minimal time slot data for service selections
|
|
12
13
|
*/
|
|
@@ -57,6 +58,7 @@ export interface BookingServiceActions {
|
|
|
57
58
|
getResourceById(resourceId: string, instanceId?: string): Resource | undefined;
|
|
58
59
|
setLocation(location: Location | null): void;
|
|
59
60
|
clearLocation(): void;
|
|
61
|
+
setTimezone(timezone: string): void;
|
|
60
62
|
setFormSubmission(values: FormValues | null): void;
|
|
61
63
|
clearFormSubmission(): void;
|
|
62
64
|
clearAll(): void;
|
|
@@ -70,6 +72,8 @@ export interface BookingService {
|
|
|
70
72
|
serviceSelections: Signal<ServiceSelection[]>;
|
|
71
73
|
/** Signal containing the selected location */
|
|
72
74
|
location: Signal<Location | null>;
|
|
75
|
+
/** Signal containing the selected timezone */
|
|
76
|
+
timezone: Signal<string | undefined>;
|
|
73
77
|
/** Signal containing the form submission */
|
|
74
78
|
formSubmission: Signal<FormValues | null>;
|
|
75
79
|
/** Actions for modifying booking state */
|
|
@@ -92,6 +96,8 @@ export interface BookingServiceConfig {
|
|
|
92
96
|
serviceSelections?: ServiceSelection[];
|
|
93
97
|
/** Optional initial location */
|
|
94
98
|
location?: Location | null;
|
|
99
|
+
/** Optional initial timezone */
|
|
100
|
+
timezone?: string;
|
|
95
101
|
/** Optional initial form submission */
|
|
96
102
|
formSubmission?: FormValues | null;
|
|
97
103
|
}
|
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
7
7
|
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
8
8
|
// ============================================================================
|
|
9
|
-
//
|
|
9
|
+
// Constants
|
|
10
|
+
// ============================================================================
|
|
11
|
+
export const ANY_STAFF_MEMBER_ID = '__any_staff_member__';
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Helpers
|
|
10
14
|
// ============================================================================
|
|
11
15
|
/**
|
|
12
16
|
* Generates a unique instance ID for service selections
|
|
@@ -14,6 +18,14 @@ import { SignalsServiceDefinition, } from '@wix/services-definitions/core-servic
|
|
|
14
18
|
function generateInstanceId() {
|
|
15
19
|
return crypto.randomUUID();
|
|
16
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Gets the client's timezone from Intl API
|
|
23
|
+
*/
|
|
24
|
+
function getClientTimezone() {
|
|
25
|
+
return typeof Intl !== 'undefined'
|
|
26
|
+
? Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
27
|
+
: undefined;
|
|
28
|
+
}
|
|
17
29
|
/**
|
|
18
30
|
* Service definition for Booking
|
|
19
31
|
*/
|
|
@@ -55,6 +67,7 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
|
|
|
55
67
|
}));
|
|
56
68
|
const serviceSelectionsSignal = signalsService.signal(initialItemsWithIds);
|
|
57
69
|
const locationSignal = signalsService.signal(config.location || null);
|
|
70
|
+
const timezoneSignal = signalsService.signal(config.timezone ?? getClientTimezone());
|
|
58
71
|
const formSubmissionSignal = signalsService.signal(config.formSubmission || null);
|
|
59
72
|
// ========================================================================
|
|
60
73
|
// Actions Implementation
|
|
@@ -142,6 +155,12 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
|
|
|
142
155
|
clearLocation() {
|
|
143
156
|
locationSignal.set(null);
|
|
144
157
|
},
|
|
158
|
+
// Timezone actions
|
|
159
|
+
setTimezone(timezone) {
|
|
160
|
+
if (timezoneSignal.get() !== timezone) {
|
|
161
|
+
timezoneSignal.set(timezone);
|
|
162
|
+
}
|
|
163
|
+
},
|
|
145
164
|
// Form Submission actions
|
|
146
165
|
setFormSubmission(values) {
|
|
147
166
|
formSubmissionSignal.set(values);
|
|
@@ -159,6 +178,7 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
|
|
|
159
178
|
return {
|
|
160
179
|
serviceSelections: serviceSelectionsSignal,
|
|
161
180
|
location: locationSignal,
|
|
181
|
+
timezone: timezoneSignal,
|
|
162
182
|
formSubmission: formSubmissionSignal,
|
|
163
183
|
actions,
|
|
164
184
|
};
|
|
@@ -65,11 +65,21 @@ export interface TimeSlotsFilters {
|
|
|
65
65
|
* Default: 1000. Max: 1000.
|
|
66
66
|
* @example
|
|
67
67
|
* ```ts
|
|
68
|
-
* // Load
|
|
69
|
-
* filters: { slotsPerPage:
|
|
68
|
+
* // Load 10 slots at a time
|
|
69
|
+
* filters: { slotsPerPage: 10 }
|
|
70
70
|
* ```
|
|
71
71
|
*/
|
|
72
72
|
slotsPerPage?: number;
|
|
73
|
+
/**
|
|
74
|
+
* Maximum number of time slots to return per day.
|
|
75
|
+
* Useful for fetching availability indicators (set to 1 to get one slot per day).
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* // Get one slot per day for calendar indicators
|
|
79
|
+
* filters: { timeSlotsPerDay: 1 }
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
timeSlotsPerDay?: number;
|
|
73
83
|
}
|
|
74
84
|
export interface TimeSlotListServiceConfig {
|
|
75
85
|
/** Services to fetch time slots for */
|
|
@@ -92,7 +102,6 @@ export interface TimeSlotListServiceActions {
|
|
|
92
102
|
clearPreferences: () => void;
|
|
93
103
|
loadMore: () => Promise<void>;
|
|
94
104
|
setDateRange: (start: Date, end: Date) => void;
|
|
95
|
-
setTimezone: (tz: string) => void;
|
|
96
105
|
}
|
|
97
106
|
export interface TimeSlotListServiceAPI {
|
|
98
107
|
timeSlots: Signal<TimeSlot[]>;
|
|
@@ -102,7 +111,6 @@ export interface TimeSlotListServiceAPI {
|
|
|
102
111
|
hasMore: Signal<boolean>;
|
|
103
112
|
startDate: Signal<Date>;
|
|
104
113
|
endDate: Signal<Date>;
|
|
105
|
-
timezone: Signal<string | undefined>;
|
|
106
114
|
actions: TimeSlotListServiceActions;
|
|
107
115
|
}
|
|
108
116
|
export declare const TimeSlotListServiceDefinition: string & {
|