@wix/headless-bookings 0.0.62 → 0.0.63

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 (49) hide show
  1. package/cjs/dist/__mocks__/time-slots.js +1 -0
  2. package/cjs/dist/api/index.d.ts +2 -2
  3. package/cjs/dist/api/index.js +2 -2
  4. package/cjs/dist/api/query-locations/index.d.ts +14 -0
  5. package/cjs/dist/api/query-locations/index.js +27 -0
  6. package/cjs/dist/api/query-services/index.d.ts +5 -0
  7. package/cjs/dist/api/query-services/index.js +2 -2
  8. package/cjs/dist/react/core/location/Location.d.ts +2 -0
  9. package/cjs/dist/react/core/location/Location.js +14 -1
  10. package/cjs/dist/react/core/time-slot-list/TimeSlot.js +0 -2
  11. package/cjs/dist/react/core/time-slot-list/TimeSlotList.js +11 -6
  12. package/cjs/dist/react/index.d.ts +0 -1
  13. package/cjs/dist/react/index.js +1 -1
  14. package/cjs/dist/react/location/Location.d.ts +4 -0
  15. package/cjs/dist/react/location/Location.js +20 -2
  16. package/cjs/dist/react/location/LocationList.d.ts +4 -0
  17. package/cjs/dist/react/location/LocationList.js +33 -7
  18. package/cjs/dist/react/time-slot-list/TimeSlotList.js +0 -4
  19. package/cjs/dist/services/index.d.ts +2 -1
  20. package/cjs/dist/services/index.js +2 -1
  21. package/cjs/dist/services/location-list/location-list.d.ts +1 -0
  22. package/cjs/dist/services/location-list/location-list.js +3 -2
  23. package/cjs/dist/services/time-slot-list/time-slot-list.def.d.ts +1 -0
  24. package/cjs/dist/services/time-slot-list/time-slot-list.js +2 -9
  25. package/dist/__mocks__/time-slots.js +1 -0
  26. package/dist/api/index.d.ts +2 -2
  27. package/dist/api/index.js +2 -2
  28. package/dist/api/query-locations/index.d.ts +14 -0
  29. package/dist/api/query-locations/index.js +27 -0
  30. package/dist/api/query-services/index.d.ts +5 -0
  31. package/dist/api/query-services/index.js +2 -2
  32. package/dist/react/core/location/Location.d.ts +2 -0
  33. package/dist/react/core/location/Location.js +14 -1
  34. package/dist/react/core/time-slot-list/TimeSlot.js +0 -2
  35. package/dist/react/core/time-slot-list/TimeSlotList.js +11 -6
  36. package/dist/react/index.d.ts +0 -1
  37. package/dist/react/index.js +1 -1
  38. package/dist/react/location/Location.d.ts +4 -0
  39. package/dist/react/location/Location.js +20 -2
  40. package/dist/react/location/LocationList.d.ts +4 -0
  41. package/dist/react/location/LocationList.js +33 -7
  42. package/dist/react/time-slot-list/TimeSlotList.js +0 -4
  43. package/dist/services/index.d.ts +2 -1
  44. package/dist/services/index.js +2 -1
  45. package/dist/services/location-list/location-list.d.ts +1 -0
  46. package/dist/services/location-list/location-list.js +3 -2
  47. package/dist/services/time-slot-list/time-slot-list.def.d.ts +1 -0
  48. package/dist/services/time-slot-list/time-slot-list.js +2 -9
  49. package/package.json +2 -2
@@ -112,5 +112,6 @@ export function createMockTimeSlotListService(config = {}) {
112
112
  dateRangeSignal.set({ start, end });
113
113
  }),
114
114
  },
115
+ dispose: vi.fn(),
115
116
  };
116
117
  }
@@ -4,12 +4,12 @@
4
4
  *
5
5
  * @module API
6
6
  */
7
- export { getServiceById, getServiceBySlug, queryServices, type PagingMetadata, type ServiceListFilters, type QueryServicesRequest, } from './query-services/index.js';
7
+ export { getServiceById, getServiceBySlug, queryServices, type PagingMetadata, type ServiceListFilters, type QueryServicesRequest, SYNTHETIC_CUSTOM_ID, SYNTHETIC_CUSTOMER_ID, } from './query-services/index.js';
8
8
  export { fetchAvailability } from './fetch-availability/index.js';
9
9
  export { createBooking, type CreateBookingOptions, type Booking, type CreateBookingRequest, type CreateBookingResponse, type ParticipantNotification, type ContactDetails, } from './create-booking/index.js';
10
10
  export { createCheckout, ChannelType, type CreateCheckoutRequest, type CreateCheckoutResponse, } from './create-checkout/index.js';
11
11
  export { createOrder, type CreateOrderOptions, type CreateOrderResponse, } from './create-order/index.js';
12
- export { queryLocations, type QueryLocationsResult, type LocationData, } from './query-locations/index.js';
12
+ export { queryLocations, getLocationById, type QueryLocationsResult, type LocationData, } from './query-locations/index.js';
13
13
  export { queryCategories, type QueryCategoriesResult, type Category, } from './query-categories/index.js';
14
14
  /**
15
15
  * PagingMetadata includes:
@@ -4,12 +4,12 @@
4
4
  *
5
5
  * @module API
6
6
  */
7
- export { getServiceById, getServiceBySlug, queryServices, } from './query-services/index.js';
7
+ export { getServiceById, getServiceBySlug, queryServices, SYNTHETIC_CUSTOM_ID, SYNTHETIC_CUSTOMER_ID, } from './query-services/index.js';
8
8
  export { fetchAvailability } from './fetch-availability/index.js';
9
9
  export { createBooking, } from './create-booking/index.js';
10
10
  export { createCheckout, ChannelType, } from './create-checkout/index.js';
11
11
  export { createOrder, } from './create-order/index.js';
12
- export { queryLocations, } from './query-locations/index.js';
12
+ export { queryLocations, getLocationById, } from './query-locations/index.js';
13
13
  export { queryCategories, } from './query-categories/index.js';
14
14
  /**
15
15
  * PagingMetadata includes:
@@ -36,3 +36,17 @@ export interface QueryLocationsResult {
36
36
  * ```
37
37
  */
38
38
  export declare function queryLocations(): Promise<QueryLocationsResult>;
39
+ /**
40
+ * Fetches a single location by its business location ID
41
+ * @param locationId - The business location ID (GUID)
42
+ * @returns Promise resolving to the location or null if not found
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const location = await getLocationById('12345678-1234-1234-1234-123456789012');
47
+ * if (location) {
48
+ * console.log(location.business?.name);
49
+ * }
50
+ * ```
51
+ */
52
+ export declare function getLocationById(locationId: string): Promise<LocationData | null>;
@@ -28,3 +28,30 @@ export async function queryLocations() {
28
28
  hasCustomerLocations: response.customerLocations?.exists || false,
29
29
  };
30
30
  }
31
+ /**
32
+ * Fetches a single location by its business location ID
33
+ * @param locationId - The business location ID (GUID)
34
+ * @returns Promise resolving to the location or null if not found
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * const location = await getLocationById('12345678-1234-1234-1234-123456789012');
39
+ * if (location) {
40
+ * console.log(location.business?.name);
41
+ * }
42
+ * ```
43
+ */
44
+ export async function getLocationById(locationId) {
45
+ try {
46
+ const response = await queryLocationsApi({
47
+ filter: {
48
+ businessLocationIds: [locationId],
49
+ },
50
+ });
51
+ return response.businessLocations?.locations?.[0] ?? null;
52
+ }
53
+ catch (error) {
54
+ console.error(`Failed to load location for id "${locationId}":`, error);
55
+ return null;
56
+ }
57
+ }
@@ -3,6 +3,11 @@
3
3
  * Fetches single or multiple services with pagination and sorting
4
4
  */
5
5
  import { type Service, type Paging, type Sorting } from '@wix/auto_sdk_bookings_services';
6
+ /**
7
+ * Synthetic location ID constants for non-business locations
8
+ */
9
+ export declare const SYNTHETIC_CUSTOM_ID = "custom";
10
+ export declare const SYNTHETIC_CUSTOMER_ID = "customer";
6
11
  /**
7
12
  * Paging metadata from query services response.
8
13
  * Extends the SDK's Paging type with hasNext flag to indicate if more services are available.
@@ -10,8 +10,8 @@ const BOOKING_APP_ID = '13d21c63-b5ec-5912-8397-c3a5ddb27a97';
10
10
  /**
11
11
  * Synthetic location ID constants for non-business locations
12
12
  */
13
- const SYNTHETIC_CUSTOM_ID = '__synthetic_custom__';
14
- const SYNTHETIC_CUSTOMER_ID = '__synthetic_customer__';
13
+ export const SYNTHETIC_CUSTOM_ID = 'custom';
14
+ export const SYNTHETIC_CUSTOMER_ID = 'customer';
15
15
  /**
16
16
  * Fetches a service by its ID
17
17
  * @param id - The service ID
@@ -27,6 +27,8 @@ export interface SyntheticLocation {
27
27
  synthetic: true;
28
28
  /** Optional ID for tracking (matches ServiceLocation._id) */
29
29
  _id?: string;
30
+ /** Optional name/label for the location */
31
+ name?: string;
30
32
  }
31
33
  /**
32
34
  * Union type - location prop accepts Service or Synthetic location
@@ -106,10 +106,23 @@ function computeLocationRenderProps(rawLocation) {
106
106
  if (isSyntheticLocation(rawLocation)) {
107
107
  const syntheticLoc = rawLocation;
108
108
  const locationType = syntheticLoc.locationType;
109
+ // Use provided name or default based on location type
110
+ let name;
111
+ if (syntheticLoc.name) {
112
+ name = syntheticLoc.name;
113
+ }
114
+ else {
115
+ name =
116
+ locationType === LocationType.CUSTOM
117
+ ? 'Custom Locations'
118
+ : locationType === LocationType.CUSTOMER
119
+ ? "Client's Place"
120
+ : undefined;
121
+ }
109
122
  return {
110
123
  locationType,
111
124
  address: null,
112
- name: undefined,
125
+ name,
113
126
  locationId: syntheticLoc._id,
114
127
  isCustomerLocation: locationType === LocationType.CUSTOMER,
115
128
  isCustomLocation: locationType === LocationType.CUSTOM,
@@ -82,7 +82,6 @@ export function Info(props) {
82
82
  const endDate = new Date(timeSlot.localEndDate);
83
83
  const locationName = timeSlot.location?.name ?? '';
84
84
  const bookable = timeSlot.bookable ?? false;
85
- // Calculate duration from start and end dates
86
85
  const durationInMinutes = Math.round((endDate.getTime() - startDate.getTime()) / (1000 * 60));
87
86
  return props.children({
88
87
  startDate,
@@ -166,7 +165,6 @@ export function StaffMembers(props) {
166
165
  const bookingService = useService(BookingServiceDefinition);
167
166
  const selectedStaffMemberId = bookingService.serviceSelections.get()[0]?.timeSlot?.resources?.[0]?._id;
168
167
  const staffMembers = timeSlot.availableResources[0].resources;
169
- // Return null if only 1 staff member - nothing to choose from
170
168
  if (staffMembers.length <= 1) {
171
169
  return null;
172
170
  }
@@ -1,4 +1,9 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * Core TimeSlotList Components
4
+ * Provides low-level access to TimeSlotListService via render props
5
+ */
6
+ import React from 'react';
2
7
  import { useService, WixServices } from '@wix/services-manager-react';
3
8
  import { createServicesMap } from '@wix/services-manager';
4
9
  import { TimeSlotListServiceDefinition, TimeSlotListService, } from '../../../services/time-slot-list/index.js';
@@ -28,18 +33,20 @@ export function Root(props) {
28
33
  * Internal component that wraps navigateToBookingForm to handle optional parameters
29
34
  */
30
35
  function RootContent({ navigateToBookingForm: providedNavigateToBookingForm, children, }) {
31
- // Get BookingService to use when timeSlot/service are not provided
36
+ const timeSlotListService = useService(TimeSlotListServiceDefinition);
37
+ React.useEffect(() => {
38
+ return () => {
39
+ timeSlotListService.dispose();
40
+ };
41
+ }, [timeSlotListService]);
32
42
  let bookingService = null;
33
43
  try {
34
44
  bookingService = useService(BookingServiceDefinition);
35
45
  }
36
46
  catch {
37
- // BookingService not available - that's ok, user must provide timeSlot/service
38
47
  bookingService = null;
39
48
  }
40
- // Wrap the provided navigateToBookingForm to handle optional parameters
41
49
  const navigateToBookingForm = async ({ timeSlot, service, }) => {
42
- // If timeSlot or service are not provided, try to get them from BookingService
43
50
  let resolvedTimeSlot = timeSlot;
44
51
  let resolvedService = service;
45
52
  if ((!resolvedTimeSlot || !resolvedService) && bookingService) {
@@ -52,14 +59,12 @@ function RootContent({ navigateToBookingForm: providedNavigateToBookingForm, chi
52
59
  }
53
60
  }
54
61
  }
55
- // Validate that we have both timeSlot and service
56
62
  if (!resolvedTimeSlot) {
57
63
  throw new Error('timeSlot is required. Either provide it as a parameter or ensure BookingService has a service selection with a timeSlot.');
58
64
  }
59
65
  if (!resolvedService) {
60
66
  throw new Error('service is required. Either provide it as a parameter or ensure BookingService has a service selection.');
61
67
  }
62
- // Call the provided function with resolved values
63
68
  return providedNavigateToBookingForm({
64
69
  timeSlot: resolvedTimeSlot,
65
70
  service: resolvedService,
@@ -1,5 +1,4 @@
1
1
  export * as Booking from './booking/Booking.js';
2
- export * as BookingForm from './booking-form/BookingForm.js';
3
2
  export * as Service from './service/Service.js';
4
3
  export * as ServiceMedia from './service/ServiceMedia.js';
5
4
  export * as TimeSlotList from './time-slot-list/TimeSlotList.js';
@@ -1,5 +1,5 @@
1
1
  export * as Booking from './booking/Booking.js';
2
- export * as BookingForm from './booking-form/BookingForm.js';
2
+ // export * as BookingForm from './booking-form/BookingForm.js';
3
3
  export * as Service from './service/Service.js';
4
4
  export * as ServiceMedia from './service/ServiceMedia.js';
5
5
  export * as TimeSlotList from './time-slot-list/TimeSlotList.js';
@@ -23,6 +23,10 @@ export interface RootProps {
23
23
  children?: React.ReactNode | AsChildChildren<CoreLocation.LocationRenderProps>;
24
24
  /** CSS class name */
25
25
  className?: string;
26
+ /** Custom label for CUSTOM location type */
27
+ customLocationLabel?: string;
28
+ /** Custom label for CUSTOMER location type */
29
+ customerLocationLabel?: string;
26
30
  /** Data attributes */
27
31
  [key: `data-${string}`]: string | undefined;
28
32
  }
@@ -9,6 +9,7 @@ import React from 'react';
9
9
  import * as CoreLocation from '../core/location/Location.js';
10
10
  import { AsChildSlot } from '@wix/headless-utils/react';
11
11
  import { Address } from '@wix/headless-components/react';
12
+ import { LocationType } from '../../services/location-list/location-list.def.js';
12
13
  // Re-export useLocationContext from core
13
14
  export { useLocationContext } from '../core/location/Location.js';
14
15
  // ==========================================
@@ -63,10 +64,27 @@ const useLocationContext = CoreLocation.useLocationContext;
63
64
  * ```
64
65
  */
65
66
  export const Root = React.forwardRef((props, ref) => {
66
- const { location, asChild, children, className, ...attrs } = props;
67
+ const { location, asChild, children, className, customLocationLabel, customerLocationLabel, ...attrs } = props;
67
68
  // Extract data-* attributes
68
69
  const dataAttrs = Object.fromEntries(Object.entries(attrs).filter(([key]) => key.startsWith('data-')));
69
- return (_jsx(CoreLocation.Root, { location: location, children: _jsx(CoreLocation.Data, { children: (renderProps) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.locationRoot, "data-location-type": renderProps.locationType, customElement: children, customElementProps: renderProps, ...dataAttrs, children: children })) }) }));
70
+ // If location is synthetic and labels are provided, update the synthetic location's name
71
+ let processedLocation = location;
72
+ if (location && 'synthetic' in location && location.synthetic === true) {
73
+ const syntheticLoc = location;
74
+ const shouldUpdateName = (syntheticLoc.locationType === LocationType.CUSTOM &&
75
+ customLocationLabel !== undefined) ||
76
+ (syntheticLoc.locationType === LocationType.CUSTOMER &&
77
+ customerLocationLabel !== undefined);
78
+ if (shouldUpdateName) {
79
+ processedLocation = {
80
+ ...syntheticLoc,
81
+ name: syntheticLoc.locationType === LocationType.CUSTOM
82
+ ? customLocationLabel
83
+ : customerLocationLabel,
84
+ };
85
+ }
86
+ }
87
+ return (_jsx(CoreLocation.Root, { location: processedLocation, children: _jsx(CoreLocation.Data, { children: (renderProps) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.locationRoot, "data-location-type": renderProps.locationType, customElement: children, customElementProps: renderProps, ...dataAttrs, children: children })) }) }));
70
88
  });
71
89
  Root.displayName = 'Location.Root';
72
90
  /**
@@ -17,6 +17,10 @@ export interface RootProps {
17
17
  locationListConfig?: LocationListServiceConfig;
18
18
  className?: string;
19
19
  variant?: ListVariant;
20
+ /** Custom label for CUSTOM location type */
21
+ customLocationLabel?: string;
22
+ /** Custom label for CUSTOMER location type */
23
+ customerLocationLabel?: string;
20
24
  }
21
25
  /**
22
26
  * Root component that provides the LocationList service context for rendering locations lists.
@@ -9,9 +9,15 @@ import React from 'react';
9
9
  import { GenericList, } from '@wix/headless-components/react';
10
10
  import { AsChildSlot } from '@wix/headless-utils/react';
11
11
  import { useService } from '@wix/services-manager-react';
12
+ import { LocationType, } from '../../services/location-list/location-list.def.js';
12
13
  import { BookingServiceDefinition } from '../../services/booking/booking.js';
13
14
  import * as CoreLocationList from '../core/location-list/LocationList.js';
14
15
  import * as Location from './Location.js';
16
+ const LocationLabelsContext = React.createContext(null);
17
+ function useLocationLabelsContext() {
18
+ const context = React.useContext(LocationLabelsContext);
19
+ return context || {};
20
+ }
15
21
  // ============================================================================
16
22
  // TestIds
17
23
  // ============================================================================
@@ -45,11 +51,11 @@ var TestIds;
45
51
  * ```
46
52
  */
47
53
  export const Root = React.forwardRef((props, ref) => {
48
- const { children, locationListConfig, className, variant } = props;
54
+ const { children, locationListConfig, className, variant, customLocationLabel, customerLocationLabel, } = props;
49
55
  const config = locationListConfig || {
50
56
  locations: [],
51
57
  };
52
- return (_jsx(CoreLocationList.Root, { locationListServiceConfig: config, children: _jsx(RootContent, { className: className, ref: ref, variant: variant, children: children }) }));
58
+ return (_jsx(LocationLabelsContext.Provider, { value: { customLocationLabel, customerLocationLabel }, children: _jsx(CoreLocationList.Root, { locationListServiceConfig: config, children: _jsx(RootContent, { className: className, ref: ref, variant: variant, children: children }) }) }));
53
59
  });
54
60
  Root.displayName = 'LocationList.Root';
55
61
  /**
@@ -85,15 +91,35 @@ export const Locations = React.forwardRef((props, ref) => {
85
91
  Locations.displayName = 'LocationList.Locations';
86
92
  export const LocationRepeater = React.forwardRef((props, ref) => {
87
93
  const { children } = props;
94
+ const { customLocationLabel, customerLocationLabel } = useLocationLabelsContext();
88
95
  // Custom itemWrapper that wraps each item in Location.Root
89
96
  const locationItemWrapper = ({ item: displayLocation, children: itemChildren, }) => {
90
97
  // Convert DisplayLocation to LocationInput
91
98
  // If location is null, create a SyntheticLocation
92
- const location = displayLocation.location ?? {
93
- locationType: displayLocation.type,
94
- synthetic: true,
95
- _id: displayLocation.id,
96
- };
99
+ let location;
100
+ if (displayLocation.location) {
101
+ location = displayLocation.location;
102
+ }
103
+ else {
104
+ const locationType = displayLocation.type;
105
+ // Determine the name based on labels or defaults
106
+ let name;
107
+ if (locationType === LocationType.CUSTOM &&
108
+ customLocationLabel !== undefined) {
109
+ name = customLocationLabel;
110
+ }
111
+ else if (locationType === LocationType.CUSTOMER &&
112
+ customerLocationLabel !== undefined) {
113
+ name = customerLocationLabel;
114
+ }
115
+ // If no label provided, name will be undefined and defaults will be used in computeLocationRenderProps
116
+ location = {
117
+ locationType,
118
+ synthetic: true,
119
+ _id: displayLocation.id,
120
+ name,
121
+ };
122
+ }
97
123
  return (_jsx(Location.Root, { location: location, "data-testid": TestIds.locationListLocation, "data-location-id": displayLocation.id, "data-location-type": displayLocation.type, "data-item-id": displayLocation.id, children: itemChildren }, displayLocation.id));
98
124
  };
99
125
  return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: locationItemWrapper, children: children }));
@@ -86,12 +86,8 @@ Timezone.displayName = 'TimeSlotList.Timezone';
86
86
  */
87
87
  export const Root = React.forwardRef((props, ref) => {
88
88
  const { children, config, className, variant, navigateToBookingForm: providedNavigateToBookingForm, } = props;
89
- // Wrap defaultNavigateToBookingForm to match optional parameter signature
90
- // The core component will handle getting timeSlot/service from BookingService if not provided
91
89
  const navigateToBookingForm = providedNavigateToBookingForm ||
92
90
  (async ({ timeSlot, service, }) => {
93
- // This will be handled by the core component's wrapper
94
- // which will resolve timeSlot/service from BookingService if needed
95
91
  if (!timeSlot || !service) {
96
92
  throw new Error('timeSlot and service are required when using default navigation. Either provide them or ensure BookingService has service selections.');
97
93
  }
@@ -6,8 +6,9 @@ export { ServiceService, ServiceServiceDefinition, type ServiceServiceAPI, type
6
6
  export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type BookingServiceActions, type ServiceSelection, type ServiceSelectionTimeSlot, } from './booking/booking.js';
7
7
  export { TimeSlotListService, TimeSlotListServiceDefinition, TimeSlotService, TimeSlotServiceDefinition, ViewMode, loadTimeSlotListConfig, type TimeSlotListServiceAPI, type TimeSlotListServiceActions, type TimeSlotListServiceConfig, type TimeSlotServiceAPI, type TimeSlotServiceConfig, type LoadTimeSlotListConfigOptions, type LoadTimeSlotListConfigResult, } from './time-slot-list/index.js';
8
8
  export { ServiceListService, ServiceListServiceDefinition, type ServiceListServiceAPI, type ServiceListServiceConfig, type ServiceListFilters, type ServiceListActions, type QueryOptions, loadServiceListServiceInitialData, type SuccessServiceListServiceConfigResult, type ErrorServiceListServiceConfigResult, } from './service-list/service-list.js';
9
+ export { SYNTHETIC_CUSTOM_ID, SYNTHETIC_CUSTOMER_ID, } from '../api/query-services/index.js';
9
10
  export { executeBookAction, canBook, buildBookingRequest, buildCheckoutRequest, type CanBookParams, type BookResult, type BookingError, type BookActionParams, type BookChildProps, type BookProps, type BuildCheckoutParams, } from './booking/book-action/index.js';
10
11
  export { BookingFormService, BookingFormServiceDefinition, type BookingFormServiceAPI, type BookingFormServiceConfig, type BookingFormServiceInternalAPI, type ValidationResult, } from './booking-form/booking-form.js';
11
12
  export { PaymentService, PaymentServiceDefinition, type PaymentServiceAPI, type PaymentServiceConfig, type PaymentDetails, type PricingServiceSelection, type LineItemAdditionalInfo, loadPaymentConfig, type SuccessPaymentConfigResult, type ErrorPaymentConfigResult, } from './payment/payment.js';
12
- export { LocationListService, LocationListServiceDefinition, LocationType, loadLocationListServiceInitialData, locationListServiceBinding, type LocationListServiceAPI, type LocationListServiceConfig, type LocationListActions, type LocationData, type DisplayLocation, type LoadLocationListServiceResult, } from './location-list/location-list.js';
13
+ export { LocationListService, LocationListServiceDefinition, LocationType, loadLocationListServiceInitialData, locationListServiceBinding, type LocationListServiceAPI, type LocationListServiceConfig, type LocationListActions, type LocationData, type DisplayLocation, type LoadLocationListServiceResult, getLocationById, } from './location-list/location-list.js';
13
14
  export { StaffMemberListService, StaffMemberListServiceDefinition, loadStaffMemberListServiceInitialData, staffMemberListServiceBinding, type StaffMemberListServiceAPI, type StaffMemberListServiceConfig, type StaffMemberListActions, type StaffMemberData, type LoadStaffMemberListServiceResult, } from './staff-member-list/staff-member-list.js';
@@ -6,8 +6,9 @@ export { ServiceService, ServiceServiceDefinition, loadServiceServiceInitialData
6
6
  export { BookingService, BookingServiceDefinition, } from './booking/booking.js';
7
7
  export { TimeSlotListService, TimeSlotListServiceDefinition, TimeSlotService, TimeSlotServiceDefinition, ViewMode, loadTimeSlotListConfig, } from './time-slot-list/index.js';
8
8
  export { ServiceListService, ServiceListServiceDefinition, loadServiceListServiceInitialData, } from './service-list/service-list.js';
9
+ export { SYNTHETIC_CUSTOM_ID, SYNTHETIC_CUSTOMER_ID, } from '../api/query-services/index.js';
9
10
  export { executeBookAction, canBook, buildBookingRequest, buildCheckoutRequest, } from './booking/book-action/index.js';
10
11
  export { BookingFormService, BookingFormServiceDefinition, } from './booking-form/booking-form.js';
11
12
  export { PaymentService, PaymentServiceDefinition, loadPaymentConfig, } from './payment/payment.js';
12
- export { LocationListService, LocationListServiceDefinition, LocationType, loadLocationListServiceInitialData, locationListServiceBinding, } from './location-list/location-list.js';
13
+ export { LocationListService, LocationListServiceDefinition, LocationType, loadLocationListServiceInitialData, locationListServiceBinding, getLocationById, } from './location-list/location-list.js';
13
14
  export { StaffMemberListService, StaffMemberListServiceDefinition, loadStaffMemberListServiceInitialData, staffMemberListServiceBinding, } from './staff-member-list/staff-member-list.js';
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import type { ServiceFactoryConfig } from '@wix/services-definitions';
8
8
  import { type LocationData } from './location-list.def.js';
9
+ export { getLocationById } from '../../api/query-locations/index.js';
9
10
  /**
10
11
  * Configuration interface for LocationListService
11
12
  */
@@ -10,14 +10,15 @@ import { 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';
13
+ export { getLocationById } from '../../api/query-locations/index.js';
13
14
  // ============================================================================
14
15
  // Constants
15
16
  // ============================================================================
16
17
  /**
17
18
  * Synthetic location IDs for non-business locations
18
19
  */
19
- const SYNTHETIC_CUSTOM_ID = '__synthetic_custom__';
20
- const SYNTHETIC_CUSTOMER_ID = '__synthetic_customer__';
20
+ const SYNTHETIC_CUSTOM_ID = 'custom';
21
+ const SYNTHETIC_CUSTOMER_ID = 'customer';
21
22
  // ============================================================================
22
23
  // Helper Functions
23
24
  // ============================================================================
@@ -88,6 +88,7 @@ export interface TimeSlotListServiceAPI {
88
88
  hasMore: Signal<boolean>;
89
89
  dateRange: Signal<DateRange>;
90
90
  actions: TimeSlotListServiceActions;
91
+ dispose: () => void;
91
92
  }
92
93
  export declare const TimeSlotListServiceDefinition: string & {
93
94
  __api: TimeSlotListServiceAPI;
@@ -19,15 +19,12 @@ function getClientTimezone() {
19
19
  // Service Implementation
20
20
  // ============================================================================
21
21
  export const TimeSlotListService = implementService.withConfig()(TimeSlotListServiceDefinition, ({ getService, config }) => {
22
- // Get dependent services
23
22
  const signalsService = getService(SignalsServiceDefinition);
24
23
  const bookingService = getService(BookingServiceDefinition);
25
- // Initialize Signals
26
24
  const timeSlotsSignal = signalsService.signal(config.timeSlots || []);
27
25
  const isLoadingSignal = signalsService.signal(false);
28
26
  const errorSignal = signalsService.signal(null);
29
27
  const hasMoreSignal = signalsService.signal(false);
30
- // Internal only - viewMode is auto-detected based on service types
31
28
  const viewModeSignal = signalsService.signal(ViewMode.CLASSIC);
32
29
  const dateRangeSignal = signalsService.signal({
33
30
  start: config.startDate,
@@ -201,8 +198,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
201
198
  : undefined;
202
199
  });
203
200
  let isFirstRun = true;
204
- signalsService.effect(() => {
205
- // Dependencies - trigger refetch when these change
201
+ const dispose = signalsService.effect(() => {
206
202
  dateRangeSignal.get();
207
203
  bookingService.timezone.get();
208
204
  bookingService.location.get();
@@ -215,16 +211,12 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
215
211
  }
216
212
  fetchTimeSlots();
217
213
  });
218
- // Return service API
219
214
  return {
220
- // State Signals
221
215
  timeSlots: timeSlotsSignal,
222
216
  isLoading: isLoadingSignal,
223
217
  error: errorSignal,
224
218
  hasMore: hasMoreSignal,
225
- // Configuration Signals (viewMode is internal only)
226
219
  dateRange: dateRangeSignal,
227
- // Actions
228
220
  actions: {
229
221
  selectSlot,
230
222
  selectStaffMember,
@@ -232,6 +224,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
232
224
  loadMore,
233
225
  setDateRange,
234
226
  },
227
+ dispose,
235
228
  };
236
229
  });
237
230
  /**
@@ -112,5 +112,6 @@ export function createMockTimeSlotListService(config = {}) {
112
112
  dateRangeSignal.set({ start, end });
113
113
  }),
114
114
  },
115
+ dispose: vi.fn(),
115
116
  };
116
117
  }
@@ -4,12 +4,12 @@
4
4
  *
5
5
  * @module API
6
6
  */
7
- export { getServiceById, getServiceBySlug, queryServices, type PagingMetadata, type ServiceListFilters, type QueryServicesRequest, } from './query-services/index.js';
7
+ export { getServiceById, getServiceBySlug, queryServices, type PagingMetadata, type ServiceListFilters, type QueryServicesRequest, SYNTHETIC_CUSTOM_ID, SYNTHETIC_CUSTOMER_ID, } from './query-services/index.js';
8
8
  export { fetchAvailability } from './fetch-availability/index.js';
9
9
  export { createBooking, type CreateBookingOptions, type Booking, type CreateBookingRequest, type CreateBookingResponse, type ParticipantNotification, type ContactDetails, } from './create-booking/index.js';
10
10
  export { createCheckout, ChannelType, type CreateCheckoutRequest, type CreateCheckoutResponse, } from './create-checkout/index.js';
11
11
  export { createOrder, type CreateOrderOptions, type CreateOrderResponse, } from './create-order/index.js';
12
- export { queryLocations, type QueryLocationsResult, type LocationData, } from './query-locations/index.js';
12
+ export { queryLocations, getLocationById, type QueryLocationsResult, type LocationData, } from './query-locations/index.js';
13
13
  export { queryCategories, type QueryCategoriesResult, type Category, } from './query-categories/index.js';
14
14
  /**
15
15
  * PagingMetadata includes:
package/dist/api/index.js CHANGED
@@ -4,12 +4,12 @@
4
4
  *
5
5
  * @module API
6
6
  */
7
- export { getServiceById, getServiceBySlug, queryServices, } from './query-services/index.js';
7
+ export { getServiceById, getServiceBySlug, queryServices, SYNTHETIC_CUSTOM_ID, SYNTHETIC_CUSTOMER_ID, } from './query-services/index.js';
8
8
  export { fetchAvailability } from './fetch-availability/index.js';
9
9
  export { createBooking, } from './create-booking/index.js';
10
10
  export { createCheckout, ChannelType, } from './create-checkout/index.js';
11
11
  export { createOrder, } from './create-order/index.js';
12
- export { queryLocations, } from './query-locations/index.js';
12
+ export { queryLocations, getLocationById, } from './query-locations/index.js';
13
13
  export { queryCategories, } from './query-categories/index.js';
14
14
  /**
15
15
  * PagingMetadata includes:
@@ -36,3 +36,17 @@ export interface QueryLocationsResult {
36
36
  * ```
37
37
  */
38
38
  export declare function queryLocations(): Promise<QueryLocationsResult>;
39
+ /**
40
+ * Fetches a single location by its business location ID
41
+ * @param locationId - The business location ID (GUID)
42
+ * @returns Promise resolving to the location or null if not found
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const location = await getLocationById('12345678-1234-1234-1234-123456789012');
47
+ * if (location) {
48
+ * console.log(location.business?.name);
49
+ * }
50
+ * ```
51
+ */
52
+ export declare function getLocationById(locationId: string): Promise<LocationData | null>;
@@ -28,3 +28,30 @@ export async function queryLocations() {
28
28
  hasCustomerLocations: response.customerLocations?.exists || false,
29
29
  };
30
30
  }
31
+ /**
32
+ * Fetches a single location by its business location ID
33
+ * @param locationId - The business location ID (GUID)
34
+ * @returns Promise resolving to the location or null if not found
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * const location = await getLocationById('12345678-1234-1234-1234-123456789012');
39
+ * if (location) {
40
+ * console.log(location.business?.name);
41
+ * }
42
+ * ```
43
+ */
44
+ export async function getLocationById(locationId) {
45
+ try {
46
+ const response = await queryLocationsApi({
47
+ filter: {
48
+ businessLocationIds: [locationId],
49
+ },
50
+ });
51
+ return response.businessLocations?.locations?.[0] ?? null;
52
+ }
53
+ catch (error) {
54
+ console.error(`Failed to load location for id "${locationId}":`, error);
55
+ return null;
56
+ }
57
+ }
@@ -3,6 +3,11 @@
3
3
  * Fetches single or multiple services with pagination and sorting
4
4
  */
5
5
  import { type Service, type Paging, type Sorting } from '@wix/auto_sdk_bookings_services';
6
+ /**
7
+ * Synthetic location ID constants for non-business locations
8
+ */
9
+ export declare const SYNTHETIC_CUSTOM_ID = "custom";
10
+ export declare const SYNTHETIC_CUSTOMER_ID = "customer";
6
11
  /**
7
12
  * Paging metadata from query services response.
8
13
  * Extends the SDK's Paging type with hasNext flag to indicate if more services are available.
@@ -10,8 +10,8 @@ const BOOKING_APP_ID = '13d21c63-b5ec-5912-8397-c3a5ddb27a97';
10
10
  /**
11
11
  * Synthetic location ID constants for non-business locations
12
12
  */
13
- const SYNTHETIC_CUSTOM_ID = '__synthetic_custom__';
14
- const SYNTHETIC_CUSTOMER_ID = '__synthetic_customer__';
13
+ export const SYNTHETIC_CUSTOM_ID = 'custom';
14
+ export const SYNTHETIC_CUSTOMER_ID = 'customer';
15
15
  /**
16
16
  * Fetches a service by its ID
17
17
  * @param id - The service ID
@@ -27,6 +27,8 @@ export interface SyntheticLocation {
27
27
  synthetic: true;
28
28
  /** Optional ID for tracking (matches ServiceLocation._id) */
29
29
  _id?: string;
30
+ /** Optional name/label for the location */
31
+ name?: string;
30
32
  }
31
33
  /**
32
34
  * Union type - location prop accepts Service or Synthetic location
@@ -106,10 +106,23 @@ function computeLocationRenderProps(rawLocation) {
106
106
  if (isSyntheticLocation(rawLocation)) {
107
107
  const syntheticLoc = rawLocation;
108
108
  const locationType = syntheticLoc.locationType;
109
+ // Use provided name or default based on location type
110
+ let name;
111
+ if (syntheticLoc.name) {
112
+ name = syntheticLoc.name;
113
+ }
114
+ else {
115
+ name =
116
+ locationType === LocationType.CUSTOM
117
+ ? 'Custom Locations'
118
+ : locationType === LocationType.CUSTOMER
119
+ ? "Client's Place"
120
+ : undefined;
121
+ }
109
122
  return {
110
123
  locationType,
111
124
  address: null,
112
- name: undefined,
125
+ name,
113
126
  locationId: syntheticLoc._id,
114
127
  isCustomerLocation: locationType === LocationType.CUSTOMER,
115
128
  isCustomLocation: locationType === LocationType.CUSTOM,
@@ -82,7 +82,6 @@ export function Info(props) {
82
82
  const endDate = new Date(timeSlot.localEndDate);
83
83
  const locationName = timeSlot.location?.name ?? '';
84
84
  const bookable = timeSlot.bookable ?? false;
85
- // Calculate duration from start and end dates
86
85
  const durationInMinutes = Math.round((endDate.getTime() - startDate.getTime()) / (1000 * 60));
87
86
  return props.children({
88
87
  startDate,
@@ -166,7 +165,6 @@ export function StaffMembers(props) {
166
165
  const bookingService = useService(BookingServiceDefinition);
167
166
  const selectedStaffMemberId = bookingService.serviceSelections.get()[0]?.timeSlot?.resources?.[0]?._id;
168
167
  const staffMembers = timeSlot.availableResources[0].resources;
169
- // Return null if only 1 staff member - nothing to choose from
170
168
  if (staffMembers.length <= 1) {
171
169
  return null;
172
170
  }
@@ -1,4 +1,9 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * Core TimeSlotList Components
4
+ * Provides low-level access to TimeSlotListService via render props
5
+ */
6
+ import React from 'react';
2
7
  import { useService, WixServices } from '@wix/services-manager-react';
3
8
  import { createServicesMap } from '@wix/services-manager';
4
9
  import { TimeSlotListServiceDefinition, TimeSlotListService, } from '../../../services/time-slot-list/index.js';
@@ -28,18 +33,20 @@ export function Root(props) {
28
33
  * Internal component that wraps navigateToBookingForm to handle optional parameters
29
34
  */
30
35
  function RootContent({ navigateToBookingForm: providedNavigateToBookingForm, children, }) {
31
- // Get BookingService to use when timeSlot/service are not provided
36
+ const timeSlotListService = useService(TimeSlotListServiceDefinition);
37
+ React.useEffect(() => {
38
+ return () => {
39
+ timeSlotListService.dispose();
40
+ };
41
+ }, [timeSlotListService]);
32
42
  let bookingService = null;
33
43
  try {
34
44
  bookingService = useService(BookingServiceDefinition);
35
45
  }
36
46
  catch {
37
- // BookingService not available - that's ok, user must provide timeSlot/service
38
47
  bookingService = null;
39
48
  }
40
- // Wrap the provided navigateToBookingForm to handle optional parameters
41
49
  const navigateToBookingForm = async ({ timeSlot, service, }) => {
42
- // If timeSlot or service are not provided, try to get them from BookingService
43
50
  let resolvedTimeSlot = timeSlot;
44
51
  let resolvedService = service;
45
52
  if ((!resolvedTimeSlot || !resolvedService) && bookingService) {
@@ -52,14 +59,12 @@ function RootContent({ navigateToBookingForm: providedNavigateToBookingForm, chi
52
59
  }
53
60
  }
54
61
  }
55
- // Validate that we have both timeSlot and service
56
62
  if (!resolvedTimeSlot) {
57
63
  throw new Error('timeSlot is required. Either provide it as a parameter or ensure BookingService has a service selection with a timeSlot.');
58
64
  }
59
65
  if (!resolvedService) {
60
66
  throw new Error('service is required. Either provide it as a parameter or ensure BookingService has a service selection.');
61
67
  }
62
- // Call the provided function with resolved values
63
68
  return providedNavigateToBookingForm({
64
69
  timeSlot: resolvedTimeSlot,
65
70
  service: resolvedService,
@@ -1,5 +1,4 @@
1
1
  export * as Booking from './booking/Booking.js';
2
- export * as BookingForm from './booking-form/BookingForm.js';
3
2
  export * as Service from './service/Service.js';
4
3
  export * as ServiceMedia from './service/ServiceMedia.js';
5
4
  export * as TimeSlotList from './time-slot-list/TimeSlotList.js';
@@ -1,5 +1,5 @@
1
1
  export * as Booking from './booking/Booking.js';
2
- export * as BookingForm from './booking-form/BookingForm.js';
2
+ // export * as BookingForm from './booking-form/BookingForm.js';
3
3
  export * as Service from './service/Service.js';
4
4
  export * as ServiceMedia from './service/ServiceMedia.js';
5
5
  export * as TimeSlotList from './time-slot-list/TimeSlotList.js';
@@ -23,6 +23,10 @@ export interface RootProps {
23
23
  children?: React.ReactNode | AsChildChildren<CoreLocation.LocationRenderProps>;
24
24
  /** CSS class name */
25
25
  className?: string;
26
+ /** Custom label for CUSTOM location type */
27
+ customLocationLabel?: string;
28
+ /** Custom label for CUSTOMER location type */
29
+ customerLocationLabel?: string;
26
30
  /** Data attributes */
27
31
  [key: `data-${string}`]: string | undefined;
28
32
  }
@@ -9,6 +9,7 @@ import React from 'react';
9
9
  import * as CoreLocation from '../core/location/Location.js';
10
10
  import { AsChildSlot } from '@wix/headless-utils/react';
11
11
  import { Address } from '@wix/headless-components/react';
12
+ import { LocationType } from '../../services/location-list/location-list.def.js';
12
13
  // Re-export useLocationContext from core
13
14
  export { useLocationContext } from '../core/location/Location.js';
14
15
  // ==========================================
@@ -63,10 +64,27 @@ const useLocationContext = CoreLocation.useLocationContext;
63
64
  * ```
64
65
  */
65
66
  export const Root = React.forwardRef((props, ref) => {
66
- const { location, asChild, children, className, ...attrs } = props;
67
+ const { location, asChild, children, className, customLocationLabel, customerLocationLabel, ...attrs } = props;
67
68
  // Extract data-* attributes
68
69
  const dataAttrs = Object.fromEntries(Object.entries(attrs).filter(([key]) => key.startsWith('data-')));
69
- return (_jsx(CoreLocation.Root, { location: location, children: _jsx(CoreLocation.Data, { children: (renderProps) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.locationRoot, "data-location-type": renderProps.locationType, customElement: children, customElementProps: renderProps, ...dataAttrs, children: children })) }) }));
70
+ // If location is synthetic and labels are provided, update the synthetic location's name
71
+ let processedLocation = location;
72
+ if (location && 'synthetic' in location && location.synthetic === true) {
73
+ const syntheticLoc = location;
74
+ const shouldUpdateName = (syntheticLoc.locationType === LocationType.CUSTOM &&
75
+ customLocationLabel !== undefined) ||
76
+ (syntheticLoc.locationType === LocationType.CUSTOMER &&
77
+ customerLocationLabel !== undefined);
78
+ if (shouldUpdateName) {
79
+ processedLocation = {
80
+ ...syntheticLoc,
81
+ name: syntheticLoc.locationType === LocationType.CUSTOM
82
+ ? customLocationLabel
83
+ : customerLocationLabel,
84
+ };
85
+ }
86
+ }
87
+ return (_jsx(CoreLocation.Root, { location: processedLocation, children: _jsx(CoreLocation.Data, { children: (renderProps) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.locationRoot, "data-location-type": renderProps.locationType, customElement: children, customElementProps: renderProps, ...dataAttrs, children: children })) }) }));
70
88
  });
71
89
  Root.displayName = 'Location.Root';
72
90
  /**
@@ -17,6 +17,10 @@ export interface RootProps {
17
17
  locationListConfig?: LocationListServiceConfig;
18
18
  className?: string;
19
19
  variant?: ListVariant;
20
+ /** Custom label for CUSTOM location type */
21
+ customLocationLabel?: string;
22
+ /** Custom label for CUSTOMER location type */
23
+ customerLocationLabel?: string;
20
24
  }
21
25
  /**
22
26
  * Root component that provides the LocationList service context for rendering locations lists.
@@ -9,9 +9,15 @@ import React from 'react';
9
9
  import { GenericList, } from '@wix/headless-components/react';
10
10
  import { AsChildSlot } from '@wix/headless-utils/react';
11
11
  import { useService } from '@wix/services-manager-react';
12
+ import { LocationType, } from '../../services/location-list/location-list.def.js';
12
13
  import { BookingServiceDefinition } from '../../services/booking/booking.js';
13
14
  import * as CoreLocationList from '../core/location-list/LocationList.js';
14
15
  import * as Location from './Location.js';
16
+ const LocationLabelsContext = React.createContext(null);
17
+ function useLocationLabelsContext() {
18
+ const context = React.useContext(LocationLabelsContext);
19
+ return context || {};
20
+ }
15
21
  // ============================================================================
16
22
  // TestIds
17
23
  // ============================================================================
@@ -45,11 +51,11 @@ var TestIds;
45
51
  * ```
46
52
  */
47
53
  export const Root = React.forwardRef((props, ref) => {
48
- const { children, locationListConfig, className, variant } = props;
54
+ const { children, locationListConfig, className, variant, customLocationLabel, customerLocationLabel, } = props;
49
55
  const config = locationListConfig || {
50
56
  locations: [],
51
57
  };
52
- return (_jsx(CoreLocationList.Root, { locationListServiceConfig: config, children: _jsx(RootContent, { className: className, ref: ref, variant: variant, children: children }) }));
58
+ return (_jsx(LocationLabelsContext.Provider, { value: { customLocationLabel, customerLocationLabel }, children: _jsx(CoreLocationList.Root, { locationListServiceConfig: config, children: _jsx(RootContent, { className: className, ref: ref, variant: variant, children: children }) }) }));
53
59
  });
54
60
  Root.displayName = 'LocationList.Root';
55
61
  /**
@@ -85,15 +91,35 @@ export const Locations = React.forwardRef((props, ref) => {
85
91
  Locations.displayName = 'LocationList.Locations';
86
92
  export const LocationRepeater = React.forwardRef((props, ref) => {
87
93
  const { children } = props;
94
+ const { customLocationLabel, customerLocationLabel } = useLocationLabelsContext();
88
95
  // Custom itemWrapper that wraps each item in Location.Root
89
96
  const locationItemWrapper = ({ item: displayLocation, children: itemChildren, }) => {
90
97
  // Convert DisplayLocation to LocationInput
91
98
  // If location is null, create a SyntheticLocation
92
- const location = displayLocation.location ?? {
93
- locationType: displayLocation.type,
94
- synthetic: true,
95
- _id: displayLocation.id,
96
- };
99
+ let location;
100
+ if (displayLocation.location) {
101
+ location = displayLocation.location;
102
+ }
103
+ else {
104
+ const locationType = displayLocation.type;
105
+ // Determine the name based on labels or defaults
106
+ let name;
107
+ if (locationType === LocationType.CUSTOM &&
108
+ customLocationLabel !== undefined) {
109
+ name = customLocationLabel;
110
+ }
111
+ else if (locationType === LocationType.CUSTOMER &&
112
+ customerLocationLabel !== undefined) {
113
+ name = customerLocationLabel;
114
+ }
115
+ // If no label provided, name will be undefined and defaults will be used in computeLocationRenderProps
116
+ location = {
117
+ locationType,
118
+ synthetic: true,
119
+ _id: displayLocation.id,
120
+ name,
121
+ };
122
+ }
97
123
  return (_jsx(Location.Root, { location: location, "data-testid": TestIds.locationListLocation, "data-location-id": displayLocation.id, "data-location-type": displayLocation.type, "data-item-id": displayLocation.id, children: itemChildren }, displayLocation.id));
98
124
  };
99
125
  return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: locationItemWrapper, children: children }));
@@ -86,12 +86,8 @@ Timezone.displayName = 'TimeSlotList.Timezone';
86
86
  */
87
87
  export const Root = React.forwardRef((props, ref) => {
88
88
  const { children, config, className, variant, navigateToBookingForm: providedNavigateToBookingForm, } = props;
89
- // Wrap defaultNavigateToBookingForm to match optional parameter signature
90
- // The core component will handle getting timeSlot/service from BookingService if not provided
91
89
  const navigateToBookingForm = providedNavigateToBookingForm ||
92
90
  (async ({ timeSlot, service, }) => {
93
- // This will be handled by the core component's wrapper
94
- // which will resolve timeSlot/service from BookingService if needed
95
91
  if (!timeSlot || !service) {
96
92
  throw new Error('timeSlot and service are required when using default navigation. Either provide them or ensure BookingService has service selections.');
97
93
  }
@@ -6,8 +6,9 @@ export { ServiceService, ServiceServiceDefinition, type ServiceServiceAPI, type
6
6
  export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type BookingServiceActions, type ServiceSelection, type ServiceSelectionTimeSlot, } from './booking/booking.js';
7
7
  export { TimeSlotListService, TimeSlotListServiceDefinition, TimeSlotService, TimeSlotServiceDefinition, ViewMode, loadTimeSlotListConfig, type TimeSlotListServiceAPI, type TimeSlotListServiceActions, type TimeSlotListServiceConfig, type TimeSlotServiceAPI, type TimeSlotServiceConfig, type LoadTimeSlotListConfigOptions, type LoadTimeSlotListConfigResult, } from './time-slot-list/index.js';
8
8
  export { ServiceListService, ServiceListServiceDefinition, type ServiceListServiceAPI, type ServiceListServiceConfig, type ServiceListFilters, type ServiceListActions, type QueryOptions, loadServiceListServiceInitialData, type SuccessServiceListServiceConfigResult, type ErrorServiceListServiceConfigResult, } from './service-list/service-list.js';
9
+ export { SYNTHETIC_CUSTOM_ID, SYNTHETIC_CUSTOMER_ID, } from '../api/query-services/index.js';
9
10
  export { executeBookAction, canBook, buildBookingRequest, buildCheckoutRequest, type CanBookParams, type BookResult, type BookingError, type BookActionParams, type BookChildProps, type BookProps, type BuildCheckoutParams, } from './booking/book-action/index.js';
10
11
  export { BookingFormService, BookingFormServiceDefinition, type BookingFormServiceAPI, type BookingFormServiceConfig, type BookingFormServiceInternalAPI, type ValidationResult, } from './booking-form/booking-form.js';
11
12
  export { PaymentService, PaymentServiceDefinition, type PaymentServiceAPI, type PaymentServiceConfig, type PaymentDetails, type PricingServiceSelection, type LineItemAdditionalInfo, loadPaymentConfig, type SuccessPaymentConfigResult, type ErrorPaymentConfigResult, } from './payment/payment.js';
12
- export { LocationListService, LocationListServiceDefinition, LocationType, loadLocationListServiceInitialData, locationListServiceBinding, type LocationListServiceAPI, type LocationListServiceConfig, type LocationListActions, type LocationData, type DisplayLocation, type LoadLocationListServiceResult, } from './location-list/location-list.js';
13
+ export { LocationListService, LocationListServiceDefinition, LocationType, loadLocationListServiceInitialData, locationListServiceBinding, type LocationListServiceAPI, type LocationListServiceConfig, type LocationListActions, type LocationData, type DisplayLocation, type LoadLocationListServiceResult, getLocationById, } from './location-list/location-list.js';
13
14
  export { StaffMemberListService, StaffMemberListServiceDefinition, loadStaffMemberListServiceInitialData, staffMemberListServiceBinding, type StaffMemberListServiceAPI, type StaffMemberListServiceConfig, type StaffMemberListActions, type StaffMemberData, type LoadStaffMemberListServiceResult, } from './staff-member-list/staff-member-list.js';
@@ -6,8 +6,9 @@ export { ServiceService, ServiceServiceDefinition, loadServiceServiceInitialData
6
6
  export { BookingService, BookingServiceDefinition, } from './booking/booking.js';
7
7
  export { TimeSlotListService, TimeSlotListServiceDefinition, TimeSlotService, TimeSlotServiceDefinition, ViewMode, loadTimeSlotListConfig, } from './time-slot-list/index.js';
8
8
  export { ServiceListService, ServiceListServiceDefinition, loadServiceListServiceInitialData, } from './service-list/service-list.js';
9
+ export { SYNTHETIC_CUSTOM_ID, SYNTHETIC_CUSTOMER_ID, } from '../api/query-services/index.js';
9
10
  export { executeBookAction, canBook, buildBookingRequest, buildCheckoutRequest, } from './booking/book-action/index.js';
10
11
  export { BookingFormService, BookingFormServiceDefinition, } from './booking-form/booking-form.js';
11
12
  export { PaymentService, PaymentServiceDefinition, loadPaymentConfig, } from './payment/payment.js';
12
- export { LocationListService, LocationListServiceDefinition, LocationType, loadLocationListServiceInitialData, locationListServiceBinding, } from './location-list/location-list.js';
13
+ export { LocationListService, LocationListServiceDefinition, LocationType, loadLocationListServiceInitialData, locationListServiceBinding, getLocationById, } from './location-list/location-list.js';
13
14
  export { StaffMemberListService, StaffMemberListServiceDefinition, loadStaffMemberListServiceInitialData, staffMemberListServiceBinding, } from './staff-member-list/staff-member-list.js';
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import type { ServiceFactoryConfig } from '@wix/services-definitions';
8
8
  import { type LocationData } from './location-list.def.js';
9
+ export { getLocationById } from '../../api/query-locations/index.js';
9
10
  /**
10
11
  * Configuration interface for LocationListService
11
12
  */
@@ -10,14 +10,15 @@ import { 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';
13
+ export { getLocationById } from '../../api/query-locations/index.js';
13
14
  // ============================================================================
14
15
  // Constants
15
16
  // ============================================================================
16
17
  /**
17
18
  * Synthetic location IDs for non-business locations
18
19
  */
19
- const SYNTHETIC_CUSTOM_ID = '__synthetic_custom__';
20
- const SYNTHETIC_CUSTOMER_ID = '__synthetic_customer__';
20
+ const SYNTHETIC_CUSTOM_ID = 'custom';
21
+ const SYNTHETIC_CUSTOMER_ID = 'customer';
21
22
  // ============================================================================
22
23
  // Helper Functions
23
24
  // ============================================================================
@@ -88,6 +88,7 @@ export interface TimeSlotListServiceAPI {
88
88
  hasMore: Signal<boolean>;
89
89
  dateRange: Signal<DateRange>;
90
90
  actions: TimeSlotListServiceActions;
91
+ dispose: () => void;
91
92
  }
92
93
  export declare const TimeSlotListServiceDefinition: string & {
93
94
  __api: TimeSlotListServiceAPI;
@@ -19,15 +19,12 @@ function getClientTimezone() {
19
19
  // Service Implementation
20
20
  // ============================================================================
21
21
  export const TimeSlotListService = implementService.withConfig()(TimeSlotListServiceDefinition, ({ getService, config }) => {
22
- // Get dependent services
23
22
  const signalsService = getService(SignalsServiceDefinition);
24
23
  const bookingService = getService(BookingServiceDefinition);
25
- // Initialize Signals
26
24
  const timeSlotsSignal = signalsService.signal(config.timeSlots || []);
27
25
  const isLoadingSignal = signalsService.signal(false);
28
26
  const errorSignal = signalsService.signal(null);
29
27
  const hasMoreSignal = signalsService.signal(false);
30
- // Internal only - viewMode is auto-detected based on service types
31
28
  const viewModeSignal = signalsService.signal(ViewMode.CLASSIC);
32
29
  const dateRangeSignal = signalsService.signal({
33
30
  start: config.startDate,
@@ -201,8 +198,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
201
198
  : undefined;
202
199
  });
203
200
  let isFirstRun = true;
204
- signalsService.effect(() => {
205
- // Dependencies - trigger refetch when these change
201
+ const dispose = signalsService.effect(() => {
206
202
  dateRangeSignal.get();
207
203
  bookingService.timezone.get();
208
204
  bookingService.location.get();
@@ -215,16 +211,12 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
215
211
  }
216
212
  fetchTimeSlots();
217
213
  });
218
- // Return service API
219
214
  return {
220
- // State Signals
221
215
  timeSlots: timeSlotsSignal,
222
216
  isLoading: isLoadingSignal,
223
217
  error: errorSignal,
224
218
  hasMore: hasMoreSignal,
225
- // Configuration Signals (viewMode is internal only)
226
219
  dateRange: dateRangeSignal,
227
- // Actions
228
220
  actions: {
229
221
  selectSlot,
230
222
  selectStaffMember,
@@ -232,6 +224,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
232
224
  loadMore,
233
225
  setDateRange,
234
226
  },
227
+ dispose,
235
228
  };
236
229
  });
237
230
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/headless-bookings",
3
- "version": "0.0.62",
3
+ "version": "0.0.63",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -72,5 +72,5 @@
72
72
  "groupId": "com.wixpress.headless-components"
73
73
  }
74
74
  },
75
- "falconPackageHash": "a7ee3575b035403add534d60cde7f1bc57053324c9c08aa82811ca8b"
75
+ "falconPackageHash": "96083b204b0065686724c6e3b5716295e35a12be6db784974a6c924d"
76
76
  }