@wix/headless-bookings 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/dist/api/index.d.ts +10 -1
- package/cjs/dist/api/index.js +10 -1
- package/cjs/dist/api/query-services/index.d.ts +78 -0
- package/cjs/dist/api/query-services/index.js +137 -0
- package/cjs/dist/react/core/booking/Booking.d.ts +5 -5
- package/cjs/dist/react/core/booking/Booking.js +5 -5
- package/cjs/dist/react/core/location/Location.d.ts +44 -0
- package/cjs/dist/react/core/location/Location.js +78 -0
- package/cjs/dist/react/core/service/Service.d.ts +160 -17
- package/cjs/dist/react/core/service/Service.js +211 -13
- package/cjs/dist/react/core/service-list/ServiceList.d.ts +75 -0
- package/cjs/dist/react/core/service-list/ServiceList.js +58 -0
- package/cjs/dist/react/index.d.ts +2 -0
- package/cjs/dist/react/index.js +2 -0
- package/cjs/dist/react/location/Location.d.ts +77 -0
- package/cjs/dist/react/location/Location.js +89 -0
- package/cjs/dist/react/service/Service.d.ts +1036 -31
- package/cjs/dist/react/service/Service.js +1060 -47
- package/cjs/dist/react/service-list/ServiceList.d.ts +185 -0
- package/cjs/dist/react/service-list/ServiceList.js +184 -0
- package/cjs/dist/services/booking/booking.d.ts +19 -11
- package/cjs/dist/services/booking/booking.js +48 -16
- package/cjs/dist/services/index.d.ts +3 -2
- package/cjs/dist/services/index.js +2 -1
- package/cjs/dist/services/service/service.d.ts +71 -18
- package/cjs/dist/services/service/service.js +186 -51
- package/cjs/dist/services/service-list/service-list.d.ts +157 -0
- package/cjs/dist/services/service-list/service-list.js +274 -0
- package/cjs/dist/utils/dateAndTime.d.ts +2 -0
- package/cjs/dist/utils/dateAndTime.js +18 -0
- package/cjs/dist/utils/money.d.ts +21 -0
- package/cjs/dist/utils/money.js +34 -0
- package/dist/api/index.d.ts +10 -1
- package/dist/api/index.js +10 -1
- package/dist/api/query-services/index.d.ts +78 -0
- package/dist/api/query-services/index.js +137 -0
- package/dist/react/core/booking/Booking.d.ts +5 -5
- package/dist/react/core/booking/Booking.js +5 -5
- package/dist/react/core/location/Location.d.ts +44 -0
- package/dist/react/core/location/Location.js +78 -0
- package/dist/react/core/service/Service.d.ts +160 -17
- package/dist/react/core/service/Service.js +211 -13
- package/dist/react/core/service-list/ServiceList.d.ts +75 -0
- package/dist/react/core/service-list/ServiceList.js +58 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.js +2 -0
- package/dist/react/location/Location.d.ts +77 -0
- package/dist/react/location/Location.js +89 -0
- package/dist/react/service/Service.d.ts +1036 -31
- package/dist/react/service/Service.js +1060 -47
- package/dist/react/service-list/ServiceList.d.ts +185 -0
- package/dist/react/service-list/ServiceList.js +184 -0
- package/dist/services/booking/booking.d.ts +19 -11
- package/dist/services/booking/booking.js +48 -16
- package/dist/services/index.d.ts +3 -2
- package/dist/services/index.js +2 -1
- package/dist/services/service/service.d.ts +71 -18
- package/dist/services/service/service.js +186 -51
- package/dist/services/service-list/service-list.d.ts +157 -0
- package/dist/services/service-list/service-list.js +274 -0
- package/dist/utils/dateAndTime.d.ts +2 -0
- package/dist/utils/dateAndTime.js +18 -0
- package/dist/utils/money.d.ts +21 -0
- package/dist/utils/money.js +34 -0
- package/package.json +2 -2
- package/cjs/dist/api/query-service/index.d.ts +0 -23
- package/cjs/dist/api/query-service/index.js +0 -41
- package/dist/api/query-service/index.d.ts +0 -23
- package/dist/api/query-service/index.js +0 -41
|
@@ -13,8 +13,17 @@ import { ServiceServiceDefinition, ServiceService, } from '../../../services/ser
|
|
|
13
13
|
* </Service.Root>
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
|
+
function RootContent({ children, }) {
|
|
17
|
+
const serviceService = useService(ServiceServiceDefinition);
|
|
18
|
+
const selected = serviceService.selectedSignal.get();
|
|
19
|
+
const bookable = serviceService.bookableSignal.get();
|
|
20
|
+
if (typeof children === 'function') {
|
|
21
|
+
return children({ selected, bookable });
|
|
22
|
+
}
|
|
23
|
+
return children;
|
|
24
|
+
}
|
|
16
25
|
export function Root(props) {
|
|
17
|
-
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(ServiceServiceDefinition, ServiceService, props.serviceServiceConfig), children: props.children }));
|
|
26
|
+
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(ServiceServiceDefinition, ServiceService, props.serviceServiceConfig), children: _jsx(RootContent, { children: props.children }) }));
|
|
18
27
|
}
|
|
19
28
|
/**
|
|
20
29
|
* Core component that provides access to full service data via render props.
|
|
@@ -31,23 +40,27 @@ export function Root(props) {
|
|
|
31
40
|
*/
|
|
32
41
|
export function Service(props) {
|
|
33
42
|
const serviceService = useService(ServiceServiceDefinition);
|
|
34
|
-
const service = serviceService.
|
|
35
|
-
const isLoading = serviceService.
|
|
36
|
-
const error = serviceService.
|
|
43
|
+
const service = serviceService.serviceSignal.get();
|
|
44
|
+
const isLoading = serviceService.isLoadingSignal.get();
|
|
45
|
+
const error = serviceService.errorSignal.get();
|
|
37
46
|
return props.children({ service, isLoading, error });
|
|
38
47
|
}
|
|
39
48
|
/**
|
|
40
49
|
* Core component that provides access to service catalog info via render props.
|
|
41
|
-
* Includes name
|
|
50
|
+
* Includes name, description, tagline, duration, type, category, locations, staff, media, and price.
|
|
42
51
|
*
|
|
43
52
|
* @component
|
|
44
53
|
* @example
|
|
45
54
|
* ```tsx
|
|
46
55
|
* <Service.Info>
|
|
47
|
-
* {({ name, description }) => (
|
|
56
|
+
* {({ name, description, tagline, duration, type, category, locations, staff, media, price }) => (
|
|
48
57
|
* <div>
|
|
49
58
|
* <h1>{name}</h1>
|
|
50
59
|
* <p>{description}</p>
|
|
60
|
+
* {tagline && <p>{tagline}</p>}
|
|
61
|
+
* {duration && <p>Duration: {duration} minutes</p>}
|
|
62
|
+
* {type && <p>Type: {type}</p>}
|
|
63
|
+
* {category && <p>Category: {category.name}</p>}
|
|
51
64
|
* </div>
|
|
52
65
|
* )}
|
|
53
66
|
* </Service.Info>
|
|
@@ -55,12 +68,99 @@ export function Service(props) {
|
|
|
55
68
|
*/
|
|
56
69
|
export function Info(props) {
|
|
57
70
|
const serviceService = useService(ServiceServiceDefinition);
|
|
58
|
-
const service = serviceService.
|
|
71
|
+
const service = serviceService.serviceSignal.get();
|
|
72
|
+
const selected = serviceService.selectedSignal.get();
|
|
73
|
+
// Extract price from service.payment for Info component
|
|
74
|
+
const payment = service.payment;
|
|
75
|
+
let priceInfo = undefined;
|
|
76
|
+
if (payment?.rateType === 'FIXED' && payment.fixed?.price) {
|
|
77
|
+
const priceValue = payment.fixed.price.value;
|
|
78
|
+
const currency = payment.fixed.price.currency || 'USD';
|
|
79
|
+
priceInfo = {
|
|
80
|
+
amount: priceValue || undefined,
|
|
81
|
+
currency,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Extract duration from schedule.availabilityConstraints.sessionDurations
|
|
85
|
+
// Use the first duration if multiple are available
|
|
86
|
+
const duration = service.schedule?.availabilityConstraints?.sessionDurations?.[0];
|
|
87
|
+
// Get staff members from staffMemberDetails.staffMembers
|
|
88
|
+
// (available when using conditionalFields: ['STAFF_MEMBER_DETAILS'] in queryServices)
|
|
89
|
+
const staff = service.staffMembers?.map((member) => ({
|
|
90
|
+
_id: member.staffMemberId,
|
|
91
|
+
name: member.name || undefined,
|
|
92
|
+
})) || [];
|
|
93
|
+
// Convert mainMedia to WixMediaImage format
|
|
94
|
+
// Handle both snake_case (main_media) and camelCase (mainMedia) from API
|
|
95
|
+
// Handle both string and object formats for image
|
|
96
|
+
const serviceMedia = service.media;
|
|
97
|
+
const mainMedia = {
|
|
98
|
+
image: serviceMedia?.mainMedia?.image,
|
|
99
|
+
};
|
|
100
|
+
// Convert coverMedia to WixMediaImage format
|
|
101
|
+
// Handle both snake_case (cover_media) and camelCase (coverMedia) from API
|
|
102
|
+
// Handle both string and object formats for image
|
|
103
|
+
const coverMedia = {
|
|
104
|
+
image: serviceMedia?.coverMedia?.image,
|
|
105
|
+
};
|
|
106
|
+
// Convert media items to MediaGallery format
|
|
107
|
+
// Handle both string and object formats for image
|
|
108
|
+
const mediaItems = service.media?.items?.map((item) => {
|
|
109
|
+
return {
|
|
110
|
+
image: item.image,
|
|
111
|
+
};
|
|
112
|
+
}) || [];
|
|
113
|
+
// Extract default capacity directly from service (convert null to undefined)
|
|
114
|
+
const defaultCapacity = service.defaultCapacity ?? undefined;
|
|
59
115
|
return props.children({
|
|
60
116
|
name: service.name || '',
|
|
61
117
|
description: service.description || '',
|
|
118
|
+
tagline: service.tagLine || undefined,
|
|
119
|
+
duration: duration,
|
|
120
|
+
type: service.type,
|
|
121
|
+
category: service.category
|
|
122
|
+
? {
|
|
123
|
+
name: service.category.name || undefined,
|
|
124
|
+
_id: service.category._id || undefined,
|
|
125
|
+
}
|
|
126
|
+
: undefined,
|
|
127
|
+
locations: service.locations,
|
|
128
|
+
staff: staff,
|
|
129
|
+
mainMedia: mainMedia,
|
|
130
|
+
coverMedia: coverMedia,
|
|
131
|
+
mediaItems: mediaItems.length > 0 ? mediaItems : undefined,
|
|
132
|
+
price: priceInfo,
|
|
133
|
+
defaultCapacity: defaultCapacity,
|
|
134
|
+
selected,
|
|
62
135
|
});
|
|
63
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Core component that provides access to service price via render props.
|
|
139
|
+
* Returns comprehensive pricing data including money, rate type, and service capabilities.
|
|
140
|
+
*
|
|
141
|
+
* @component
|
|
142
|
+
* @example
|
|
143
|
+
* ```tsx
|
|
144
|
+
* <Service.Price>
|
|
145
|
+
* {({ money, rateType, minPrice, maxPrice, priceDescription, hasAddOns, hasPricingPlans }) => (
|
|
146
|
+
* rateType === 'FIXED' && money ? (
|
|
147
|
+
* <Money money={money} />
|
|
148
|
+
* ) : rateType === 'VARIED' && minPrice && maxPrice ? (
|
|
149
|
+
* <span><Money money={minPrice} /> - <Money money={maxPrice} /></span>
|
|
150
|
+
* ) : rateType === 'CUSTOM' && priceDescription ? (
|
|
151
|
+
* <span>{priceDescription}</span>
|
|
152
|
+
* ) : rateType === 'NO_FEE' ? (
|
|
153
|
+
* <span>Free</span>
|
|
154
|
+
* ) : null
|
|
155
|
+
* )}
|
|
156
|
+
* </Service.Price>
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export function Price(props) {
|
|
160
|
+
const serviceService = useService(ServiceServiceDefinition);
|
|
161
|
+
const paymentData = serviceService.paymentDataSignal.get();
|
|
162
|
+
return props.children(paymentData);
|
|
163
|
+
}
|
|
64
164
|
/**
|
|
65
165
|
* Core component that provides booking selection actions via render props.
|
|
66
166
|
*
|
|
@@ -68,7 +168,7 @@ export function Info(props) {
|
|
|
68
168
|
* @example
|
|
69
169
|
* ```tsx
|
|
70
170
|
* <Service.Actions>
|
|
71
|
-
* {({ select, add, remove,
|
|
171
|
+
* {({ select, add, remove, rawService, requiresAvailability }) => (
|
|
72
172
|
* <div>
|
|
73
173
|
* <button onClick={select}>Select</button>
|
|
74
174
|
* <button onClick={add}>Add</button>
|
|
@@ -80,11 +180,109 @@ export function Info(props) {
|
|
|
80
180
|
*/
|
|
81
181
|
export function Actions(props) {
|
|
82
182
|
const serviceService = useService(ServiceServiceDefinition);
|
|
83
|
-
const
|
|
183
|
+
const rawService = serviceService.serviceSignal.get();
|
|
184
|
+
const bookable = serviceService.bookableSignal.get();
|
|
185
|
+
const selected = serviceService.selectedSignal.get();
|
|
186
|
+
const requiresAvailability = serviceService.requiresAvailabilitySignal.get();
|
|
187
|
+
return props.children({
|
|
188
|
+
select: serviceService.actions.select,
|
|
189
|
+
add: serviceService.actions.add,
|
|
190
|
+
remove: serviceService.actions.remove,
|
|
191
|
+
rawService,
|
|
192
|
+
bookable,
|
|
193
|
+
selected,
|
|
194
|
+
requiresAvailability,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Core component that provides access to service booking policy via render props.
|
|
199
|
+
* Computes all enabled flags and values from the booking policy.
|
|
200
|
+
*
|
|
201
|
+
* @component
|
|
202
|
+
* @example
|
|
203
|
+
* ```tsx
|
|
204
|
+
* <Service.Policy>
|
|
205
|
+
* {({ bookingPolicy, cancellationPolicyEnabled, latestCancellationInMinutes }) => (
|
|
206
|
+
* cancellationPolicyEnabled ? (
|
|
207
|
+
* <div>Cancel up to {latestCancellationInMinutes} minutes before</div>
|
|
208
|
+
* ) : null
|
|
209
|
+
* )}
|
|
210
|
+
* </Service.Policy>
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
export function Policy(props) {
|
|
214
|
+
const serviceService = useService(ServiceServiceDefinition);
|
|
215
|
+
const service = serviceService.serviceSignal.get();
|
|
216
|
+
const bookingPolicy = service.bookingPolicy || null;
|
|
217
|
+
// Compute all flags here (not in headless components)
|
|
218
|
+
const cancellationPolicy = bookingPolicy?.cancellationPolicy;
|
|
219
|
+
const cancellationPolicyEnabled = cancellationPolicy?.enabled ?? false;
|
|
220
|
+
const limitLatestCancellationEnabled = cancellationPolicy?.limitLatestCancellation ?? false;
|
|
221
|
+
const latestCancellationInMinutes = cancellationPolicy?.latestCancellationInMinutes;
|
|
222
|
+
const lateBookingPolicy = bookingPolicy?.limitLateBookingPolicy;
|
|
223
|
+
const latestBookingPolicyEnabled = lateBookingPolicy?.enabled ?? false;
|
|
224
|
+
const latestBookingInMinutes = lateBookingPolicy?.latestBookingInMinutes;
|
|
225
|
+
const earlyBookingPolicy = bookingPolicy?.limitEarlyBookingPolicy;
|
|
226
|
+
const earliestBookingPolicyEnabled = earlyBookingPolicy?.enabled ?? false;
|
|
227
|
+
const earliestBookingInMinutes = earlyBookingPolicy?.earliestBookingInMinutes;
|
|
228
|
+
const reschedulePolicy = bookingPolicy?.reschedulePolicy;
|
|
229
|
+
const reschedulePolicyEnabled = reschedulePolicy?.enabled ?? false;
|
|
230
|
+
const limitLatestRescheduleEnabled = reschedulePolicy?.limitLatestReschedule ?? false;
|
|
231
|
+
const latestRescheduleInMinutes = reschedulePolicy?.latestRescheduleInMinutes;
|
|
232
|
+
const waitlistPolicy = bookingPolicy?.waitlistPolicy;
|
|
233
|
+
const waitlistPolicyEnabled = waitlistPolicy?.enabled ?? false;
|
|
234
|
+
const waitlistCapacity = waitlistPolicy?.capacity;
|
|
235
|
+
const bookAfterStartPolicy = bookingPolicy?.bookAfterStartPolicy;
|
|
236
|
+
const bookAfterStartEnabled = bookAfterStartPolicy?.enabled ?? false;
|
|
237
|
+
const participantsPolicy = bookingPolicy?.participantsPolicy;
|
|
238
|
+
const maxParticipantsPerBooking = participantsPolicy?.maxParticipantsPerBooking;
|
|
239
|
+
return props.children({
|
|
240
|
+
bookingPolicy,
|
|
241
|
+
cancellationPolicyEnabled,
|
|
242
|
+
limitLatestCancellationEnabled,
|
|
243
|
+
latestCancellationInMinutes,
|
|
244
|
+
latestBookingPolicyEnabled,
|
|
245
|
+
latestBookingInMinutes,
|
|
246
|
+
earliestBookingPolicyEnabled,
|
|
247
|
+
earliestBookingInMinutes,
|
|
248
|
+
reschedulePolicyEnabled,
|
|
249
|
+
limitLatestRescheduleEnabled,
|
|
250
|
+
latestRescheduleInMinutes,
|
|
251
|
+
waitlistPolicyEnabled,
|
|
252
|
+
waitlistCapacity,
|
|
253
|
+
bookAfterStartEnabled,
|
|
254
|
+
maxParticipantsPerBooking,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Core component that provides access to service schedule via render props.
|
|
259
|
+
* Uses the SDK's Schedule type directly. Only renders for CLASS or COURSE service types.
|
|
260
|
+
*
|
|
261
|
+
* @component
|
|
262
|
+
* @example
|
|
263
|
+
* ```tsx
|
|
264
|
+
* <Service.Schedule>
|
|
265
|
+
* {({ schedule, isClassOrCourse }) => (
|
|
266
|
+
* schedule && isClassOrCourse ? (
|
|
267
|
+
* <div>
|
|
268
|
+
* {schedule.firstSessionStart && (
|
|
269
|
+
* <span>Starts: {new Date(schedule.firstSessionStart).toLocaleDateString()}</span>
|
|
270
|
+
* )}
|
|
271
|
+
* {schedule.lastSessionEnd && (
|
|
272
|
+
* <span>Ends: {new Date(schedule.lastSessionEnd).toLocaleDateString()}</span>
|
|
273
|
+
* )}
|
|
274
|
+
* </div>
|
|
275
|
+
* ) : null
|
|
276
|
+
* )}
|
|
277
|
+
* </Service.Schedule>
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
export function Schedule(props) {
|
|
281
|
+
const serviceService = useService(ServiceServiceDefinition);
|
|
282
|
+
const service = serviceService.serviceSignal.get();
|
|
283
|
+
const isClassOrCourse = service.type === 'CLASS' || service.type === 'COURSE';
|
|
84
284
|
return props.children({
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
remove: serviceService.remove,
|
|
88
|
-
service,
|
|
285
|
+
schedule: service.schedule || null,
|
|
286
|
+
isClassOrCourse,
|
|
89
287
|
});
|
|
90
288
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core ServiceList Components
|
|
3
|
+
* Provides low-level access to ServiceListService via render props
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { type ServiceListServiceConfig, type QueryOptions } from '../../../services/service-list/service-list.js';
|
|
7
|
+
import type { services } from '@wix/bookings';
|
|
8
|
+
import type { PagingMetadata } from '../../../api/query-services/index.js';
|
|
9
|
+
/**
|
|
10
|
+
* Props for ServiceList.Root component
|
|
11
|
+
*/
|
|
12
|
+
export interface RootProps {
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
serviceListConfig: ServiceListServiceConfig;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Root component that provides ServiceList service context.
|
|
18
|
+
*
|
|
19
|
+
* @component
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* <ServiceList.Root serviceListConfig={{ services: myServices }}>
|
|
23
|
+
* {children}
|
|
24
|
+
* </ServiceList.Root>
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function Root(props: RootProps): React.ReactNode;
|
|
28
|
+
/**
|
|
29
|
+
* Props for Services render prop component
|
|
30
|
+
*/
|
|
31
|
+
export interface ServicesProps {
|
|
32
|
+
/** Render function that receives services list and metadata */
|
|
33
|
+
children: (props: ServicesRenderProps) => React.ReactNode;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Render props for Services component
|
|
37
|
+
*/
|
|
38
|
+
export interface ServicesRenderProps {
|
|
39
|
+
/** Array of services */
|
|
40
|
+
services: services.Service[];
|
|
41
|
+
/** Whether services are currently loading */
|
|
42
|
+
isLoading: boolean;
|
|
43
|
+
/** Error message, or null if no error */
|
|
44
|
+
error: string | null;
|
|
45
|
+
/** Current query options (appId, filters, sort) */
|
|
46
|
+
queryOptions: QueryOptions;
|
|
47
|
+
/** Pagination metadata (limit, offset, count, hasNext) */
|
|
48
|
+
pagingMetadata: PagingMetadata;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Component that provides services list data through render props.
|
|
52
|
+
* Exposes services, loading state, error, query options, and pagination metadata (including hasNext flag).
|
|
53
|
+
*
|
|
54
|
+
* @component
|
|
55
|
+
* @example
|
|
56
|
+
* ```tsx
|
|
57
|
+
* <ServiceList.Services>
|
|
58
|
+
* {({ services, isLoading, error, pagingMetadata }) => {
|
|
59
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
60
|
+
* if (error) return <div>Error: {error}</div>;
|
|
61
|
+
* return (
|
|
62
|
+
* <div>
|
|
63
|
+
* {services.map(service => (
|
|
64
|
+
* <div key={service._id}>{service.name}</div>
|
|
65
|
+
* ))}
|
|
66
|
+
* {pagingMetadata.hasNext && (
|
|
67
|
+
* <button>Load More Services</button>
|
|
68
|
+
* )}
|
|
69
|
+
* </div>
|
|
70
|
+
* );
|
|
71
|
+
* }}
|
|
72
|
+
* </ServiceList.Services>
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export declare function Services(props: ServicesProps): React.ReactNode;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useService, WixServices } from '@wix/services-manager-react';
|
|
3
|
+
import { createServicesMap } from '@wix/services-manager';
|
|
4
|
+
import { ServiceListServiceDefinition, ServiceListService, } from '../../../services/service-list/service-list.js';
|
|
5
|
+
/**
|
|
6
|
+
* Root component that provides ServiceList service context.
|
|
7
|
+
*
|
|
8
|
+
* @component
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <ServiceList.Root serviceListConfig={{ services: myServices }}>
|
|
12
|
+
* {children}
|
|
13
|
+
* </ServiceList.Root>
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function Root(props) {
|
|
17
|
+
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(ServiceListServiceDefinition, ServiceListService, props.serviceListConfig), children: props.children }));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Component that provides services list data through render props.
|
|
21
|
+
* Exposes services, loading state, error, query options, and pagination metadata (including hasNext flag).
|
|
22
|
+
*
|
|
23
|
+
* @component
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <ServiceList.Services>
|
|
27
|
+
* {({ services, isLoading, error, pagingMetadata }) => {
|
|
28
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
29
|
+
* if (error) return <div>Error: {error}</div>;
|
|
30
|
+
* return (
|
|
31
|
+
* <div>
|
|
32
|
+
* {services.map(service => (
|
|
33
|
+
* <div key={service._id}>{service.name}</div>
|
|
34
|
+
* ))}
|
|
35
|
+
* {pagingMetadata.hasNext && (
|
|
36
|
+
* <button>Load More Services</button>
|
|
37
|
+
* )}
|
|
38
|
+
* </div>
|
|
39
|
+
* );
|
|
40
|
+
* }}
|
|
41
|
+
* </ServiceList.Services>
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function Services(props) {
|
|
45
|
+
const serviceListService = useService(ServiceListServiceDefinition);
|
|
46
|
+
const services = serviceListService.servicesSignal.get();
|
|
47
|
+
const isLoading = serviceListService.isLoadingSignal.get();
|
|
48
|
+
const error = serviceListService.errorSignal.get();
|
|
49
|
+
const queryOptions = serviceListService.queryOptionsSignal.get();
|
|
50
|
+
const pagingMetadata = serviceListService.pagingMetadataSignal.get();
|
|
51
|
+
return props.children({
|
|
52
|
+
services,
|
|
53
|
+
isLoading,
|
|
54
|
+
error,
|
|
55
|
+
queryOptions,
|
|
56
|
+
pagingMetadata,
|
|
57
|
+
});
|
|
58
|
+
}
|
package/cjs/dist/react/index.js
CHANGED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Location - Headless component for displaying service location information
|
|
3
|
+
* Provides components for displaying location type and address
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import * as CoreLocation from '../core/location/Location.js';
|
|
7
|
+
import { AsChildChildren } from '@wix/headless-utils/react';
|
|
8
|
+
import type { services } from '@wix/bookings';
|
|
9
|
+
/**
|
|
10
|
+
* Re-export AddressData type from core for convenience
|
|
11
|
+
*/
|
|
12
|
+
export type { AddressData } from '../core/location/Location.js';
|
|
13
|
+
/**
|
|
14
|
+
* Props for Location.Root component
|
|
15
|
+
*/
|
|
16
|
+
export interface LocationRootProps {
|
|
17
|
+
location: NonNullable<services.Service['locations']>[number];
|
|
18
|
+
asChild?: boolean;
|
|
19
|
+
children?: React.ReactNode | AsChildChildren<{
|
|
20
|
+
locationType: services.LocationType;
|
|
21
|
+
address: CoreLocation.AddressData | null;
|
|
22
|
+
}>;
|
|
23
|
+
className?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Root component that provides location context and handles location type detection
|
|
27
|
+
* and address parsing.
|
|
28
|
+
*
|
|
29
|
+
* @component
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* import { Location } from '@wix/bookings/components';
|
|
33
|
+
*
|
|
34
|
+
* // Default usage - automatically renders Address.Formatted
|
|
35
|
+
* function ServiceLocations({ location }) {
|
|
36
|
+
* return (
|
|
37
|
+
* <Location.Root location={location} />
|
|
38
|
+
* );
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```tsx
|
|
44
|
+
* // With asChild to access location data
|
|
45
|
+
* <Location.Root location={location} asChild>
|
|
46
|
+
* {({ locationType, address }) => (
|
|
47
|
+
* <div>
|
|
48
|
+
* <span className="badge">{locationType}</span>
|
|
49
|
+
* {address && (
|
|
50
|
+
* <Address.Root address={address}>
|
|
51
|
+
* <Address.Formatted />
|
|
52
|
+
* </Address.Root>
|
|
53
|
+
* )}
|
|
54
|
+
* </div>
|
|
55
|
+
* )}
|
|
56
|
+
* </Location.Root>
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* // Conditional rendering based on location type
|
|
62
|
+
* <Location.Root location={location} asChild>
|
|
63
|
+
* {({ locationType, address }) => (
|
|
64
|
+
* locationType === 'customer' ? (
|
|
65
|
+
* <span className="text-primary">At your location</span>
|
|
66
|
+
* ) : (
|
|
67
|
+
* address && (
|
|
68
|
+
* <Address.Root address={address}>
|
|
69
|
+
* <Address.Formatted />
|
|
70
|
+
* </Address.Root>
|
|
71
|
+
* )
|
|
72
|
+
* )
|
|
73
|
+
* )}
|
|
74
|
+
* </Location.Root>
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare const Root: React.ForwardRefExoticComponent<LocationRootProps & React.RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Location - Headless component for displaying service location information
|
|
4
|
+
* Provides components for displaying location type and address
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import * as CoreLocation from '../core/location/Location.js';
|
|
8
|
+
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
9
|
+
import { Address } from '@wix/headless-components/react';
|
|
10
|
+
// ==========================================
|
|
11
|
+
// TestIds Enum
|
|
12
|
+
// ==========================================
|
|
13
|
+
var TestIds;
|
|
14
|
+
(function (TestIds) {
|
|
15
|
+
TestIds["locationRoot"] = "location-root";
|
|
16
|
+
})(TestIds || (TestIds = {}));
|
|
17
|
+
// ==========================================
|
|
18
|
+
// Components
|
|
19
|
+
// ==========================================
|
|
20
|
+
/**
|
|
21
|
+
* Root component that provides location context and handles location type detection
|
|
22
|
+
* and address parsing.
|
|
23
|
+
*
|
|
24
|
+
* @component
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* import { Location } from '@wix/bookings/components';
|
|
28
|
+
*
|
|
29
|
+
* // Default usage - automatically renders Address.Formatted
|
|
30
|
+
* function ServiceLocations({ location }) {
|
|
31
|
+
* return (
|
|
32
|
+
* <Location.Root location={location} />
|
|
33
|
+
* );
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```tsx
|
|
39
|
+
* // With asChild to access location data
|
|
40
|
+
* <Location.Root location={location} asChild>
|
|
41
|
+
* {({ locationType, address }) => (
|
|
42
|
+
* <div>
|
|
43
|
+
* <span className="badge">{locationType}</span>
|
|
44
|
+
* {address && (
|
|
45
|
+
* <Address.Root address={address}>
|
|
46
|
+
* <Address.Formatted />
|
|
47
|
+
* </Address.Root>
|
|
48
|
+
* )}
|
|
49
|
+
* </div>
|
|
50
|
+
* )}
|
|
51
|
+
* </Location.Root>
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* // Conditional rendering based on location type
|
|
57
|
+
* <Location.Root location={location} asChild>
|
|
58
|
+
* {({ locationType, address }) => (
|
|
59
|
+
* locationType === 'customer' ? (
|
|
60
|
+
* <span className="text-primary">At your location</span>
|
|
61
|
+
* ) : (
|
|
62
|
+
* address && (
|
|
63
|
+
* <Address.Root address={address}>
|
|
64
|
+
* <Address.Formatted />
|
|
65
|
+
* </Address.Root>
|
|
66
|
+
* )
|
|
67
|
+
* )
|
|
68
|
+
* )}
|
|
69
|
+
* </Location.Root>
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export const Root = React.forwardRef((props, ref) => {
|
|
73
|
+
const { location, asChild, children, className, ...attrs } = props;
|
|
74
|
+
return (_jsx(CoreLocation.Location, { location: location, children: ({ locationType, address }) => {
|
|
75
|
+
// If asChild is used with custom children, always pass location data to children
|
|
76
|
+
if (asChild && children) {
|
|
77
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.locationRoot, "data-location-type": locationType, customElement: children, customElementProps: { locationType, address }, ...attrs, children: address ? (_jsx(Address.Root, { address: address, children: _jsx(Address.Formatted, {}) })) : null }));
|
|
78
|
+
}
|
|
79
|
+
// Default rendering: return null if no address data
|
|
80
|
+
if (!address) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
// Default rendering with Address.Formatted and optional children
|
|
84
|
+
return (_jsxs("span", { ref: ref, "data-testid": TestIds.locationRoot, "data-location-type": locationType, className: className, ...attrs, children: [_jsx(Address.Root, { address: address, children: _jsx(Address.Formatted, {}) }), typeof children !== 'function'
|
|
85
|
+
? children
|
|
86
|
+
: null] }));
|
|
87
|
+
} }));
|
|
88
|
+
});
|
|
89
|
+
Root.displayName = 'Location.Root';
|