@wix/headless-bookings 1.0.0 → 1.0.2
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/__mocks__/booking/booking-mocks.d.ts +1 -1
- package/cjs/dist/__mocks__/services/services-mocks.d.ts +23 -0
- package/cjs/dist/__mocks__/services/services-mocks.js +65 -1
- package/cjs/dist/api/query-services/index.js +2 -2
- package/cjs/dist/react/core/booking/Booking.d.ts +1 -1
- package/cjs/dist/react/core/booking/Booking.js +18 -5
- package/cjs/dist/react/core/location/Location.d.ts +1 -1
- package/cjs/dist/react/core/location/Location.js +5 -5
- package/cjs/dist/react/core/service/Service.d.ts +10 -1
- package/cjs/dist/react/core/service/Service.js +5 -4
- package/cjs/dist/react/service/Service.d.ts +68 -1
- package/cjs/dist/react/service/Service.js +81 -1
- package/cjs/dist/services/booking/booking.d.ts +1 -1
- package/cjs/dist/services/location-list/location-list.def.d.ts +1 -1
- package/cjs/dist/services/location-list/location-list.def.js +1 -1
- package/cjs/dist/services/location-list/location-list.js +7 -7
- package/cjs/dist/services/payment/payment.def.d.ts +6 -0
- package/cjs/dist/services/payment/payment.js +56 -5
- package/dist/__mocks__/booking/booking-mocks.d.ts +1 -1
- package/dist/__mocks__/services/services-mocks.d.ts +23 -0
- package/dist/__mocks__/services/services-mocks.js +64 -0
- package/dist/api/query-services/index.js +1 -1
- package/dist/react/core/booking/Booking.d.ts +1 -1
- package/dist/react/core/booking/Booking.js +18 -5
- package/dist/react/core/location/Location.d.ts +1 -1
- package/dist/react/core/location/Location.js +1 -1
- package/dist/react/core/service/Service.d.ts +10 -1
- package/dist/react/core/service/Service.js +5 -4
- package/dist/react/service/Service.d.ts +68 -1
- package/dist/react/service/Service.js +81 -1
- package/dist/services/booking/booking.d.ts +1 -1
- package/dist/services/location-list/location-list.def.d.ts +1 -1
- package/dist/services/location-list/location-list.def.js +1 -1
- package/dist/services/location-list/location-list.js +1 -1
- package/dist/services/payment/payment.def.d.ts +6 -0
- package/dist/services/payment/payment.js +57 -6
- package/package.json +5 -3
|
@@ -10,6 +10,7 @@ exports.loadPaymentConfig = loadPaymentConfig;
|
|
|
10
10
|
const services_definitions_1 = require("@wix/services-definitions");
|
|
11
11
|
const signals_1 = require("@wix/services-definitions/core-services/signals");
|
|
12
12
|
const auto_sdk_ecom_totals_calculator_1 = require("@wix/auto_sdk_ecom_totals-calculator");
|
|
13
|
+
const auto_sdk_bookings_pricing_1 = require("@wix/auto_sdk_bookings_pricing");
|
|
13
14
|
const booking_js_1 = require("../booking/booking.js");
|
|
14
15
|
const auto_sdk_bookings_services_1 = require("@wix/auto_sdk_bookings_services");
|
|
15
16
|
const payment_def_js_1 = require("./payment.def.js");
|
|
@@ -91,13 +92,56 @@ function buildLineItem(service, totalParticipants, lineItemId) {
|
|
|
91
92
|
paymentOption,
|
|
92
93
|
};
|
|
93
94
|
}
|
|
95
|
+
// durationRange is an @internal field on AvailabilityConstraints (bookings services SDK v1.0.226+).
|
|
96
|
+
// It signals that the service uses flexible duration pricing (hourly/daily rentals),
|
|
97
|
+
// where the correct price must be fetched via previewPrice() rather than the fixed unit price.
|
|
98
|
+
function getDurationRange(service) {
|
|
99
|
+
return service.schedule?.availabilityConstraints?.durationRange;
|
|
100
|
+
}
|
|
101
|
+
async function getPreviewedPrice(service, localStartDate, localEndDate, timeZone) {
|
|
102
|
+
if (!service._id)
|
|
103
|
+
return null;
|
|
104
|
+
const lineItemInput = {
|
|
105
|
+
serviceId: service._id,
|
|
106
|
+
localStartDate,
|
|
107
|
+
localEndDate,
|
|
108
|
+
...(timeZone ? { timeZone } : {}),
|
|
109
|
+
};
|
|
110
|
+
const result = await (0, auto_sdk_bookings_pricing_1.previewPrice)([lineItemInput]);
|
|
111
|
+
return result.priceInfo?.calculatedPrice ?? null;
|
|
112
|
+
}
|
|
113
|
+
async function buildLineItemWithPreview(item, totalParticipants) {
|
|
114
|
+
if (item.localStartDate &&
|
|
115
|
+
item.localEndDate &&
|
|
116
|
+
getDurationRange(item.service)) {
|
|
117
|
+
const previewedPrice = await getPreviewedPrice(item.service, item.localStartDate, item.localEndDate, item.timeZone).catch(() => null);
|
|
118
|
+
if (previewedPrice != null) {
|
|
119
|
+
const depositValue = item.service.payment?.fixed?.deposit?.value;
|
|
120
|
+
const hasDeposit = !!depositValue && Number(depositValue) > 0;
|
|
121
|
+
const deposit = hasDeposit
|
|
122
|
+
? Number(depositValue) * totalParticipants
|
|
123
|
+
: undefined;
|
|
124
|
+
return {
|
|
125
|
+
_id: item.lineItemId,
|
|
126
|
+
catalogReference: {
|
|
127
|
+
catalogItemId: item.service._id || '',
|
|
128
|
+
appId: constants_js_1.BOOKING_APP_ID,
|
|
129
|
+
},
|
|
130
|
+
price: String(previewedPrice),
|
|
131
|
+
...(deposit ? { depositAmount: String(deposit) } : {}),
|
|
132
|
+
quantity: 1,
|
|
133
|
+
paymentOption: getPaymentOption(item.service, hasDeposit),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return buildLineItem(item.service, totalParticipants, item.lineItemId);
|
|
138
|
+
}
|
|
94
139
|
async function calculatePaymentDetails(pricingServiceSelections, totalParticipants) {
|
|
95
|
-
// Ensure all booking services have a lineItemId
|
|
96
140
|
const data = pricingServiceSelections.map((selection) => ({
|
|
97
141
|
...selection,
|
|
98
142
|
lineItemId: selection.lineItemId || (0, guid_js_1.generateLineItemId)(),
|
|
99
143
|
}));
|
|
100
|
-
const lineItems = data.map((item) =>
|
|
144
|
+
const lineItems = await Promise.all(data.map((item) => buildLineItemWithPreview(item, totalParticipants)));
|
|
101
145
|
const response = await (0, auto_sdk_ecom_totals_calculator_1.calculateTotals)({
|
|
102
146
|
lineItems,
|
|
103
147
|
});
|
|
@@ -168,22 +212,29 @@ exports.PaymentService = services_definitions_1.implementService.withConfig()(pa
|
|
|
168
212
|
}
|
|
169
213
|
// Mode 3: Reactive - observe BookingService signals (client-side only)
|
|
170
214
|
else if (typeof window !== 'undefined' && bookingService) {
|
|
171
|
-
// Computed signal that
|
|
215
|
+
// Computed signal that changes when services or selected time slots change (not participants)
|
|
172
216
|
const servicesKey = signalsService.computed(() => {
|
|
173
217
|
const selections = bookingService?.serviceSelections.get() || [];
|
|
174
|
-
|
|
218
|
+
const timezone = bookingService?.timezone.get();
|
|
219
|
+
return (selections
|
|
220
|
+
.map((s) => `${s.service._id}:${s.timeSlot?.startDate ?? ''}:${s.timeSlot?.endDate ?? ''}`)
|
|
221
|
+
.join(',') + `:${timezone ?? ''}`);
|
|
175
222
|
});
|
|
176
223
|
signalsService.effect(() => {
|
|
177
|
-
// Subscribe to servicesKey to trigger effect
|
|
224
|
+
// Subscribe to servicesKey to trigger effect when service or time slot changes
|
|
178
225
|
servicesKey.get();
|
|
179
226
|
// Read current selections without subscribing (peek)
|
|
180
227
|
const selections = bookingService?.serviceSelections.peek() || [];
|
|
228
|
+
const timezone = bookingService?.timezone.peek();
|
|
181
229
|
// For single service mode, take the first selection
|
|
182
230
|
const firstSelection = selections[0];
|
|
183
231
|
const numParticipants = firstSelection?.totalParticipants || 1;
|
|
184
232
|
const pricingServiceSelections = selections.map((selection) => ({
|
|
185
233
|
service: selection.service,
|
|
186
234
|
lineItemId: selection.instanceId,
|
|
235
|
+
localStartDate: selection.timeSlot?.startDate,
|
|
236
|
+
localEndDate: selection.timeSlot?.endDate,
|
|
237
|
+
timeZone: timezone,
|
|
187
238
|
}));
|
|
188
239
|
if (pricingServiceSelections.length) {
|
|
189
240
|
serviceOptionsSignal.set(deriveServiceOptions(pricingServiceSelections));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FormValues } from '@wix/forms/components';
|
|
2
|
-
import type { Location } from '@wix/auto_sdk_bookings_services';
|
|
2
|
+
import type { V2Location as Location } from '@wix/auto_sdk_bookings_services';
|
|
3
3
|
import type { ServiceSelection, ServiceSelectionTimeSlot, ExtendedResource } from '../../services/booking/booking.js';
|
|
4
4
|
export declare function createMockResource(overrides?: Partial<ExtendedResource>): ExtendedResource;
|
|
5
5
|
export declare function createMockLocation(overrides?: Partial<Location>): Location;
|
|
@@ -35,6 +35,29 @@ export declare const mockServiceCourse: Service;
|
|
|
35
35
|
* Mock service without optional fields (minimal)
|
|
36
36
|
*/
|
|
37
37
|
export declare const mockServiceMinimal: Service;
|
|
38
|
+
/**
|
|
39
|
+
* Mock service driving the fixed-duration path: a single value in
|
|
40
|
+
* `sessionDurations`, no `durationRange`. Drives `Service.DurationInMinutes`;
|
|
41
|
+
* `Service.DurationRange` renders nothing for this shape.
|
|
42
|
+
*
|
|
43
|
+
* `mockService` already carries this shape — this is a renamed copy for
|
|
44
|
+
* tests/examples that want to name the case they're exercising.
|
|
45
|
+
*/
|
|
46
|
+
export declare const mockServiceFixedDuration: Service;
|
|
47
|
+
/**
|
|
48
|
+
* Mock service driving the HOUR-unit DurationRange path. Mirrors the server
|
|
49
|
+
* payload shape: empty `sessionDurations`, range pre-computed at
|
|
50
|
+
* `availabilityConstraints.durationRange`. `durationRange` is not yet in the
|
|
51
|
+
* SDK's `AvailabilityConstraints` typing (runtime is ahead of types), so the
|
|
52
|
+
* service object is cast — matches the read-side cast in
|
|
53
|
+
* `core/service/Service.tsx`.
|
|
54
|
+
*/
|
|
55
|
+
export declare const mockServiceHourRange: Service;
|
|
56
|
+
/**
|
|
57
|
+
* Mock service driving the DAY-unit DurationRange path. Same server shape as
|
|
58
|
+
* {@link mockServiceHourRange}.
|
|
59
|
+
*/
|
|
60
|
+
export declare const mockServiceDayRange: Service;
|
|
38
61
|
/**
|
|
39
62
|
* Array of mock services for list tests
|
|
40
63
|
*/
|
|
@@ -170,6 +170,70 @@ export const mockServiceMinimal = {
|
|
|
170
170
|
name: 'Minimal Service',
|
|
171
171
|
description: '',
|
|
172
172
|
};
|
|
173
|
+
/**
|
|
174
|
+
* Mock service driving the fixed-duration path: a single value in
|
|
175
|
+
* `sessionDurations`, no `durationRange`. Drives `Service.DurationInMinutes`;
|
|
176
|
+
* `Service.DurationRange` renders nothing for this shape.
|
|
177
|
+
*
|
|
178
|
+
* `mockService` already carries this shape — this is a renamed copy for
|
|
179
|
+
* tests/examples that want to name the case they're exercising.
|
|
180
|
+
*/
|
|
181
|
+
export const mockServiceFixedDuration = {
|
|
182
|
+
...mockService,
|
|
183
|
+
_id: 'test-service-fixed-duration',
|
|
184
|
+
name: 'Fixed Duration Service',
|
|
185
|
+
schedule: {
|
|
186
|
+
availabilityConstraints: {
|
|
187
|
+
sessionDurations: [60],
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* Mock service driving the HOUR-unit DurationRange path. Mirrors the server
|
|
193
|
+
* payload shape: empty `sessionDurations`, range pre-computed at
|
|
194
|
+
* `availabilityConstraints.durationRange`. `durationRange` is not yet in the
|
|
195
|
+
* SDK's `AvailabilityConstraints` typing (runtime is ahead of types), so the
|
|
196
|
+
* service object is cast — matches the read-side cast in
|
|
197
|
+
* `core/service/Service.tsx`.
|
|
198
|
+
*/
|
|
199
|
+
export const mockServiceHourRange = {
|
|
200
|
+
...mockService,
|
|
201
|
+
_id: 'test-service-hour-range',
|
|
202
|
+
name: 'Hourly Range Service',
|
|
203
|
+
schedule: {
|
|
204
|
+
availabilityConstraints: {
|
|
205
|
+
sessionDurations: [],
|
|
206
|
+
durationRange: {
|
|
207
|
+
unitType: 'HOUR',
|
|
208
|
+
hourOptions: {
|
|
209
|
+
minDurationInMinutes: 120,
|
|
210
|
+
maxDurationInMinutes: 540,
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* Mock service driving the DAY-unit DurationRange path. Same server shape as
|
|
218
|
+
* {@link mockServiceHourRange}.
|
|
219
|
+
*/
|
|
220
|
+
export const mockServiceDayRange = {
|
|
221
|
+
...mockService,
|
|
222
|
+
_id: 'test-service-day-range',
|
|
223
|
+
name: 'Daily Range Service',
|
|
224
|
+
schedule: {
|
|
225
|
+
availabilityConstraints: {
|
|
226
|
+
sessionDurations: [],
|
|
227
|
+
durationRange: {
|
|
228
|
+
unitType: 'DAY',
|
|
229
|
+
dayOptions: {
|
|
230
|
+
minDurationInDays: 2,
|
|
231
|
+
maxDurationInDays: 5,
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
};
|
|
173
237
|
/**
|
|
174
238
|
* Array of mock services for list tests
|
|
175
239
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Query Services API
|
|
3
3
|
* Fetches single or multiple services with pagination and sorting
|
|
4
4
|
*/
|
|
5
|
-
import { queryServices as queryServicesApi, LocationType, } from '@wix/auto_sdk_bookings_services';
|
|
5
|
+
import { queryServices as queryServicesApi, LocationTypeEnumLocationType as LocationType, } from '@wix/auto_sdk_bookings_services';
|
|
6
6
|
import { BOOKING_APP_ID } from '../../services/constants.js';
|
|
7
7
|
/**
|
|
8
8
|
* Synthetic location ID constants for non-business locations
|
|
@@ -6,7 +6,7 @@ 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/forms/components';
|
|
8
8
|
import type { TimeSlot, Resource } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
9
|
-
import { type Service, type
|
|
9
|
+
import { type Service, type V2Location as ServiceLocationType } from '@wix/auto_sdk_bookings_services';
|
|
10
10
|
import type { PricingServiceSelection } from '../../../services/payment/payment.js';
|
|
11
11
|
/**
|
|
12
12
|
* Props for Booking.Root component
|
|
@@ -7,7 +7,7 @@ import React from 'react';
|
|
|
7
7
|
import { WixServices, useService } from '@wix/services-manager-react';
|
|
8
8
|
import { createServicesMap } from '@wix/services-manager';
|
|
9
9
|
import { BookingServiceDefinition, BookingService, } from '../../../services/booking/booking.js';
|
|
10
|
-
import { LocationType, } from '@wix/auto_sdk_bookings_services';
|
|
10
|
+
import { LocationTypeEnumLocationType as LocationType, } from '@wix/auto_sdk_bookings_services';
|
|
11
11
|
/**
|
|
12
12
|
* Root component that provides booking context to the entire app.
|
|
13
13
|
*
|
|
@@ -53,7 +53,16 @@ export function Root(props) {
|
|
|
53
53
|
function mapTimeSlotLocationToServiceLocation(timeSlotLocation) {
|
|
54
54
|
// TimeSlot location has flat name/formattedAddress at top level
|
|
55
55
|
// Convert to nested business/custom structure that CoreLocation expects
|
|
56
|
-
const
|
|
56
|
+
const isCustomer = timeSlotLocation.locationType === LocationType.CUSTOMER;
|
|
57
|
+
const isCustom = timeSlotLocation.locationType === LocationType.CUSTOM;
|
|
58
|
+
// The two SDKs share BUSINESS/CUSTOM/CUSTOMER but the time-slots enum also
|
|
59
|
+
// exposes UNKNOWN_LOCATION_TYPE, which V2Location.type does not accept.
|
|
60
|
+
// Default to BUSINESS for any unrecognized value.
|
|
61
|
+
const type = isCustomer
|
|
62
|
+
? LocationType.CUSTOMER
|
|
63
|
+
: isCustom
|
|
64
|
+
? LocationType.CUSTOM
|
|
65
|
+
: LocationType.BUSINESS;
|
|
57
66
|
const location = {
|
|
58
67
|
_id: timeSlotLocation._id ?? undefined,
|
|
59
68
|
name: timeSlotLocation.name ?? undefined,
|
|
@@ -65,10 +74,10 @@ function mapTimeSlotLocationToServiceLocation(timeSlotLocation) {
|
|
|
65
74
|
};
|
|
66
75
|
return {
|
|
67
76
|
_id: timeSlotLocation._id ?? undefined,
|
|
68
|
-
type
|
|
69
|
-
...(
|
|
77
|
+
type,
|
|
78
|
+
...(isCustomer
|
|
70
79
|
? null
|
|
71
|
-
:
|
|
80
|
+
: isCustom
|
|
72
81
|
? { custom: location }
|
|
73
82
|
: { business: location }),
|
|
74
83
|
};
|
|
@@ -275,9 +284,13 @@ export function PaymentData(props) {
|
|
|
275
284
|
const { children } = props;
|
|
276
285
|
const bookingService = useService(BookingServiceDefinition);
|
|
277
286
|
const serviceSelections = bookingService.serviceSelections.get();
|
|
287
|
+
const timezone = bookingService.timezone.get();
|
|
278
288
|
const pricingServiceSelections = serviceSelections.map((selection) => ({
|
|
279
289
|
service: selection.service,
|
|
280
290
|
lineItemId: selection.instanceId,
|
|
291
|
+
localStartDate: selection.timeSlot?.startDate,
|
|
292
|
+
localEndDate: selection.timeSlot?.endDate,
|
|
293
|
+
timeZone: timezone,
|
|
281
294
|
}));
|
|
282
295
|
return children({ pricingServiceSelections });
|
|
283
296
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @module Core/Location
|
|
7
7
|
*/
|
|
8
8
|
import React from 'react';
|
|
9
|
-
import { LocationType } from '@wix/auto_sdk_bookings_services';
|
|
9
|
+
import { LocationTypeEnumLocationType as LocationType } from '@wix/auto_sdk_bookings_services';
|
|
10
10
|
import type { AddressData as AddressDataType } from '@wix/headless-components/react';
|
|
11
11
|
import type { Location } from '../../../services/location-list/location-list.def.js';
|
|
12
12
|
/**
|
|
@@ -8,7 +8,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
8
8
|
*/
|
|
9
9
|
import React, { createContext, useContext } from 'react';
|
|
10
10
|
import { useService } from '@wix/services-manager-react';
|
|
11
|
-
import { LocationType } from '@wix/auto_sdk_bookings_services';
|
|
11
|
+
import { LocationTypeEnumLocationType as LocationType } from '@wix/auto_sdk_bookings_services';
|
|
12
12
|
import { BookingServiceDefinition } from '../../../services/booking/booking.js';
|
|
13
13
|
import { LocationListServiceDefinition } from '../../../services/location-list/location-list.def.js';
|
|
14
14
|
// ==========================================
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import { type ServiceServiceConfig } from '../../../services/service/service.js';
|
|
7
|
-
import type { Service, Payment, BookingPolicy, Schedule, StaffMember } from '@wix/auto_sdk_bookings_services';
|
|
7
|
+
import type { Service, Payment, BookingPolicy, Schedule, StaffMember, DurationRange } from '@wix/auto_sdk_bookings_services';
|
|
8
8
|
import type { MoneyData } from '@wix/headless-components/react';
|
|
9
9
|
/**
|
|
10
10
|
* Props for Service.Root component
|
|
@@ -50,6 +50,15 @@ export interface InfoProps {
|
|
|
50
50
|
description: string;
|
|
51
51
|
tagline?: string;
|
|
52
52
|
duration?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Typed range of supported session durations, derived from
|
|
55
|
+
* `service.schedule.availabilityConstraints.sessionDurations`. Set when the
|
|
56
|
+
* service supports two or more distinct durations; otherwise undefined and
|
|
57
|
+
* the single-value `duration` field above should be used. Consumers branch
|
|
58
|
+
* on `range.unitType` (the SDK `UnitType` enum) and read the matching
|
|
59
|
+
* `range.hourOptions` / `range.dayOptions` config.
|
|
60
|
+
*/
|
|
61
|
+
durationRange?: DurationRange;
|
|
53
62
|
type?: string;
|
|
54
63
|
category?: {
|
|
55
64
|
name?: string;
|
|
@@ -87,9 +87,9 @@ export function Info(props) {
|
|
|
87
87
|
currency,
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
90
|
+
const constraints = service.schedule?.availabilityConstraints;
|
|
91
|
+
const duration = constraints?.sessionDurations?.[0];
|
|
92
|
+
const durationRange = constraints?.durationRange;
|
|
93
93
|
// Get staff members from staffMemberDetails.staffMembers
|
|
94
94
|
// (available when using conditionalFields: ['STAFF_MEMBER_DETAILS'] in queryServices)
|
|
95
95
|
const staff = service.staffMembers || [];
|
|
@@ -119,7 +119,8 @@ export function Info(props) {
|
|
|
119
119
|
name: service.name || '',
|
|
120
120
|
description: service.description || '',
|
|
121
121
|
tagline: service.tagLine || undefined,
|
|
122
|
-
duration
|
|
122
|
+
duration,
|
|
123
|
+
durationRange,
|
|
123
124
|
type: service.type,
|
|
124
125
|
category: service.category
|
|
125
126
|
? {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import { AsChildChildren } from '@wix/headless-utils/react';
|
|
7
7
|
import { MoneyData } from '@wix/headless-components/react';
|
|
8
|
-
import { type Service, type Payment } from '@wix/auto_sdk_bookings_services';
|
|
8
|
+
import { type Service, type Payment, type DurationRange as DurationRangeData } from '@wix/auto_sdk_bookings_services';
|
|
9
9
|
import * as ServiceMediaModule from './ServiceMedia.js';
|
|
10
10
|
export declare const TestIds: {
|
|
11
11
|
readonly serviceRoot: "service-root";
|
|
@@ -14,6 +14,7 @@ export declare const TestIds: {
|
|
|
14
14
|
readonly servicePrice: "service-price";
|
|
15
15
|
readonly serviceTagline: "service-tagline";
|
|
16
16
|
readonly serviceDurationInMinutes: "service-duration-in-minutes";
|
|
17
|
+
readonly serviceDurationRange: "service-duration-range";
|
|
17
18
|
readonly serviceType: "service-type";
|
|
18
19
|
readonly serviceCategory: "service-category";
|
|
19
20
|
readonly serviceLocations: "service-locations";
|
|
@@ -340,6 +341,72 @@ export interface DurationInMinutesProps extends Omit<React.HTMLAttributes<HTMLEl
|
|
|
340
341
|
* ```
|
|
341
342
|
*/
|
|
342
343
|
export declare const DurationInMinutes: React.ForwardRefExoticComponent<DurationInMinutesProps & React.RefAttributes<HTMLElement>>;
|
|
344
|
+
/**
|
|
345
|
+
* Props for Service DurationRange component
|
|
346
|
+
*/
|
|
347
|
+
export interface DurationRangeProps extends Omit<React.HTMLAttributes<HTMLElement>, 'children'> {
|
|
348
|
+
asChild?: boolean;
|
|
349
|
+
children?: AsChildChildren<{
|
|
350
|
+
range: DurationRangeData;
|
|
351
|
+
}>;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Provides the service's supported session duration range as raw SDK data.
|
|
355
|
+
* Renders nothing when the service has fewer than two distinct supported
|
|
356
|
+
* durations — use {@link DurationInMinutes} for that case.
|
|
357
|
+
*
|
|
358
|
+
* The component is intentionally UI-agnostic: it does not pick formatting,
|
|
359
|
+
* units, or labels for you. The default render outputs only the raw
|
|
360
|
+
* `min - max` numbers (no unit text). Consumers wanting unit-aware UI use
|
|
361
|
+
* `asChild` with a custom render and narrow on the SDK `range` payload
|
|
362
|
+
* (`range.hourOptions` / `range.dayOptions` / `range.unitType`, or any
|
|
363
|
+
* other unit configuration the SDK adds in the future).
|
|
364
|
+
*
|
|
365
|
+
* @component
|
|
366
|
+
* @example
|
|
367
|
+
* ```tsx
|
|
368
|
+
* // Default usage - displays raw min/max, e.g. "120 - 540" or "2 - 5"
|
|
369
|
+
* <Service.DurationRange className="text-base text-secondary-foreground" />
|
|
370
|
+
* ```
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```tsx
|
|
374
|
+
* // asChild with primitive element
|
|
375
|
+
* <Service.DurationRange asChild>
|
|
376
|
+
* <span className="font-semibold" />
|
|
377
|
+
* </Service.DurationRange>
|
|
378
|
+
* ```
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* ```tsx
|
|
382
|
+
* // asChild with custom component - narrow on the SDK range payload to
|
|
383
|
+
* // decide unit-specific formatting.
|
|
384
|
+
* <Service.DurationRange asChild>
|
|
385
|
+
* {React.forwardRef(({ range, ...props }, ref) => {
|
|
386
|
+
* if (range.hourOptions) {
|
|
387
|
+
* const { minDurationInMinutes: min, maxDurationInMinutes: max } =
|
|
388
|
+
* range.hourOptions;
|
|
389
|
+
* return (
|
|
390
|
+
* <span ref={ref} {...props}>
|
|
391
|
+
* {min}-{max} min
|
|
392
|
+
* </span>
|
|
393
|
+
* );
|
|
394
|
+
* }
|
|
395
|
+
* if (range.dayOptions) {
|
|
396
|
+
* const { minDurationInDays: min, maxDurationInDays: max } =
|
|
397
|
+
* range.dayOptions;
|
|
398
|
+
* return (
|
|
399
|
+
* <span ref={ref} {...props}>
|
|
400
|
+
* {min}-{max} days
|
|
401
|
+
* </span>
|
|
402
|
+
* );
|
|
403
|
+
* }
|
|
404
|
+
* return <span ref={ref} {...props} />;
|
|
405
|
+
* })}
|
|
406
|
+
* </Service.DurationRange>
|
|
407
|
+
* ```
|
|
408
|
+
*/
|
|
409
|
+
export declare const DurationRange: React.ForwardRefExoticComponent<DurationRangeProps & React.RefAttributes<HTMLElement>>;
|
|
343
410
|
/**
|
|
344
411
|
* Props for Service Type component
|
|
345
412
|
*/
|
|
@@ -9,7 +9,7 @@ import * as CoreServiceMediaGallery from '../core/service/ServiceMediaGallery.js
|
|
|
9
9
|
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
10
10
|
import { Money } from '@wix/headless-components/react';
|
|
11
11
|
import { MediaGallery } from '@wix/headless-media/react';
|
|
12
|
-
import { RateType, } from '@wix/auto_sdk_bookings_services';
|
|
12
|
+
import { RateType, UnitType, } from '@wix/auto_sdk_bookings_services';
|
|
13
13
|
import * as LocationList from '../location/LocationList.js';
|
|
14
14
|
// Note: Location components are used inside LocationList.LocationRepeater
|
|
15
15
|
// Users should import { Location } from '@wix/headless-bookings/react' for Location.Name, Location.Address, etc.
|
|
@@ -24,6 +24,7 @@ export const TestIds = {
|
|
|
24
24
|
servicePrice: 'service-price',
|
|
25
25
|
serviceTagline: 'service-tagline',
|
|
26
26
|
serviceDurationInMinutes: 'service-duration-in-minutes',
|
|
27
|
+
serviceDurationRange: 'service-duration-range',
|
|
27
28
|
serviceType: 'service-type',
|
|
28
29
|
serviceCategory: 'service-category',
|
|
29
30
|
serviceLocations: 'service-locations',
|
|
@@ -302,6 +303,85 @@ export const DurationInMinutes = React.forwardRef((props, ref) => {
|
|
|
302
303
|
} }));
|
|
303
304
|
});
|
|
304
305
|
DurationInMinutes.displayName = 'Service.DurationInMinutes';
|
|
306
|
+
/**
|
|
307
|
+
* Provides the service's supported session duration range as raw SDK data.
|
|
308
|
+
* Renders nothing when the service has fewer than two distinct supported
|
|
309
|
+
* durations — use {@link DurationInMinutes} for that case.
|
|
310
|
+
*
|
|
311
|
+
* The component is intentionally UI-agnostic: it does not pick formatting,
|
|
312
|
+
* units, or labels for you. The default render outputs only the raw
|
|
313
|
+
* `min - max` numbers (no unit text). Consumers wanting unit-aware UI use
|
|
314
|
+
* `asChild` with a custom render and narrow on the SDK `range` payload
|
|
315
|
+
* (`range.hourOptions` / `range.dayOptions` / `range.unitType`, or any
|
|
316
|
+
* other unit configuration the SDK adds in the future).
|
|
317
|
+
*
|
|
318
|
+
* @component
|
|
319
|
+
* @example
|
|
320
|
+
* ```tsx
|
|
321
|
+
* // Default usage - displays raw min/max, e.g. "120 - 540" or "2 - 5"
|
|
322
|
+
* <Service.DurationRange className="text-base text-secondary-foreground" />
|
|
323
|
+
* ```
|
|
324
|
+
*
|
|
325
|
+
* @example
|
|
326
|
+
* ```tsx
|
|
327
|
+
* // asChild with primitive element
|
|
328
|
+
* <Service.DurationRange asChild>
|
|
329
|
+
* <span className="font-semibold" />
|
|
330
|
+
* </Service.DurationRange>
|
|
331
|
+
* ```
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* ```tsx
|
|
335
|
+
* // asChild with custom component - narrow on the SDK range payload to
|
|
336
|
+
* // decide unit-specific formatting.
|
|
337
|
+
* <Service.DurationRange asChild>
|
|
338
|
+
* {React.forwardRef(({ range, ...props }, ref) => {
|
|
339
|
+
* if (range.hourOptions) {
|
|
340
|
+
* const { minDurationInMinutes: min, maxDurationInMinutes: max } =
|
|
341
|
+
* range.hourOptions;
|
|
342
|
+
* return (
|
|
343
|
+
* <span ref={ref} {...props}>
|
|
344
|
+
* {min}-{max} min
|
|
345
|
+
* </span>
|
|
346
|
+
* );
|
|
347
|
+
* }
|
|
348
|
+
* if (range.dayOptions) {
|
|
349
|
+
* const { minDurationInDays: min, maxDurationInDays: max } =
|
|
350
|
+
* range.dayOptions;
|
|
351
|
+
* return (
|
|
352
|
+
* <span ref={ref} {...props}>
|
|
353
|
+
* {min}-{max} days
|
|
354
|
+
* </span>
|
|
355
|
+
* );
|
|
356
|
+
* }
|
|
357
|
+
* return <span ref={ref} {...props} />;
|
|
358
|
+
* })}
|
|
359
|
+
* </Service.DurationRange>
|
|
360
|
+
* ```
|
|
361
|
+
*/
|
|
362
|
+
export const DurationRange = React.forwardRef((props, ref) => {
|
|
363
|
+
const { asChild, children, ...rest } = props;
|
|
364
|
+
return (_jsx(CoreService.Info, { children: ({ durationRange }) => {
|
|
365
|
+
if (!durationRange)
|
|
366
|
+
return null;
|
|
367
|
+
// When `unitType` is missing or unrecognised, no default content is
|
|
368
|
+
// rendered — consumers can still read the raw `range` via asChild.
|
|
369
|
+
const { unitType, hourOptions, dayOptions } = durationRange;
|
|
370
|
+
let min;
|
|
371
|
+
let max;
|
|
372
|
+
if (unitType === UnitType.HOUR) {
|
|
373
|
+
min = hourOptions?.minDurationInMinutes;
|
|
374
|
+
max = hourOptions?.maxDurationInMinutes;
|
|
375
|
+
}
|
|
376
|
+
else if (unitType === UnitType.DAY) {
|
|
377
|
+
min = dayOptions?.minDurationInDays;
|
|
378
|
+
max = dayOptions?.maxDurationInDays;
|
|
379
|
+
}
|
|
380
|
+
const hasRange = min != null && max != null;
|
|
381
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, ...rest, "data-testid": TestIds.serviceDurationRange, customElement: children, customElementProps: { range: durationRange }, children: hasRange ? _jsx("span", { children: `${min} - ${max}` }) : null }));
|
|
382
|
+
} }));
|
|
383
|
+
});
|
|
384
|
+
DurationRange.displayName = 'Service.DurationRange';
|
|
305
385
|
/**
|
|
306
386
|
* Displays the service type (APPOINTMENT, CLASS, COURSE, etc.) with customizable rendering.
|
|
307
387
|
*
|
|
@@ -4,7 +4,7 @@
|
|
|
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 { Service,
|
|
7
|
+
import type { Service, V2Location as ServiceLocationType } from '@wix/auto_sdk_bookings_services';
|
|
8
8
|
import type { Resource, EventInfo, Location as TimeSlotLocationType } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
9
9
|
import type { FormValues } from '@wix/forms/components';
|
|
10
10
|
import type { BookResult } from './book-action/types.js';
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @module Services/LocationList/Definition
|
|
6
6
|
*/
|
|
7
7
|
import type { Signal, ReadOnlySignal } from '@wix/services-definitions/core-services/signals';
|
|
8
|
-
import { LocationType, type Service } from '@wix/auto_sdk_bookings_services';
|
|
8
|
+
import { LocationTypeEnumLocationType as LocationType, type Service } from '@wix/auto_sdk_bookings_services';
|
|
9
9
|
/**
|
|
10
10
|
* Location type from the SDK
|
|
11
11
|
* Represents a service location (BUSINESS, CUSTOM, or CUSTOMER type)
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @module Services/LocationList/Definition
|
|
6
6
|
*/
|
|
7
7
|
import { defineService } from '@wix/services-definitions';
|
|
8
|
-
import { LocationType } from '@wix/auto_sdk_bookings_services';
|
|
8
|
+
import { LocationTypeEnumLocationType as LocationType, } from '@wix/auto_sdk_bookings_services';
|
|
9
9
|
// ============================================================================
|
|
10
10
|
// Service Definition
|
|
11
11
|
// ============================================================================
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { implementService } from '@wix/services-definitions';
|
|
8
8
|
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
9
|
-
import { LocationType } from '@wix/auto_sdk_bookings_services';
|
|
9
|
+
import { LocationTypeEnumLocationType as LocationType } from '@wix/auto_sdk_bookings_services';
|
|
10
10
|
import { LocationListServiceDefinition, } from './location-list.def.js';
|
|
11
11
|
import { BookingServiceDefinition } from '../booking/booking.js';
|
|
12
12
|
import { queryLocations } from '../../api/query-locations/index.js';
|
|
@@ -48,6 +48,12 @@ export interface PricingServiceSelection {
|
|
|
48
48
|
service: Service;
|
|
49
49
|
/** Optional line item ID. If not provided, one will be generated. */
|
|
50
50
|
lineItemId?: string;
|
|
51
|
+
/** Local start date of the selected slot in ISO-8601 format (e.g. "2024-01-30T13:30:00"). */
|
|
52
|
+
localStartDate?: string;
|
|
53
|
+
/** Local end date of the selected slot in ISO-8601 format (e.g. "2024-01-30T14:30:00"). */
|
|
54
|
+
localEndDate?: string;
|
|
55
|
+
/** IANA time zone identifier for the selected slot (e.g. "America/New_York"). */
|
|
56
|
+
timeZone?: string;
|
|
51
57
|
}
|
|
52
58
|
/**
|
|
53
59
|
* Public config for PaymentService (SSR mode only):
|