@wix/headless-bookings 0.0.43 → 0.0.45

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 (53) hide show
  1. package/cjs/dist/__mocks__/booking.d.ts +9 -4
  2. package/cjs/dist/__mocks__/booking.js +48 -3
  3. package/cjs/dist/__mocks__/time-slots.d.ts +28 -0
  4. package/cjs/dist/__mocks__/time-slots.js +116 -0
  5. package/cjs/dist/api/index.d.ts +1 -0
  6. package/cjs/dist/api/index.js +1 -0
  7. package/cjs/dist/api/query-locations/index.d.ts +38 -0
  8. package/cjs/dist/api/query-locations/index.js +30 -0
  9. package/cjs/dist/react/core/location/Location.d.ts +113 -14
  10. package/cjs/dist/react/core/location/Location.js +189 -30
  11. package/cjs/dist/react/core/location-list/LocationList.d.ts +102 -0
  12. package/cjs/dist/react/core/location-list/LocationList.js +71 -0
  13. package/cjs/dist/react/index.d.ts +1 -0
  14. package/cjs/dist/react/index.js +1 -0
  15. package/cjs/dist/react/location/Location.d.ts +211 -41
  16. package/cjs/dist/react/location/Location.js +219 -46
  17. package/cjs/dist/react/location/LocationList.d.ts +98 -0
  18. package/cjs/dist/react/location/LocationList.js +120 -0
  19. package/cjs/dist/react/service/Service.d.ts +17 -24
  20. package/cjs/dist/react/service/Service.js +24 -36
  21. package/cjs/dist/services/index.d.ts +1 -0
  22. package/cjs/dist/services/index.js +1 -0
  23. package/cjs/dist/services/location-list/location-list.d.ts +100 -0
  24. package/cjs/dist/services/location-list/location-list.def.d.ts +62 -0
  25. package/cjs/dist/services/location-list/location-list.def.js +17 -0
  26. package/cjs/dist/services/location-list/location-list.js +212 -0
  27. package/dist/__mocks__/booking.d.ts +9 -4
  28. package/dist/__mocks__/booking.js +48 -3
  29. package/dist/__mocks__/time-slots.d.ts +28 -0
  30. package/dist/__mocks__/time-slots.js +116 -0
  31. package/dist/api/index.d.ts +1 -0
  32. package/dist/api/index.js +1 -0
  33. package/dist/api/query-locations/index.d.ts +38 -0
  34. package/dist/api/query-locations/index.js +30 -0
  35. package/dist/react/core/location/Location.d.ts +113 -14
  36. package/dist/react/core/location/Location.js +189 -30
  37. package/dist/react/core/location-list/LocationList.d.ts +102 -0
  38. package/dist/react/core/location-list/LocationList.js +71 -0
  39. package/dist/react/index.d.ts +1 -0
  40. package/dist/react/index.js +1 -0
  41. package/dist/react/location/Location.d.ts +211 -41
  42. package/dist/react/location/Location.js +219 -46
  43. package/dist/react/location/LocationList.d.ts +98 -0
  44. package/dist/react/location/LocationList.js +120 -0
  45. package/dist/react/service/Service.d.ts +17 -24
  46. package/dist/react/service/Service.js +24 -36
  47. package/dist/services/index.d.ts +1 -0
  48. package/dist/services/index.js +1 -0
  49. package/dist/services/location-list/location-list.d.ts +100 -0
  50. package/dist/services/location-list/location-list.def.d.ts +62 -0
  51. package/dist/services/location-list/location-list.def.js +17 -0
  52. package/dist/services/location-list/location-list.js +212 -0
  53. package/package.json +2 -2
@@ -1,26 +1,50 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
1
2
  /**
2
3
  * Core Location Component - Parses service location data
3
4
  * Handles business, custom, and customer location types
4
5
  * Converts location data to Address component format
6
+ *
7
+ * @module Core/Location
8
+ */
9
+ import React, { createContext, useContext } from 'react';
10
+ import { useService } from '@wix/services-manager-react';
11
+ import { LocationType, } from '@wix/auto_sdk_bookings_services';
12
+ import { BookingServiceDefinition } from '../../../services/booking/booking.js';
13
+ // ==========================================
14
+ // Context
15
+ // ==========================================
16
+ /**
17
+ * Location context value - same as LocationRenderProps
18
+ */
19
+ const LocationContext = createContext(null);
20
+ /**
21
+ * Hook to access location context from CoreLocation.Root
22
+ * @throws Error if used outside of CoreLocation.Root
5
23
  */
6
- import { LocationType } from '@wix/auto_sdk_bookings_services';
24
+ export function useLocationContext() {
25
+ const context = useContext(LocationContext);
26
+ if (!context) {
27
+ throw new Error('useLocationContext must be used within a CoreLocation.Root component');
28
+ }
29
+ return context;
30
+ }
31
+ // ==========================================
32
+ // Helper Functions
33
+ // ==========================================
34
+ /**
35
+ * Type guard to check if location is a Synthetic location.
36
+ * Synthetic locations have a `synthetic: true` marker.
37
+ */
38
+ function isSyntheticLocation(location) {
39
+ return 'synthetic' in location && location.synthetic === true;
40
+ }
7
41
  /**
8
- * Parses location data into Address component format
42
+ * Parses ServiceLocation data into Address component format
9
43
  */
10
44
  function parseLocationAddress(location, locationType) {
11
- // Handle customer location specially
45
+ // Handle customer location - return null, let consumer handle
12
46
  if (locationType === LocationType.CUSTOMER) {
13
- // For customer location, return an AddressData object with Customer's Place
14
- return {
15
- address: {
16
- addressLine: "Customer's Place",
17
- formattedAddress: "Customer's Place",
18
- city: '',
19
- subdivision: '',
20
- postalCode: '',
21
- country: '',
22
- },
23
- };
47
+ return null;
24
48
  }
25
49
  // Get the common address from the appropriate location type
26
50
  const commonAddress = location.calculatedAddress ||
@@ -29,7 +53,7 @@ function parseLocationAddress(location, locationType) {
29
53
  if (!commonAddress) {
30
54
  return null;
31
55
  }
32
- // Convert CommonAddress to AddressData format (compatible with Address.Root from @wix/headless-components)
56
+ // Convert CommonAddress to AddressData format
33
57
  return {
34
58
  address: {
35
59
  addressLine: commonAddress.streetAddress?.name ||
@@ -50,29 +74,164 @@ function parseLocationAddress(location, locationType) {
50
74
  },
51
75
  };
52
76
  }
77
+ /**
78
+ * Get location type from ServiceLocation data
79
+ */
80
+ function getLocationType(location) {
81
+ return location.type || LocationType.BUSINESS;
82
+ }
83
+ // ==========================================
84
+ // Helper function for computing render props
85
+ // ==========================================
86
+ /**
87
+ * Computes LocationRenderProps from location input
88
+ */
89
+ function computeLocationRenderProps(rawLocation) {
90
+ // Handle no location
91
+ if (!rawLocation) {
92
+ return {
93
+ locationType: LocationType.BUSINESS,
94
+ address: null,
95
+ name: undefined,
96
+ locationId: undefined,
97
+ isCustomerLocation: false,
98
+ isCustomLocation: false,
99
+ isSynthetic: false,
100
+ phone: undefined,
101
+ email: undefined,
102
+ rawLocation: null,
103
+ };
104
+ }
105
+ // Handle synthetic location
106
+ if (isSyntheticLocation(rawLocation)) {
107
+ const syntheticLoc = rawLocation;
108
+ const locationType = syntheticLoc.locationType;
109
+ return {
110
+ locationType,
111
+ address: null,
112
+ name: undefined,
113
+ locationId: syntheticLoc.id,
114
+ isCustomerLocation: locationType === LocationType.CUSTOMER,
115
+ isCustomLocation: locationType === LocationType.CUSTOM,
116
+ isSynthetic: true,
117
+ phone: undefined,
118
+ email: undefined,
119
+ rawLocation: syntheticLoc,
120
+ };
121
+ }
122
+ // Handle Service location
123
+ const serviceLoc = rawLocation;
124
+ const locationType = getLocationType(serviceLoc);
125
+ return {
126
+ locationType,
127
+ address: parseLocationAddress(serviceLoc, locationType),
128
+ name: serviceLoc.business?.name ||
129
+ serviceLoc.custom?.address?.addressLine ||
130
+ '',
131
+ locationId: serviceLoc.business?._id || serviceLoc.custom?._id,
132
+ isCustomerLocation: locationType === LocationType.CUSTOMER,
133
+ isCustomLocation: locationType === LocationType.CUSTOM,
134
+ isSynthetic: false,
135
+ phone: serviceLoc.business?.phone ?? undefined,
136
+ email: serviceLoc.business?.email ?? undefined,
137
+ rawLocation,
138
+ };
139
+ }
53
140
  // ==========================================
54
- // Component
141
+ // Root Component (Context Provider)
55
142
  // ==========================================
56
143
  /**
57
- * Core Location component that parses service location data
58
- * and provides location type and address data to children
144
+ * Core Location Root component that provides location context.
145
+ * Parses location data and makes it available to all child components via context.
59
146
  *
60
147
  * @component
61
148
  * @example
62
149
  * ```tsx
63
- * <CoreLocation location={serviceLocation}>
64
- * {({ locationType, address }) => (
65
- * <div>
66
- * <span>Type: {locationType}</span>
67
- * {address && <Address.Root address={address}><Address.Formatted /></Address.Root>}
68
- * </div>
69
- * )}
70
- * </CoreLocation>
150
+ * <CoreLocation.Root location={serviceLocation}>
151
+ * <Location.Name />
152
+ * <Location.Address />
153
+ * </CoreLocation.Root>
71
154
  * ```
72
155
  */
73
- export function Location(props) {
156
+ export function Root(props) {
74
157
  const { location, children } = props;
75
- const locationType = location.type;
76
- const address = parseLocationAddress(location, locationType);
77
- return children({ locationType, address });
158
+ const renderProps = computeLocationRenderProps(location);
159
+ return (_jsx(LocationContext.Provider, { value: renderProps, children: children }));
160
+ }
161
+ // ==========================================
162
+ // Data Component (Render Props)
163
+ // ==========================================
164
+ /**
165
+ * Core Location Data component that exposes location data via render props.
166
+ * Must be used within a CoreLocation.Root component.
167
+ *
168
+ * @component
169
+ * @example
170
+ * ```tsx
171
+ * <CoreLocation.Root location={serviceLocation}>
172
+ * <CoreLocation.Data>
173
+ * {({ displayName, address }) => (
174
+ * <div>
175
+ * <span>{displayName}</span>
176
+ * {address && <Address.Formatted address={address} />}
177
+ * </div>
178
+ * )}
179
+ * </CoreLocation.Data>
180
+ * </CoreLocation.Root>
181
+ * ```
182
+ */
183
+ export function Data(props) {
184
+ const context = useLocationContext();
185
+ return props.children(context);
186
+ }
187
+ /**
188
+ * Core component that provides location selection actions via render props.
189
+ * Sets the location in BookingService when select is called.
190
+ *
191
+ * @component
192
+ * @example
193
+ * ```tsx
194
+ * <CoreLocation.Root location={serviceLocation}>
195
+ * <CoreLocation.Actions>
196
+ * {({ select, selected, rawLocation }) => (
197
+ * <button onClick={select}>
198
+ * {selected ? 'Selected' : 'Select'}
199
+ * </button>
200
+ * )}
201
+ * </CoreLocation.Actions>
202
+ * </CoreLocation.Root>
203
+ * ```
204
+ */
205
+ export function Actions(props) {
206
+ const { rawLocation } = useLocationContext();
207
+ // Try to get BookingService for setting location
208
+ let bookingService = null;
209
+ try {
210
+ // eslint-disable-next-line react-hooks/rules-of-hooks
211
+ bookingService = useService(BookingServiceDefinition);
212
+ }
213
+ catch {
214
+ bookingService = null;
215
+ }
216
+ // Compute selected state from BookingService
217
+ const selected = React.useMemo(() => {
218
+ if (!bookingService || !rawLocation)
219
+ return false;
220
+ const currentLocation = bookingService.location.get();
221
+ if (!currentLocation || !rawLocation)
222
+ return false;
223
+ // Compare by _id if available
224
+ return currentLocation._id === rawLocation._id;
225
+ }, [bookingService, rawLocation]);
226
+ const select = () => {
227
+ // Set location in BookingService
228
+ if (bookingService && rawLocation) {
229
+ bookingService.actions.setLocation(rawLocation);
230
+ }
231
+ };
232
+ return props.children({
233
+ select,
234
+ rawLocation,
235
+ selected,
236
+ });
78
237
  }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Core LocationList Component
3
+ * Bridge between LocationListService and headless components using render props
4
+ *
5
+ * @module Core/LocationList
6
+ */
7
+ import React from 'react';
8
+ import { type LocationListServiceConfig } from '../../../services/location-list/location-list.js';
9
+ import type { LocationData, DisplayLocation } from '../../../services/location-list/location-list.def.js';
10
+ /**
11
+ * Props for LocationList.Root component
12
+ */
13
+ export interface RootProps {
14
+ children: React.ReactNode;
15
+ locationListServiceConfig: LocationListServiceConfig;
16
+ }
17
+ /**
18
+ * Root component that provides LocationList service context
19
+ *
20
+ * @component
21
+ * @example
22
+ * ```tsx
23
+ * <CoreLocationList.Root locationListServiceConfig={config}>
24
+ * <CoreLocationList.Locations>
25
+ * {({ displayLocations }) => (
26
+ * // render locations
27
+ * )}
28
+ * </CoreLocationList.Locations>
29
+ * </CoreLocationList.Root>
30
+ * ```
31
+ */
32
+ export declare function Root(props: RootProps): React.ReactNode;
33
+ /**
34
+ * Render props for Locations component
35
+ */
36
+ export interface LocationsRenderProps {
37
+ /** Raw locations array from the service */
38
+ locations: LocationData[];
39
+ /** Processed display locations for UI */
40
+ displayLocations: DisplayLocation[];
41
+ /** Whether there are any locations */
42
+ hasLocations: boolean;
43
+ /** Whether custom locations exist */
44
+ hasCustomLocations: boolean;
45
+ /** Whether customer locations exist */
46
+ hasCustomerLocations: boolean;
47
+ /** Whether locations are currently loading */
48
+ isLoading: boolean;
49
+ /** Error message if any */
50
+ error: string | null;
51
+ }
52
+ /**
53
+ * Props for Locations render prop component
54
+ */
55
+ export interface LocationsProps {
56
+ children: (data: LocationsRenderProps) => React.ReactNode;
57
+ }
58
+ /**
59
+ * Core component that provides access to locations list via render props
60
+ *
61
+ * @component
62
+ * @example
63
+ * ```tsx
64
+ * <CoreLocationList.Locations>
65
+ * {({ displayLocations, hasLocations, isLoading }) => (
66
+ * isLoading ? <Spinner /> : displayLocations.map(...)
67
+ * )}
68
+ * </CoreLocationList.Locations>
69
+ * ```
70
+ */
71
+ export declare function Locations(props: LocationsProps): React.ReactNode;
72
+ /**
73
+ * Render props for Actions component
74
+ */
75
+ export interface ActionsRenderProps {
76
+ /** Select a display location */
77
+ select: (displayLocation: DisplayLocation) => void;
78
+ /** Currently selected location (from BookingService) */
79
+ selectedLocation: LocationData | null;
80
+ }
81
+ /**
82
+ * Props for Actions render prop component
83
+ */
84
+ export interface ActionsProps {
85
+ children: (actions: ActionsRenderProps) => React.ReactNode;
86
+ }
87
+ /**
88
+ * Core component that provides location actions via render props
89
+ *
90
+ * @component
91
+ * @example
92
+ * ```tsx
93
+ * <CoreLocationList.Actions>
94
+ * {({ select, selectedLocation }) => (
95
+ * <button onClick={() => select(displayLoc)}>
96
+ * {selectedLocation?.business?.name || 'Select'}
97
+ * </button>
98
+ * )}
99
+ * </CoreLocationList.Actions>
100
+ * ```
101
+ */
102
+ export declare function Actions(props: ActionsProps): React.ReactNode;
@@ -0,0 +1,71 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { WixServices, useService } from '@wix/services-manager-react';
3
+ import { createServicesMap } from '@wix/services-manager';
4
+ import { LocationListServiceDefinition, LocationListService, } from '../../../services/location-list/location-list.js';
5
+ /**
6
+ * Root component that provides LocationList service context
7
+ *
8
+ * @component
9
+ * @example
10
+ * ```tsx
11
+ * <CoreLocationList.Root locationListServiceConfig={config}>
12
+ * <CoreLocationList.Locations>
13
+ * {({ displayLocations }) => (
14
+ * // render locations
15
+ * )}
16
+ * </CoreLocationList.Locations>
17
+ * </CoreLocationList.Root>
18
+ * ```
19
+ */
20
+ export function Root(props) {
21
+ return (_jsx(WixServices, { servicesMap: createServicesMap().addService(LocationListServiceDefinition, LocationListService, props.locationListServiceConfig), children: props.children }));
22
+ }
23
+ /**
24
+ * Core component that provides access to locations list via render props
25
+ *
26
+ * @component
27
+ * @example
28
+ * ```tsx
29
+ * <CoreLocationList.Locations>
30
+ * {({ displayLocations, hasLocations, isLoading }) => (
31
+ * isLoading ? <Spinner /> : displayLocations.map(...)
32
+ * )}
33
+ * </CoreLocationList.Locations>
34
+ * ```
35
+ */
36
+ export function Locations(props) {
37
+ const service = useService(LocationListServiceDefinition);
38
+ const locations = service.locations.get();
39
+ const displayLocations = service.displayLocations.get();
40
+ return props.children({
41
+ locations,
42
+ displayLocations,
43
+ hasLocations: displayLocations.length > 0,
44
+ hasCustomLocations: service.hasCustomLocations.get(),
45
+ hasCustomerLocations: service.hasCustomerLocations.get(),
46
+ isLoading: service.isLoading.get(),
47
+ error: service.error.get(),
48
+ });
49
+ }
50
+ /**
51
+ * Core component that provides location actions via render props
52
+ *
53
+ * @component
54
+ * @example
55
+ * ```tsx
56
+ * <CoreLocationList.Actions>
57
+ * {({ select, selectedLocation }) => (
58
+ * <button onClick={() => select(displayLoc)}>
59
+ * {selectedLocation?.business?.name || 'Select'}
60
+ * </button>
61
+ * )}
62
+ * </CoreLocationList.Actions>
63
+ * ```
64
+ */
65
+ export function Actions(props) {
66
+ const service = useService(LocationListServiceDefinition);
67
+ return props.children({
68
+ select: service.actions.select,
69
+ selectedLocation: service.selectedLocation.get(),
70
+ });
71
+ }
@@ -5,4 +5,5 @@ export * as ServiceMedia from './service/ServiceMedia.js';
5
5
  export * as TimeSlotList from './time-slot-list/TimeSlotList.js';
6
6
  export * as ServiceList from './service-list/ServiceList.js';
7
7
  export * as Location from './location/Location.js';
8
+ export * as LocationList from './location/LocationList.js';
8
9
  export * as Payment from './payment/Payment.js';
@@ -5,4 +5,5 @@ export * as ServiceMedia from './service/ServiceMedia.js';
5
5
  export * as TimeSlotList from './time-slot-list/TimeSlotList.js';
6
6
  export * as ServiceList from './service-list/ServiceList.js';
7
7
  export * as Location from './location/Location.js';
8
+ export * as LocationList from './location/LocationList.js';
8
9
  export * as Payment from './payment/Payment.js';