@wix/headless-bookings 1.0.0 → 1.0.1

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.
Files changed (33) hide show
  1. package/cjs/dist/__mocks__/booking/booking-mocks.d.ts +1 -1
  2. package/cjs/dist/__mocks__/services/services-mocks.d.ts +23 -0
  3. package/cjs/dist/__mocks__/services/services-mocks.js +65 -1
  4. package/cjs/dist/api/query-services/index.js +2 -2
  5. package/cjs/dist/react/core/booking/Booking.d.ts +1 -1
  6. package/cjs/dist/react/core/booking/Booking.js +14 -5
  7. package/cjs/dist/react/core/location/Location.d.ts +1 -1
  8. package/cjs/dist/react/core/location/Location.js +5 -5
  9. package/cjs/dist/react/core/service/Service.d.ts +10 -1
  10. package/cjs/dist/react/core/service/Service.js +5 -4
  11. package/cjs/dist/react/service/Service.d.ts +68 -1
  12. package/cjs/dist/react/service/Service.js +81 -1
  13. package/cjs/dist/services/booking/booking.d.ts +1 -1
  14. package/cjs/dist/services/location-list/location-list.def.d.ts +1 -1
  15. package/cjs/dist/services/location-list/location-list.def.js +1 -1
  16. package/cjs/dist/services/location-list/location-list.js +7 -7
  17. package/dist/__mocks__/booking/booking-mocks.d.ts +1 -1
  18. package/dist/__mocks__/services/services-mocks.d.ts +23 -0
  19. package/dist/__mocks__/services/services-mocks.js +64 -0
  20. package/dist/api/query-services/index.js +1 -1
  21. package/dist/react/core/booking/Booking.d.ts +1 -1
  22. package/dist/react/core/booking/Booking.js +14 -5
  23. package/dist/react/core/location/Location.d.ts +1 -1
  24. package/dist/react/core/location/Location.js +1 -1
  25. package/dist/react/core/service/Service.d.ts +10 -1
  26. package/dist/react/core/service/Service.js +5 -4
  27. package/dist/react/service/Service.d.ts +68 -1
  28. package/dist/react/service/Service.js +81 -1
  29. package/dist/services/booking/booking.d.ts +1 -1
  30. package/dist/services/location-list/location-list.def.d.ts +1 -1
  31. package/dist/services/location-list/location-list.def.js +1 -1
  32. package/dist/services/location-list/location-list.js +1 -1
  33. package/package.json +4 -3
@@ -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
  */
@@ -3,7 +3,7 @@
3
3
  * Shared mock data for booking service tests
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.mockServiceInPerson = exports.mockServiceWithDeposit = exports.mockSingleStaffMemberListConfig = exports.mockEmptyStaffMemberListConfig = exports.mockStaffMemberListConfig = exports.mockStaffMembers = exports.mockStaffMemberNoName = exports.mockStaffMemberMinimal = exports.mockStaffMember2 = exports.mockStaffMember = exports.mockServiceListConfigWithCategories = exports.mockCategories = exports.mockServiceConfig = exports.mockEmptyServiceListConfig = exports.mockServiceListConfigWithMore = exports.mockServiceListConfig = exports.mockPagingMetadataEmpty = exports.mockPagingMetadataWithMore = exports.mockPagingMetadata = exports.mockServices = exports.mockServiceMinimal = exports.mockServiceCourse = exports.mockServiceClass = exports.mockServiceNoFee = exports.mockServiceCustomPrice = exports.mockServiceVariedPrice = exports.mockService = void 0;
6
+ exports.mockServiceInPerson = exports.mockServiceWithDeposit = exports.mockSingleStaffMemberListConfig = exports.mockEmptyStaffMemberListConfig = exports.mockStaffMemberListConfig = exports.mockStaffMembers = exports.mockStaffMemberNoName = exports.mockStaffMemberMinimal = exports.mockStaffMember2 = exports.mockStaffMember = exports.mockServiceListConfigWithCategories = exports.mockCategories = exports.mockServiceConfig = exports.mockEmptyServiceListConfig = exports.mockServiceListConfigWithMore = exports.mockServiceListConfig = exports.mockPagingMetadataEmpty = exports.mockPagingMetadataWithMore = exports.mockPagingMetadata = exports.mockServices = exports.mockServiceDayRange = exports.mockServiceHourRange = exports.mockServiceFixedDuration = exports.mockServiceMinimal = exports.mockServiceCourse = exports.mockServiceClass = exports.mockServiceNoFee = exports.mockServiceCustomPrice = exports.mockServiceVariedPrice = exports.mockService = void 0;
7
7
  exports.createLargeServiceList = createLargeServiceList;
8
8
  exports.createLargeStaffMemberList = createLargeStaffMemberList;
9
9
  const auto_sdk_bookings_services_1 = require("@wix/auto_sdk_bookings_services");
@@ -175,6 +175,70 @@ exports.mockServiceMinimal = {
175
175
  name: 'Minimal Service',
176
176
  description: '',
177
177
  };
178
+ /**
179
+ * Mock service driving the fixed-duration path: a single value in
180
+ * `sessionDurations`, no `durationRange`. Drives `Service.DurationInMinutes`;
181
+ * `Service.DurationRange` renders nothing for this shape.
182
+ *
183
+ * `mockService` already carries this shape — this is a renamed copy for
184
+ * tests/examples that want to name the case they're exercising.
185
+ */
186
+ exports.mockServiceFixedDuration = {
187
+ ...exports.mockService,
188
+ _id: 'test-service-fixed-duration',
189
+ name: 'Fixed Duration Service',
190
+ schedule: {
191
+ availabilityConstraints: {
192
+ sessionDurations: [60],
193
+ },
194
+ },
195
+ };
196
+ /**
197
+ * Mock service driving the HOUR-unit DurationRange path. Mirrors the server
198
+ * payload shape: empty `sessionDurations`, range pre-computed at
199
+ * `availabilityConstraints.durationRange`. `durationRange` is not yet in the
200
+ * SDK's `AvailabilityConstraints` typing (runtime is ahead of types), so the
201
+ * service object is cast — matches the read-side cast in
202
+ * `core/service/Service.tsx`.
203
+ */
204
+ exports.mockServiceHourRange = {
205
+ ...exports.mockService,
206
+ _id: 'test-service-hour-range',
207
+ name: 'Hourly Range Service',
208
+ schedule: {
209
+ availabilityConstraints: {
210
+ sessionDurations: [],
211
+ durationRange: {
212
+ unitType: 'HOUR',
213
+ hourOptions: {
214
+ minDurationInMinutes: 120,
215
+ maxDurationInMinutes: 540,
216
+ },
217
+ },
218
+ },
219
+ },
220
+ };
221
+ /**
222
+ * Mock service driving the DAY-unit DurationRange path. Same server shape as
223
+ * {@link mockServiceHourRange}.
224
+ */
225
+ exports.mockServiceDayRange = {
226
+ ...exports.mockService,
227
+ _id: 'test-service-day-range',
228
+ name: 'Daily Range Service',
229
+ schedule: {
230
+ availabilityConstraints: {
231
+ sessionDurations: [],
232
+ durationRange: {
233
+ unitType: 'DAY',
234
+ dayOptions: {
235
+ minDurationInDays: 2,
236
+ maxDurationInDays: 5,
237
+ },
238
+ },
239
+ },
240
+ },
241
+ };
178
242
  /**
179
243
  * Array of mock services for list tests
180
244
  */
@@ -143,10 +143,10 @@ function convertPlatformFilterToApiFilter(platformFilter) {
143
143
  const businessLocationIds = [];
144
144
  for (const id of locationIds) {
145
145
  if (id === exports.SYNTHETIC_CUSTOM_ID) {
146
- syntheticTypes.push(auto_sdk_bookings_services_1.LocationType.CUSTOM);
146
+ syntheticTypes.push(auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOM);
147
147
  }
148
148
  else if (id === exports.SYNTHETIC_CUSTOMER_ID) {
149
- syntheticTypes.push(auto_sdk_bookings_services_1.LocationType.CUSTOMER);
149
+ syntheticTypes.push(auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOMER);
150
150
  }
151
151
  else {
152
152
  businessLocationIds.push(id);
@@ -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 Location as ServiceLocationType } from '@wix/auto_sdk_bookings_services';
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
@@ -65,7 +65,16 @@ function Root(props) {
65
65
  function mapTimeSlotLocationToServiceLocation(timeSlotLocation) {
66
66
  // TimeSlot location has flat name/formattedAddress at top level
67
67
  // Convert to nested business/custom structure that CoreLocation expects
68
- const locationType = timeSlotLocation.locationType;
68
+ const isCustomer = timeSlotLocation.locationType === auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOMER;
69
+ const isCustom = timeSlotLocation.locationType === auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOM;
70
+ // The two SDKs share BUSINESS/CUSTOM/CUSTOMER but the time-slots enum also
71
+ // exposes UNKNOWN_LOCATION_TYPE, which V2Location.type does not accept.
72
+ // Default to BUSINESS for any unrecognized value.
73
+ const type = isCustomer
74
+ ? auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOMER
75
+ : isCustom
76
+ ? auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOM
77
+ : auto_sdk_bookings_services_1.LocationTypeEnumLocationType.BUSINESS;
69
78
  const location = {
70
79
  _id: timeSlotLocation._id ?? undefined,
71
80
  name: timeSlotLocation.name ?? undefined,
@@ -77,10 +86,10 @@ function mapTimeSlotLocationToServiceLocation(timeSlotLocation) {
77
86
  };
78
87
  return {
79
88
  _id: timeSlotLocation._id ?? undefined,
80
- type: locationType,
81
- ...(locationType === auto_sdk_bookings_services_1.LocationType.CUSTOMER
89
+ type,
90
+ ...(isCustomer
82
91
  ? null
83
- : locationType === auto_sdk_bookings_services_1.LocationType.CUSTOM
92
+ : isCustom
84
93
  ? { custom: location }
85
94
  : { business: location }),
86
95
  };
@@ -91,7 +100,7 @@ function mapTimeSlotLocationToServiceLocation(timeSlotLocation) {
91
100
  * 2. If not set, fall back to the first service selection's slot location
92
101
  */
93
102
  function resolveLocation(bookingLocation, serviceSelections) {
94
- if (bookingLocation && bookingLocation.type === auto_sdk_bookings_services_1.LocationType.BUSINESS) {
103
+ if (bookingLocation && bookingLocation.type === auto_sdk_bookings_services_1.LocationTypeEnumLocationType.BUSINESS) {
95
104
  return bookingLocation;
96
105
  }
97
106
  // Fallback to first slot's location
@@ -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
  /**
@@ -90,7 +90,7 @@ function hasLocationData(location) {
90
90
  */
91
91
  function parseLocationAddress(location) {
92
92
  // Handle customer location - return null, let consumer handle
93
- if (location.type !== auto_sdk_bookings_services_1.LocationType.BUSINESS) {
93
+ if (location.type !== auto_sdk_bookings_services_1.LocationTypeEnumLocationType.BUSINESS) {
94
94
  return null;
95
95
  }
96
96
  // Get the common address from the appropriate location type
@@ -123,7 +123,7 @@ function parseLocationAddress(location) {
123
123
  * Get location type from location data
124
124
  */
125
125
  function getLocationType(location) {
126
- return location.type || auto_sdk_bookings_services_1.LocationType.BUSINESS;
126
+ return location.type || auto_sdk_bookings_services_1.LocationTypeEnumLocationType.BUSINESS;
127
127
  }
128
128
  /**
129
129
  * Computes LocationRenderProps from location with label fallbacks
@@ -132,7 +132,7 @@ function computeLocationRenderProps(rawLocation, labels) {
132
132
  // Handle no location
133
133
  if (!rawLocation) {
134
134
  return {
135
- locationType: auto_sdk_bookings_services_1.LocationType.BUSINESS,
135
+ locationType: auto_sdk_bookings_services_1.LocationTypeEnumLocationType.BUSINESS,
136
136
  address: null,
137
137
  name: undefined,
138
138
  locationId: undefined,
@@ -146,8 +146,8 @@ function computeLocationRenderProps(rawLocation, labels) {
146
146
  }
147
147
  const locationType = getLocationType(rawLocation);
148
148
  const hasData = hasLocationData(rawLocation);
149
- const isCustomLocation = locationType === auto_sdk_bookings_services_1.LocationType.CUSTOM;
150
- const isCustomerLocation = locationType === auto_sdk_bookings_services_1.LocationType.CUSTOMER;
149
+ const isCustomLocation = locationType === auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOM;
150
+ const isCustomerLocation = locationType === auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOMER;
151
151
  // Compute name with fallback chain:
152
152
  // 1. business.name
153
153
  // 2. custom.address.addressLine
@@ -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;
@@ -96,9 +96,9 @@ function Info(props) {
96
96
  currency,
97
97
  };
98
98
  }
99
- // Extract duration from schedule.availabilityConstraints.sessionDurations
100
- // Use the first duration if multiple are available
101
- const duration = service.schedule?.availabilityConstraints?.sessionDurations?.[0];
99
+ const constraints = service.schedule?.availabilityConstraints;
100
+ const duration = constraints?.sessionDurations?.[0];
101
+ const durationRange = constraints?.durationRange;
102
102
  // Get staff members from staffMemberDetails.staffMembers
103
103
  // (available when using conditionalFields: ['STAFF_MEMBER_DETAILS'] in queryServices)
104
104
  const staff = service.staffMembers || [];
@@ -128,7 +128,8 @@ function Info(props) {
128
128
  name: service.name || '',
129
129
  description: service.description || '',
130
130
  tagline: service.tagLine || undefined,
131
- duration: duration,
131
+ duration,
132
+ durationRange,
132
133
  type: service.type,
133
134
  category: service.category
134
135
  ? {
@@ -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
  */
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.CoverMedia = exports.MainMedia = exports.StaffMembers = exports.Locations = exports.AvailableOnline = exports.DefaultCapacity = exports.Schedule = exports.ScheduleSessionDuration = exports.ScheduleLastSessionEnd = exports.ScheduleFirstSessionStart = exports.Policy = exports.PolicyMaxParticipantsPerBooking = exports.PolicyBookAfterStartEnabled = exports.PolicyWaitlistCapacity = exports.PolicyLatestRescheduleInMinutes = exports.PolicyEarliestBookingInMinutes = exports.PolicyLatestBookingInMinutes = exports.PolicyLatestCancellationInMinutes = exports.Actions = exports.Raw = exports.StaffMemberRepeater = exports.StaffMembersList = exports.LocationRepeater = exports.LocationsList = exports.Category = exports.Type = exports.DurationInMinutes = exports.Tagline = exports.Price = exports.Description = exports.Name = exports.Root = exports.TestIds = void 0;
39
+ exports.CoverMedia = exports.MainMedia = exports.StaffMembers = exports.Locations = exports.AvailableOnline = exports.DefaultCapacity = exports.Schedule = exports.ScheduleSessionDuration = exports.ScheduleLastSessionEnd = exports.ScheduleFirstSessionStart = exports.Policy = exports.PolicyMaxParticipantsPerBooking = exports.PolicyBookAfterStartEnabled = exports.PolicyWaitlistCapacity = exports.PolicyLatestRescheduleInMinutes = exports.PolicyEarliestBookingInMinutes = exports.PolicyLatestBookingInMinutes = exports.PolicyLatestCancellationInMinutes = exports.Actions = exports.Raw = exports.StaffMemberRepeater = exports.StaffMembersList = exports.LocationRepeater = exports.LocationsList = exports.Category = exports.Type = exports.DurationRange = exports.DurationInMinutes = exports.Tagline = exports.Price = exports.Description = exports.Name = exports.Root = exports.TestIds = void 0;
40
40
  const jsx_runtime_1 = require("react/jsx-runtime");
41
41
  /**
42
42
  * Service - High-level component for displaying service information
@@ -63,6 +63,7 @@ exports.TestIds = {
63
63
  servicePrice: 'service-price',
64
64
  serviceTagline: 'service-tagline',
65
65
  serviceDurationInMinutes: 'service-duration-in-minutes',
66
+ serviceDurationRange: 'service-duration-range',
66
67
  serviceType: 'service-type',
67
68
  serviceCategory: 'service-category',
68
69
  serviceLocations: 'service-locations',
@@ -341,6 +342,85 @@ exports.DurationInMinutes = react_1.default.forwardRef((props, ref) => {
341
342
  } }));
342
343
  });
343
344
  exports.DurationInMinutes.displayName = 'Service.DurationInMinutes';
345
+ /**
346
+ * Provides the service's supported session duration range as raw SDK data.
347
+ * Renders nothing when the service has fewer than two distinct supported
348
+ * durations — use {@link DurationInMinutes} for that case.
349
+ *
350
+ * The component is intentionally UI-agnostic: it does not pick formatting,
351
+ * units, or labels for you. The default render outputs only the raw
352
+ * `min - max` numbers (no unit text). Consumers wanting unit-aware UI use
353
+ * `asChild` with a custom render and narrow on the SDK `range` payload
354
+ * (`range.hourOptions` / `range.dayOptions` / `range.unitType`, or any
355
+ * other unit configuration the SDK adds in the future).
356
+ *
357
+ * @component
358
+ * @example
359
+ * ```tsx
360
+ * // Default usage - displays raw min/max, e.g. "120 - 540" or "2 - 5"
361
+ * <Service.DurationRange className="text-base text-secondary-foreground" />
362
+ * ```
363
+ *
364
+ * @example
365
+ * ```tsx
366
+ * // asChild with primitive element
367
+ * <Service.DurationRange asChild>
368
+ * <span className="font-semibold" />
369
+ * </Service.DurationRange>
370
+ * ```
371
+ *
372
+ * @example
373
+ * ```tsx
374
+ * // asChild with custom component - narrow on the SDK range payload to
375
+ * // decide unit-specific formatting.
376
+ * <Service.DurationRange asChild>
377
+ * {React.forwardRef(({ range, ...props }, ref) => {
378
+ * if (range.hourOptions) {
379
+ * const { minDurationInMinutes: min, maxDurationInMinutes: max } =
380
+ * range.hourOptions;
381
+ * return (
382
+ * <span ref={ref} {...props}>
383
+ * {min}-{max} min
384
+ * </span>
385
+ * );
386
+ * }
387
+ * if (range.dayOptions) {
388
+ * const { minDurationInDays: min, maxDurationInDays: max } =
389
+ * range.dayOptions;
390
+ * return (
391
+ * <span ref={ref} {...props}>
392
+ * {min}-{max} days
393
+ * </span>
394
+ * );
395
+ * }
396
+ * return <span ref={ref} {...props} />;
397
+ * })}
398
+ * </Service.DurationRange>
399
+ * ```
400
+ */
401
+ exports.DurationRange = react_1.default.forwardRef((props, ref) => {
402
+ const { asChild, children, ...rest } = props;
403
+ return ((0, jsx_runtime_1.jsx)(CoreService.Info, { children: ({ durationRange }) => {
404
+ if (!durationRange)
405
+ return null;
406
+ // When `unitType` is missing or unrecognised, no default content is
407
+ // rendered — consumers can still read the raw `range` via asChild.
408
+ const { unitType, hourOptions, dayOptions } = durationRange;
409
+ let min;
410
+ let max;
411
+ if (unitType === auto_sdk_bookings_services_1.UnitType.HOUR) {
412
+ min = hourOptions?.minDurationInMinutes;
413
+ max = hourOptions?.maxDurationInMinutes;
414
+ }
415
+ else if (unitType === auto_sdk_bookings_services_1.UnitType.DAY) {
416
+ min = dayOptions?.minDurationInDays;
417
+ max = dayOptions?.maxDurationInDays;
418
+ }
419
+ const hasRange = min != null && max != null;
420
+ return ((0, jsx_runtime_1.jsx)(react_2.AsChildSlot, { ref: ref, asChild: asChild, ...rest, "data-testid": exports.TestIds.serviceDurationRange, customElement: children, customElementProps: { range: durationRange }, children: hasRange ? (0, jsx_runtime_1.jsx)("span", { children: `${min} - ${max}` }) : null }));
421
+ } }));
422
+ });
423
+ exports.DurationRange.displayName = 'Service.DurationRange';
344
424
  /**
345
425
  * Displays the service type (APPOINTMENT, CLASS, COURSE, etc.) with customizable rendering.
346
426
  *
@@ -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, Location as ServiceLocationType } from '@wix/auto_sdk_bookings_services';
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)
@@ -9,7 +9,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.LocationType = exports.LocationListServiceDefinition = void 0;
10
10
  const services_definitions_1 = require("@wix/services-definitions");
11
11
  const auto_sdk_bookings_services_1 = require("@wix/auto_sdk_bookings_services");
12
- Object.defineProperty(exports, "LocationType", { enumerable: true, get: function () { return auto_sdk_bookings_services_1.LocationType; } });
12
+ Object.defineProperty(exports, "LocationType", { enumerable: true, get: function () { return auto_sdk_bookings_services_1.LocationTypeEnumLocationType; } });
13
13
  // ============================================================================
14
14
  // Service Definition
15
15
  // ============================================================================
@@ -35,13 +35,13 @@ const SYNTHETIC_CUSTOMER_ID = 'customer';
35
35
  function buildDisplayLocations(locations, hasCustomLocations, hasCustomerLocations) {
36
36
  const displayLocations = [];
37
37
  // 1. Add all BUSINESS locations directly
38
- const businessLocations = locations.filter((loc) => loc.type === auto_sdk_bookings_services_1.LocationType.BUSINESS || loc.type === undefined);
38
+ const businessLocations = locations.filter((loc) => loc.type === auto_sdk_bookings_services_1.LocationTypeEnumLocationType.BUSINESS || loc.type === undefined);
39
39
  for (const loc of businessLocations) {
40
40
  displayLocations.push(loc);
41
41
  }
42
42
  // Check for existing CUSTOM/CUSTOMER in array
43
- const customFromArray = locations.find((loc) => loc.type === auto_sdk_bookings_services_1.LocationType.CUSTOM);
44
- const customerFromArray = locations.find((loc) => loc.type === auto_sdk_bookings_services_1.LocationType.CUSTOMER);
43
+ const customFromArray = locations.find((loc) => loc.type === auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOM);
44
+ const customerFromArray = locations.find((loc) => loc.type === auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOMER);
45
45
  // 2. Add CUSTOM location (from array, or create placeholder)
46
46
  if (customFromArray) {
47
47
  displayLocations.push(customFromArray);
@@ -49,7 +49,7 @@ function buildDisplayLocations(locations, hasCustomLocations, hasCustomerLocatio
49
49
  else if (hasCustomLocations) {
50
50
  // Placeholder custom location (only from explicit flag, not array)
51
51
  const placeholderCustom = {
52
- type: auto_sdk_bookings_services_1.LocationType.CUSTOM,
52
+ type: auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOM,
53
53
  _id: SYNTHETIC_CUSTOM_ID,
54
54
  };
55
55
  displayLocations.push(placeholderCustom);
@@ -61,7 +61,7 @@ function buildDisplayLocations(locations, hasCustomLocations, hasCustomerLocatio
61
61
  else if (hasCustomerLocations) {
62
62
  // Placeholder customer location (only from explicit flag, not array)
63
63
  const placeholderCustomer = {
64
- type: auto_sdk_bookings_services_1.LocationType.CUSTOMER,
64
+ type: auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOMER,
65
65
  _id: SYNTHETIC_CUSTOMER_ID,
66
66
  };
67
67
  displayLocations.push(placeholderCustomer);
@@ -89,8 +89,8 @@ exports.LocationListService = services_definitions_1.implementService.withConfig
89
89
  // Initialize raw locations signal
90
90
  const locationsSignal = signalsService.signal(config.locations || []);
91
91
  // Auto-detect from array
92
- const hasCustomInArray = (config.locations || []).some((loc) => loc.type === auto_sdk_bookings_services_1.LocationType.CUSTOM);
93
- const hasCustomerInArray = (config.locations || []).some((loc) => loc.type === auto_sdk_bookings_services_1.LocationType.CUSTOMER);
92
+ const hasCustomInArray = (config.locations || []).some((loc) => loc.type === auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOM);
93
+ const hasCustomerInArray = (config.locations || []).some((loc) => loc.type === auto_sdk_bookings_services_1.LocationTypeEnumLocationType.CUSTOMER);
94
94
  // Final flags: explicit config OR auto-detected
95
95
  const hasCustomLocationsSignal = signalsService.computed(() => config.hasCustomLocations ?? hasCustomInArray);
96
96
  const hasCustomerLocationsSignal = signalsService.computed(() => config.hasCustomerLocations ?? hasCustomerInArray);
@@ -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 Location as ServiceLocationType } from '@wix/auto_sdk_bookings_services';
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 locationType = timeSlotLocation.locationType;
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: locationType,
69
- ...(locationType === LocationType.CUSTOMER
77
+ type,
78
+ ...(isCustomer
70
79
  ? null
71
- : locationType === LocationType.CUSTOM
80
+ : isCustom
72
81
  ? { custom: location }
73
82
  : { business: location }),
74
83
  };
@@ -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
- // Extract duration from schedule.availabilityConstraints.sessionDurations
91
- // Use the first duration if multiple are available
92
- const duration = service.schedule?.availabilityConstraints?.sessionDurations?.[0];
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: 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, Location as ServiceLocationType } from '@wix/auto_sdk_bookings_services';
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';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/headless-bookings",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -34,8 +34,9 @@
34
34
  }
35
35
  },
36
36
  "dependencies": {
37
- "@wix/auto_sdk_bookings_bookings": "^1.0.103",
37
+ "@wix/auto_sdk_bookings_bookings": "^1.0.183",
38
38
  "@wix/auto_sdk_bookings_event-time-slots": "^1.0.64",
39
+ "@wix/auto_sdk_bookings_services": "^1.0.226",
39
40
  "@wix/auto_sdk_ecom_cart-v-2": "^1.0.86",
40
41
  "@wix/forms": "^1.0.384",
41
42
  "@wix/headless-media": "0.0.25",
@@ -73,5 +74,5 @@
73
74
  "groupId": "com.wixpress.headless-components"
74
75
  }
75
76
  },
76
- "falconPackageHash": "c937e3d58e53147f0712bea70a6759a841fd018967a90028599b0895"
77
+ "falconPackageHash": "c5f3384150eba7e23d903366ac5a1fc164fc30f5172f6fc4bc2d61d8"
77
78
  }