@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* Service - High-level component for displaying service information
|
|
4
4
|
* Provides components for displaying service details and booking actions
|
|
@@ -6,14 +6,49 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
import * as CoreService from '../core/service/Service.js';
|
|
8
8
|
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
9
|
+
import { Money, GenericList } from '@wix/headless-components/react';
|
|
10
|
+
import { WixMediaImage } from '@wix/headless-media/react';
|
|
11
|
+
import { MediaGallery } from '@wix/headless-media/react';
|
|
12
|
+
import { services } from '@wix/bookings';
|
|
13
|
+
import * as Location from '../location/Location.js';
|
|
9
14
|
var TestIds;
|
|
10
15
|
(function (TestIds) {
|
|
11
16
|
TestIds["serviceRoot"] = "service-root";
|
|
12
17
|
TestIds["serviceName"] = "service-name";
|
|
13
18
|
TestIds["serviceDescription"] = "service-description";
|
|
19
|
+
TestIds["servicePrice"] = "service-price";
|
|
20
|
+
TestIds["serviceTagline"] = "service-tagline";
|
|
21
|
+
TestIds["serviceDurationInMinutes"] = "service-duration-in-minutes";
|
|
22
|
+
TestIds["serviceType"] = "service-type";
|
|
23
|
+
TestIds["serviceCategory"] = "service-category";
|
|
24
|
+
TestIds["serviceLocations"] = "service-locations";
|
|
25
|
+
TestIds["serviceLocation"] = "service-location";
|
|
26
|
+
TestIds["serviceLocationRepeater"] = "service-location-repeater";
|
|
27
|
+
TestIds["locationRoot"] = "location-root";
|
|
28
|
+
TestIds["serviceStaffMembers"] = "service-staff-members";
|
|
29
|
+
TestIds["serviceStaffMemberRepeater"] = "service-staff-member-repeater";
|
|
30
|
+
TestIds["serviceMedia"] = "service-media";
|
|
31
|
+
TestIds["serviceMainMedia"] = "service-main-media";
|
|
32
|
+
TestIds["serviceCoverMedia"] = "service-cover-media";
|
|
33
|
+
TestIds["serviceMediaItems"] = "service-media-items";
|
|
34
|
+
TestIds["serviceSchedule"] = "service-schedule";
|
|
35
|
+
TestIds["serviceDefaultCapacity"] = "service-default-capacity";
|
|
36
|
+
TestIds["serviceRaw"] = "service-raw";
|
|
14
37
|
TestIds["serviceActionSelect"] = "service-action-select";
|
|
15
38
|
TestIds["serviceActionAdd"] = "service-action-add";
|
|
16
39
|
TestIds["serviceActionRemove"] = "service-action-remove";
|
|
40
|
+
// Policy component TestIds
|
|
41
|
+
TestIds["servicePolicyLatestCancellationInMinutes"] = "service-policy-latest-cancellation-in-minutes";
|
|
42
|
+
TestIds["servicePolicyLatestBookingInMinutes"] = "service-policy-latest-booking-in-minutes";
|
|
43
|
+
TestIds["servicePolicyEarliestBookingInMinutes"] = "service-policy-earliest-booking-in-minutes";
|
|
44
|
+
TestIds["servicePolicyLatestRescheduleInMinutes"] = "service-policy-latest-reschedule-in-minutes";
|
|
45
|
+
TestIds["servicePolicyWaitlistCapacity"] = "service-policy-waitlist-capacity";
|
|
46
|
+
TestIds["servicePolicyBookAfterStartEnabled"] = "service-policy-book-after-start-enabled";
|
|
47
|
+
TestIds["servicePolicyMaxParticipantsPerBooking"] = "service-policy-max-participants-per-booking";
|
|
48
|
+
// Schedule component TestIds
|
|
49
|
+
TestIds["serviceScheduleFirstSessionStart"] = "service-schedule-first-session-start";
|
|
50
|
+
TestIds["serviceScheduleLastSessionEnd"] = "service-schedule-last-session-end";
|
|
51
|
+
TestIds["serviceScheduleSessionDuration"] = "service-schedule-session-duration";
|
|
17
52
|
})(TestIds || (TestIds = {}));
|
|
18
53
|
/**
|
|
19
54
|
* Root component that provides service context to the entire app.
|
|
@@ -35,8 +70,8 @@ var TestIds;
|
|
|
35
70
|
* ```
|
|
36
71
|
*/
|
|
37
72
|
export const Root = React.forwardRef((props, ref) => {
|
|
38
|
-
const { children, service, asChild, className, ...attrs } = props;
|
|
39
|
-
return (_jsx(CoreService.Root, { serviceServiceConfig: { service }, children: _jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceRoot,
|
|
73
|
+
const { children, service, appId, asChild, className, ...attrs } = props;
|
|
74
|
+
return (_jsx(CoreService.Root, { serviceServiceConfig: { service, appId }, children: ({ selected, bookable }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceRoot, "data-selected": selected, "data-bookable": bookable, customElement: children, customElementProps: { selected, bookable }, ...attrs, children: children })) }));
|
|
40
75
|
});
|
|
41
76
|
Root.displayName = 'Service.Root';
|
|
42
77
|
/**
|
|
@@ -88,6 +123,595 @@ export const Description = React.forwardRef((props, ref) => {
|
|
|
88
123
|
return (_jsx(CoreService.Info, { children: ({ description }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceDescription, customElement: children, customElementProps: { description }, children: _jsx("div", { children: description }) })) }));
|
|
89
124
|
});
|
|
90
125
|
Description.displayName = 'Service.Description';
|
|
126
|
+
/**
|
|
127
|
+
* Displays the service price using the Money component with customizable rendering.
|
|
128
|
+
* Renders different defaults based on rate type:
|
|
129
|
+
* - FIXED: Shows formatted price (e.g., '$50.00')
|
|
130
|
+
* - VARIED: Shows price range (e.g., '$30.00 - $50.00')
|
|
131
|
+
* - CUSTOM: Shows custom description text
|
|
132
|
+
* - NO_FEE: Shows zero price (e.g., '$0.00')
|
|
133
|
+
*
|
|
134
|
+
* @component
|
|
135
|
+
* @example
|
|
136
|
+
* ```tsx
|
|
137
|
+
* // Default usage - renders based on rate type
|
|
138
|
+
* <Service.Price className="text-3xl font-bold" />
|
|
139
|
+
*
|
|
140
|
+
* // Custom rendering with full price data
|
|
141
|
+
* <Service.Price asChild>
|
|
142
|
+
* {({ rateType, money, minPrice, maxPrice, priceDescription, hasAddOns, hasPricingPlans }) => (
|
|
143
|
+
* <div>
|
|
144
|
+
* {rateType === 'FIXED' && money && <Money money={money} />}
|
|
145
|
+
* {rateType === 'VARIED' && minPrice && maxPrice && (
|
|
146
|
+
* <span><Money money={minPrice} /> - <Money money={maxPrice} /></span>
|
|
147
|
+
* )}
|
|
148
|
+
* {rateType === 'CUSTOM' && priceDescription && <span>{priceDescription}</span>}
|
|
149
|
+
* {rateType === 'NO_FEE' && money && <Money money={money} />}
|
|
150
|
+
* {hasPricingPlans && <span>Pricing plans available</span>}
|
|
151
|
+
* </div>
|
|
152
|
+
* )}
|
|
153
|
+
* </Service.Price>
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
export const Price = React.forwardRef((props, ref) => {
|
|
157
|
+
const { asChild, children, className } = props;
|
|
158
|
+
return (_jsx(CoreService.Price, { children: (childProps) => {
|
|
159
|
+
const { rateType, money, minPrice, maxPrice, priceDescription } = childProps;
|
|
160
|
+
// Default rendering based on rate type
|
|
161
|
+
const renderDefaultPrice = () => {
|
|
162
|
+
switch (rateType) {
|
|
163
|
+
case services.RateType.FIXED:
|
|
164
|
+
return money ? (_jsx(Money, { money: money, className: className })) : null;
|
|
165
|
+
case services.RateType.VARIED:
|
|
166
|
+
if (minPrice && maxPrice) {
|
|
167
|
+
return (_jsxs("span", { className: className, "data-testid": TestIds.servicePrice, children: [_jsx(Money, { money: minPrice }), " - ", _jsx(Money, { money: maxPrice })] }));
|
|
168
|
+
}
|
|
169
|
+
// Fallback to defaultPrice if min/max not available
|
|
170
|
+
return money ? (_jsx(Money, { money: money, className: className })) : null;
|
|
171
|
+
case services.RateType.CUSTOM:
|
|
172
|
+
return priceDescription ? (_jsx("span", { className: className, "data-testid": TestIds.servicePrice, children: priceDescription })) : null;
|
|
173
|
+
case services.RateType.NO_FEE:
|
|
174
|
+
return money ? (_jsx(Money, { money: money, className: className })) : null;
|
|
175
|
+
default:
|
|
176
|
+
// UNKNOWN_RATE_TYPE or undefined
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.servicePrice, customElement: children, customElementProps: childProps, children: renderDefaultPrice() }));
|
|
181
|
+
} }));
|
|
182
|
+
});
|
|
183
|
+
Price.displayName = 'Service.Price';
|
|
184
|
+
/**
|
|
185
|
+
* Displays the service tagline with customizable rendering.
|
|
186
|
+
*
|
|
187
|
+
* @component
|
|
188
|
+
* @example
|
|
189
|
+
* ```tsx
|
|
190
|
+
* // Default usage
|
|
191
|
+
* <Service.Tagline className="text-lg text-secondary-foreground" />
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```tsx
|
|
196
|
+
* // asChild with primitive element
|
|
197
|
+
* <Service.Tagline asChild>
|
|
198
|
+
* <p className="italic text-secondary-foreground" />
|
|
199
|
+
* </Service.Tagline>
|
|
200
|
+
* ```
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```tsx
|
|
204
|
+
* // asChild with custom component accessing tagline data
|
|
205
|
+
* <Service.Tagline asChild>
|
|
206
|
+
* {React.forwardRef(({tagline, ...props}, ref) => (
|
|
207
|
+
* <blockquote ref={ref} {...props} className="border-l-4 pl-4">
|
|
208
|
+
* "{tagline}"
|
|
209
|
+
* </blockquote>
|
|
210
|
+
* ))}
|
|
211
|
+
* </Service.Tagline>
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
export const Tagline = React.forwardRef((props, ref) => {
|
|
215
|
+
const { asChild, children, className } = props;
|
|
216
|
+
return (_jsx(CoreService.Info, { children: ({ tagline }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceTagline, customElement: children, customElementProps: { tagline }, children: tagline ? _jsx("p", { children: tagline }) : null })) }));
|
|
217
|
+
});
|
|
218
|
+
Tagline.displayName = 'Service.Tagline';
|
|
219
|
+
/**
|
|
220
|
+
* Displays the service duration in minutes (raw number) with customizable rendering.
|
|
221
|
+
* Returns the duration as a numeric value representing minutes.
|
|
222
|
+
*
|
|
223
|
+
* @component
|
|
224
|
+
* @example
|
|
225
|
+
* ```tsx
|
|
226
|
+
* // Default usage - displays raw minutes
|
|
227
|
+
* <Service.DurationInMinutes className="text-base text-secondary-foreground" />
|
|
228
|
+
* ```
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* ```tsx
|
|
232
|
+
* // asChild with primitive element
|
|
233
|
+
* <Service.DurationInMinutes asChild>
|
|
234
|
+
* <span className="font-semibold" />
|
|
235
|
+
* </Service.DurationInMinutes>
|
|
236
|
+
* ```
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```tsx
|
|
240
|
+
* // asChild with custom component to format duration
|
|
241
|
+
* <Service.DurationInMinutes asChild>
|
|
242
|
+
* {React.forwardRef(({duration, ...props}, ref) => (
|
|
243
|
+
* <span ref={ref} {...props}>
|
|
244
|
+
* {duration} minutes
|
|
245
|
+
* </span>
|
|
246
|
+
* ))}
|
|
247
|
+
* </Service.DurationInMinutes>
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
export const DurationInMinutes = React.forwardRef((props, ref) => {
|
|
251
|
+
const { asChild, children, className } = props;
|
|
252
|
+
return (_jsx(CoreService.Info, { children: ({ duration }) => {
|
|
253
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceDurationInMinutes, customElement: children, customElementProps: { duration }, children: duration ? _jsx("span", { children: duration }) : null }));
|
|
254
|
+
} }));
|
|
255
|
+
});
|
|
256
|
+
DurationInMinutes.displayName = 'Service.DurationInMinutes';
|
|
257
|
+
/**
|
|
258
|
+
* Displays the service type (APPOINTMENT, CLASS, COURSE, etc.) with customizable rendering.
|
|
259
|
+
*
|
|
260
|
+
* @component
|
|
261
|
+
* @example
|
|
262
|
+
* ```tsx
|
|
263
|
+
* // Default usage
|
|
264
|
+
* <Service.Type className="text-sm text-secondary-foreground uppercase" />
|
|
265
|
+
* ```
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```tsx
|
|
269
|
+
* // asChild with badge styling
|
|
270
|
+
* <Service.Type asChild>
|
|
271
|
+
* <span className="px-2 py-1 bg-secondary text-secondary-foreground rounded-full text-xs" />
|
|
272
|
+
* </Service.Type>
|
|
273
|
+
* ```
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```tsx
|
|
277
|
+
* // asChild with custom component to format type
|
|
278
|
+
* <Service.Type asChild>
|
|
279
|
+
* {React.forwardRef(({type, ...props}, ref) => {
|
|
280
|
+
* const label = {
|
|
281
|
+
* APPOINTMENT: '1-on-1',
|
|
282
|
+
* CLASS: 'Group Class',
|
|
283
|
+
* COURSE: 'Course',
|
|
284
|
+
* }[type] || type;
|
|
285
|
+
* return <span ref={ref} {...props}>{label}</span>;
|
|
286
|
+
* })}
|
|
287
|
+
* </Service.Type>
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
export const Type = React.forwardRef((props, ref) => {
|
|
291
|
+
const { asChild, children, className } = props;
|
|
292
|
+
return (_jsx(CoreService.Info, { children: ({ type }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceType, customElement: children, customElementProps: { type }, children: type ? _jsx("span", { children: type }) : null })) }));
|
|
293
|
+
});
|
|
294
|
+
Type.displayName = 'Service.Type';
|
|
295
|
+
/**
|
|
296
|
+
* Displays the service category with customizable rendering.
|
|
297
|
+
*
|
|
298
|
+
* @component
|
|
299
|
+
* @example
|
|
300
|
+
* ```tsx
|
|
301
|
+
* // Default usage
|
|
302
|
+
* <Service.Category className="text-sm text-secondary-foreground" />
|
|
303
|
+
* ```
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```tsx
|
|
307
|
+
* // asChild with link styling
|
|
308
|
+
* <Service.Category asChild>
|
|
309
|
+
* <a href="#" className="text-primary hover:underline" />
|
|
310
|
+
* </Service.Category>
|
|
311
|
+
* ```
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* ```tsx
|
|
315
|
+
* // asChild with custom component accessing category data
|
|
316
|
+
* <Service.Category asChild>
|
|
317
|
+
* {React.forwardRef(({category, ...props}, ref) => (
|
|
318
|
+
* <a
|
|
319
|
+
* ref={ref}
|
|
320
|
+
* {...props}
|
|
321
|
+
* href={`/category/${category._id}`}
|
|
322
|
+
* className="text-primary hover:underline"
|
|
323
|
+
* >
|
|
324
|
+
* {category.name}
|
|
325
|
+
* </a>
|
|
326
|
+
* ))}
|
|
327
|
+
* </Service.Category>
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
330
|
+
export const Category = React.forwardRef((props, ref) => {
|
|
331
|
+
const { asChild, children, className } = props;
|
|
332
|
+
return (_jsx(CoreService.Info, { children: ({ category }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceCategory, customElement: children, customElementProps: { category }, children: category?.name ? _jsx("span", { children: category.name }) : null })) }));
|
|
333
|
+
});
|
|
334
|
+
Category.displayName = 'Service.Category';
|
|
335
|
+
/**
|
|
336
|
+
* Container for service locations list (Container Level).
|
|
337
|
+
* Follows the 3-level List/Options/Repeater pattern.
|
|
338
|
+
* Provides context and doesn't render when there are no locations.
|
|
339
|
+
*
|
|
340
|
+
* @component
|
|
341
|
+
* @example
|
|
342
|
+
* ```tsx
|
|
343
|
+
* // Basic usage with 3-level pattern
|
|
344
|
+
* <Service.Locations>
|
|
345
|
+
* <Service.Locations.List emptyState={<div>No locations available</div>}>
|
|
346
|
+
* <Service.Locations.LocationRepeater>
|
|
347
|
+
* {({ location }) => (
|
|
348
|
+
* <div>
|
|
349
|
+
* <span>{location.name}</span>
|
|
350
|
+
* <Address.Root address={location.address}>
|
|
351
|
+
* <Address.Formatted />
|
|
352
|
+
* </Address.Root>
|
|
353
|
+
* </div>
|
|
354
|
+
* )}
|
|
355
|
+
* </Service.Locations.LocationRepeater>
|
|
356
|
+
* </Service.Locations.List>
|
|
357
|
+
* </Service.Locations>
|
|
358
|
+
*
|
|
359
|
+
* // With asChild pattern for custom container
|
|
360
|
+
* <Service.Locations asChild>
|
|
361
|
+
* <ul className="locations-list">
|
|
362
|
+
* <Service.Locations.List>
|
|
363
|
+
* <Service.Locations.LocationRepeater>
|
|
364
|
+
* {({ location }) => <li>{location.name}</li>}
|
|
365
|
+
* </Service.Locations.LocationRepeater>
|
|
366
|
+
* </Service.Locations.List>
|
|
367
|
+
* </ul>
|
|
368
|
+
* </Service.Locations>
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
const LocationsBase = React.forwardRef((props, ref) => {
|
|
372
|
+
const { asChild, children, className, ...attributes } = props;
|
|
373
|
+
return (_jsx(CoreService.Info, { children: ({ locations }) => {
|
|
374
|
+
// Container level: don't render if no locations
|
|
375
|
+
if (!locations || locations.length === 0) {
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
// Map locations to include required id field for GenericList
|
|
379
|
+
const items = locations.map((location, index) => ({
|
|
380
|
+
...location,
|
|
381
|
+
id: location._id || String(index),
|
|
382
|
+
}));
|
|
383
|
+
return (_jsx(GenericList.Root, { items: items, children: _jsx(AsChildSlot, { ...attributes, ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceLocations, customElement: children, children: _jsx("div", { children: React.isValidElement(children) ? children : null }) }) }));
|
|
384
|
+
} }));
|
|
385
|
+
});
|
|
386
|
+
LocationsBase.displayName = 'Service.Locations';
|
|
387
|
+
/**
|
|
388
|
+
* List container for locations with empty state support (List Container Level).
|
|
389
|
+
* Renders emptyState when no locations, otherwise renders children.
|
|
390
|
+
*
|
|
391
|
+
* @component
|
|
392
|
+
* @example
|
|
393
|
+
* ```tsx
|
|
394
|
+
* <Service.Locations.List emptyState={<div>No locations available</div>}>
|
|
395
|
+
* <Service.Locations.LocationRepeater />
|
|
396
|
+
* </Service.Locations.List>
|
|
397
|
+
* ```
|
|
398
|
+
*/
|
|
399
|
+
export const LocationsList = React.forwardRef((props, ref) => {
|
|
400
|
+
const { children, emptyState, className, ...otherProps } = props;
|
|
401
|
+
return (_jsx(GenericList.Items, { ref: ref, emptyState: emptyState, className: className, ...otherProps, children: children }));
|
|
402
|
+
});
|
|
403
|
+
LocationsList.displayName = 'Service.Locations.List';
|
|
404
|
+
/**
|
|
405
|
+
* Repeater component that renders Location.Root for each location.
|
|
406
|
+
* Supports asChild pattern for custom rendering.
|
|
407
|
+
*
|
|
408
|
+
* @component
|
|
409
|
+
* @example
|
|
410
|
+
* ```tsx
|
|
411
|
+
* // Standard usage - renders Location.Root for each location
|
|
412
|
+
* <Service.Locations.LocationRepeater>
|
|
413
|
+
* <span className="location-badge">📍</span>
|
|
414
|
+
* </Service.Locations.LocationRepeater>
|
|
415
|
+
*
|
|
416
|
+
* // AsChild usage with custom numbered list
|
|
417
|
+
* <Service.Locations.LocationRepeater asChild>
|
|
418
|
+
* {({ items, itemWrapper }) => (
|
|
419
|
+
* <ol>
|
|
420
|
+
* {items.map((item, index) => (
|
|
421
|
+
* <li key={item.id}>
|
|
422
|
+
* {index + 1}. {itemWrapper({ item, index, children: null })}
|
|
423
|
+
* </li>
|
|
424
|
+
* ))}
|
|
425
|
+
* </ol>
|
|
426
|
+
* )}
|
|
427
|
+
* </Service.Locations.LocationRepeater>
|
|
428
|
+
* ```
|
|
429
|
+
*/
|
|
430
|
+
export const LocationRepeater = React.forwardRef((props, ref) => {
|
|
431
|
+
const { children, asChild } = props;
|
|
432
|
+
// Custom itemWrapper that renders Location.Root for each location
|
|
433
|
+
const locationItemWrapper = ({ item: location, children: itemChildren, }) => {
|
|
434
|
+
return (_jsx(Location.Root, { location: location, "data-testid": TestIds.serviceLocationRepeater, children: itemChildren || undefined }, location.id));
|
|
435
|
+
};
|
|
436
|
+
return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: locationItemWrapper, asChild: asChild, children: children }));
|
|
437
|
+
});
|
|
438
|
+
LocationRepeater.displayName = 'Service.Locations.LocationRepeater';
|
|
439
|
+
/**
|
|
440
|
+
* Container for service staff members list (Container Level).
|
|
441
|
+
* Follows the 3-level List/Options/Repeater pattern.
|
|
442
|
+
* Provides context and doesn't render when there are no staff members.
|
|
443
|
+
*
|
|
444
|
+
* @component
|
|
445
|
+
* @example
|
|
446
|
+
* ```tsx
|
|
447
|
+
* // Basic usage with 3-level pattern
|
|
448
|
+
* <Service.StaffMembers>
|
|
449
|
+
* <Service.StaffMembers.List emptyState={<div>No staff assigned</div>}>
|
|
450
|
+
* <Service.StaffMembers.StaffMemberRepeater>
|
|
451
|
+
* {({ staffMember }) => (
|
|
452
|
+
* <div className="staff-card">
|
|
453
|
+
* <img src={staffMember.mainMedia?.image} alt={staffMember.name} />
|
|
454
|
+
* <span>{staffMember.name}</span>
|
|
455
|
+
* </div>
|
|
456
|
+
* )}
|
|
457
|
+
* </Service.StaffMembers.StaffMemberRepeater>
|
|
458
|
+
* </Service.StaffMembers.List>
|
|
459
|
+
* </Service.StaffMembers>
|
|
460
|
+
*
|
|
461
|
+
* // With asChild pattern for custom container
|
|
462
|
+
* <Service.StaffMembers asChild>
|
|
463
|
+
* <ul className="staff-list">
|
|
464
|
+
* <Service.StaffMembers.List>
|
|
465
|
+
* <Service.StaffMembers.StaffMemberRepeater>
|
|
466
|
+
* {({ staffMember }) => <li>{staffMember.name}</li>}
|
|
467
|
+
* </Service.StaffMembers.StaffMemberRepeater>
|
|
468
|
+
* </Service.StaffMembers.List>
|
|
469
|
+
* </ul>
|
|
470
|
+
* </Service.StaffMembers>
|
|
471
|
+
* ```
|
|
472
|
+
*/
|
|
473
|
+
export const StaffMembersBase = React.forwardRef((props, ref) => {
|
|
474
|
+
const { asChild, children, className, ...attributes } = props;
|
|
475
|
+
return (_jsx(CoreService.Info, { children: ({ staff }) => {
|
|
476
|
+
// Container level: don't render if no staff members
|
|
477
|
+
if (!staff || staff.length === 0) {
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
// Map staff to include required id field for GenericList
|
|
481
|
+
const items = staff.map((member, index) => ({
|
|
482
|
+
...member,
|
|
483
|
+
id: member._id || String(index),
|
|
484
|
+
}));
|
|
485
|
+
return (_jsx(GenericList.Root, { items: items, children: _jsx(AsChildSlot, { ...attributes, ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceStaffMembers, customElement: children, children: _jsx("div", { children: React.isValidElement(children) ? children : null }) }) }));
|
|
486
|
+
} }));
|
|
487
|
+
});
|
|
488
|
+
StaffMembersBase.displayName = 'Service.StaffMembers';
|
|
489
|
+
/**
|
|
490
|
+
* List container for staff members with empty state support (List Container Level).
|
|
491
|
+
* Renders emptyState when no staff members, otherwise renders children.
|
|
492
|
+
*
|
|
493
|
+
* @component
|
|
494
|
+
* @example
|
|
495
|
+
* ```tsx
|
|
496
|
+
* <Service.StaffMembers.List emptyState={<div>No staff assigned</div>}>
|
|
497
|
+
* <Service.StaffMembers.StaffMemberRepeater />
|
|
498
|
+
* </Service.StaffMembers.List>
|
|
499
|
+
* ```
|
|
500
|
+
*/
|
|
501
|
+
export const StaffMembersList = React.forwardRef((props, ref) => {
|
|
502
|
+
const { children, emptyState, className, ...otherProps } = props;
|
|
503
|
+
return (_jsx(GenericList.Items, { ref: ref, emptyState: emptyState, className: className, ...otherProps, children: children }));
|
|
504
|
+
});
|
|
505
|
+
StaffMembersList.displayName = 'Service.StaffMembers.List';
|
|
506
|
+
/**
|
|
507
|
+
* Repeater component that renders staff member name for each staff member.
|
|
508
|
+
* Supports asChild pattern for custom rendering.
|
|
509
|
+
*
|
|
510
|
+
* @component
|
|
511
|
+
* @example
|
|
512
|
+
* ```tsx
|
|
513
|
+
* // Standard usage - renders staff member names
|
|
514
|
+
* <Service.StaffMembers.StaffMemberRepeater>
|
|
515
|
+
* <span className="staff-badge">👤</span>
|
|
516
|
+
* </Service.StaffMembers.StaffMemberRepeater>
|
|
517
|
+
*
|
|
518
|
+
* // AsChild usage with custom numbered list
|
|
519
|
+
* <Service.StaffMembers.StaffMemberRepeater asChild>
|
|
520
|
+
* {({ items, itemWrapper }) => (
|
|
521
|
+
* <ol>
|
|
522
|
+
* {items.map((item, index) => (
|
|
523
|
+
* <li key={item.id}>
|
|
524
|
+
* {index + 1}. {itemWrapper({ item, index, children: null })}
|
|
525
|
+
* </li>
|
|
526
|
+
* ))}
|
|
527
|
+
* </ol>
|
|
528
|
+
* )}
|
|
529
|
+
* </Service.StaffMembers.StaffMemberRepeater>
|
|
530
|
+
* ```
|
|
531
|
+
*/
|
|
532
|
+
export const StaffMemberRepeater = React.forwardRef((props, ref) => {
|
|
533
|
+
const { children, asChild } = props;
|
|
534
|
+
// Custom itemWrapper that renders staff member name
|
|
535
|
+
const staffMemberItemWrapper = ({ item: member, children: itemChildren, }) => {
|
|
536
|
+
return (_jsxs(React.Fragment, { children: [_jsx("span", { "data-testid": TestIds.serviceStaffMemberRepeater, children: member.name }), itemChildren] }, member.id));
|
|
537
|
+
};
|
|
538
|
+
// When asChild is true, provide custom render props
|
|
539
|
+
if (asChild && typeof children === 'function') {
|
|
540
|
+
return (_jsx(GenericList.Repeater, { ref: ref, asChild: true, itemWrapper: staffMemberItemWrapper, children: (genericProps) => {
|
|
541
|
+
const renderProps = {
|
|
542
|
+
items: genericProps.items,
|
|
543
|
+
itemWrapper: staffMemberItemWrapper,
|
|
544
|
+
};
|
|
545
|
+
return children(renderProps);
|
|
546
|
+
} }));
|
|
547
|
+
}
|
|
548
|
+
return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: staffMemberItemWrapper, children: children }));
|
|
549
|
+
});
|
|
550
|
+
StaffMemberRepeater.displayName = 'Service.StaffMembers.StaffMemberRepeater';
|
|
551
|
+
/**
|
|
552
|
+
* Displays the service main media image using WixMediaImage.
|
|
553
|
+
*
|
|
554
|
+
* @component
|
|
555
|
+
* @example
|
|
556
|
+
* ```tsx
|
|
557
|
+
* // Default usage
|
|
558
|
+
* <Service.MainMedia className="w-full h-64 object-cover rounded-lg" />
|
|
559
|
+
* ```
|
|
560
|
+
*
|
|
561
|
+
* @example
|
|
562
|
+
* ```tsx
|
|
563
|
+
* // asChild with primitive img element
|
|
564
|
+
* <Service.MainMedia asChild>
|
|
565
|
+
* <img className="w-full h-64 object-cover shadow-lg" />
|
|
566
|
+
* </Service.MainMedia>
|
|
567
|
+
* ```
|
|
568
|
+
*
|
|
569
|
+
* @example
|
|
570
|
+
* ```tsx
|
|
571
|
+
* // asChild with custom component accessing media data
|
|
572
|
+
* <Service.MainMedia asChild>
|
|
573
|
+
* {React.forwardRef(({media, ...props}, ref) => (
|
|
574
|
+
* <div ref={ref} {...props} className="relative aspect-video">
|
|
575
|
+
* <WixMediaImage media={media} className="w-full h-full object-cover" />
|
|
576
|
+
* <div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/50 p-4">
|
|
577
|
+
* <Service.Name className="text-primary-foreground" />
|
|
578
|
+
* </div>
|
|
579
|
+
* </div>
|
|
580
|
+
* ))}
|
|
581
|
+
* </Service.MainMedia>
|
|
582
|
+
* ```
|
|
583
|
+
*/
|
|
584
|
+
export const MainMedia = React.forwardRef((props, ref) => {
|
|
585
|
+
const { asChild, children, className } = props;
|
|
586
|
+
return (_jsx(CoreService.Info, { children: ({ mainMedia }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceMainMedia, customElement: children, customElementProps: { media: mainMedia }, children: mainMedia?.image ? _jsx(WixMediaImage, { media: mainMedia }) : null })) }));
|
|
587
|
+
});
|
|
588
|
+
MainMedia.displayName = 'Service.MainMedia';
|
|
589
|
+
/**
|
|
590
|
+
* Displays the service cover media image using WixMediaImage.
|
|
591
|
+
* The cover media is typically used as a hero/banner image.
|
|
592
|
+
*
|
|
593
|
+
* @component
|
|
594
|
+
* @example
|
|
595
|
+
* ```tsx
|
|
596
|
+
* // Default usage
|
|
597
|
+
* <Service.CoverMedia className="w-full h-96 object-cover" />
|
|
598
|
+
* ```
|
|
599
|
+
*
|
|
600
|
+
* @example
|
|
601
|
+
* ```tsx
|
|
602
|
+
* // asChild as a background image container
|
|
603
|
+
* <Service.CoverMedia asChild>
|
|
604
|
+
* <div className="w-full h-96 bg-cover bg-center" />
|
|
605
|
+
* </Service.CoverMedia>
|
|
606
|
+
* ```
|
|
607
|
+
*
|
|
608
|
+
* @example
|
|
609
|
+
* ```tsx
|
|
610
|
+
* // asChild with custom component accessing media data
|
|
611
|
+
* <Service.CoverMedia asChild>
|
|
612
|
+
* {React.forwardRef(({media, ...props}, ref) => (
|
|
613
|
+
* <header ref={ref} {...props} className="relative h-96">
|
|
614
|
+
* <WixMediaImage media={media} className="w-full h-full object-cover" />
|
|
615
|
+
* <div className="absolute inset-0 bg-black/40 flex items-center justify-center">
|
|
616
|
+
* <h1 className="text-4xl font-bold text-primary-foreground">
|
|
617
|
+
* <Service.Name />
|
|
618
|
+
* </h1>
|
|
619
|
+
* </div>
|
|
620
|
+
* </header>
|
|
621
|
+
* ))}
|
|
622
|
+
* </Service.CoverMedia>
|
|
623
|
+
* ```
|
|
624
|
+
*/
|
|
625
|
+
export const CoverMedia = React.forwardRef((props, ref) => {
|
|
626
|
+
const { asChild, children, className } = props;
|
|
627
|
+
return (_jsx(CoreService.Info, { children: ({ coverMedia }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceCoverMedia, customElement: children, customElementProps: { media: coverMedia }, children: coverMedia?.image ? _jsx(WixMediaImage, { media: coverMedia }) : null })) }));
|
|
628
|
+
});
|
|
629
|
+
CoverMedia.displayName = 'Service.CoverMedia';
|
|
630
|
+
/**
|
|
631
|
+
* Container for service media items gallery.
|
|
632
|
+
* Renders a MediaGallery.Root with the service media items.
|
|
633
|
+
* Supports autoPlay and infinite scroll options for carousel behavior.
|
|
634
|
+
*
|
|
635
|
+
* @component
|
|
636
|
+
* @example
|
|
637
|
+
* ```tsx
|
|
638
|
+
* // Basic usage with MediaGallery components
|
|
639
|
+
* <Service.MediaItems>
|
|
640
|
+
* <MediaGallery.Thumbnails>
|
|
641
|
+
* <MediaGallery.ThumbnailRepeater>
|
|
642
|
+
* {({ mediaItem, isActive }) => (
|
|
643
|
+
* <img
|
|
644
|
+
* src={mediaItem.url}
|
|
645
|
+
* alt={mediaItem.altText}
|
|
646
|
+
* className={isActive ? 'active' : ''}
|
|
647
|
+
* />
|
|
648
|
+
* )}
|
|
649
|
+
* </MediaGallery.ThumbnailRepeater>
|
|
650
|
+
* </MediaGallery.Thumbnails>
|
|
651
|
+
* </Service.MediaItems>
|
|
652
|
+
*
|
|
653
|
+
* // With autoPlay carousel
|
|
654
|
+
* <Service.MediaItems
|
|
655
|
+
* autoPlay={{ direction: 'forward', intervalMs: 3000 }}
|
|
656
|
+
* infinite
|
|
657
|
+
* >
|
|
658
|
+
* <MediaGallery.MainImage />
|
|
659
|
+
* <MediaGallery.Actions.Previous />
|
|
660
|
+
* <MediaGallery.Actions.Next />
|
|
661
|
+
* </Service.MediaItems>
|
|
662
|
+
*
|
|
663
|
+
* // Full gallery with thumbnails and navigation
|
|
664
|
+
* <Service.MediaItems infinite>
|
|
665
|
+
* <div className="gallery-container">
|
|
666
|
+
* <MediaGallery.MainImage className="main-image" />
|
|
667
|
+
* <div className="controls">
|
|
668
|
+
* <MediaGallery.Actions.Previous>Prev</MediaGallery.Actions.Previous>
|
|
669
|
+
* <MediaGallery.Actions.Next>Next</MediaGallery.Actions.Next>
|
|
670
|
+
* </div>
|
|
671
|
+
* <MediaGallery.Thumbnails className="thumbnails" />
|
|
672
|
+
* </div>
|
|
673
|
+
* </Service.MediaItems>
|
|
674
|
+
* ```
|
|
675
|
+
*/
|
|
676
|
+
export const MediaItems = React.forwardRef((props, ref) => {
|
|
677
|
+
const { children, infinite, autoPlay } = props;
|
|
678
|
+
return (_jsx(CoreService.Info, { children: ({ mediaItems }) => {
|
|
679
|
+
if (!mediaItems || mediaItems.length === 0)
|
|
680
|
+
return null;
|
|
681
|
+
const mediaGalleryServiceConfig = {
|
|
682
|
+
media: mediaItems,
|
|
683
|
+
infinite,
|
|
684
|
+
autoPlay,
|
|
685
|
+
};
|
|
686
|
+
const attributes = {
|
|
687
|
+
'data-testid': TestIds.serviceMediaItems,
|
|
688
|
+
};
|
|
689
|
+
return (_jsx("div", { ...attributes, ref: ref, children: _jsx(MediaGallery.Root, { mediaGalleryServiceConfig: mediaGalleryServiceConfig, children: children }) }));
|
|
690
|
+
} }));
|
|
691
|
+
});
|
|
692
|
+
MediaItems.displayName = 'Service.MediaItems';
|
|
693
|
+
/**
|
|
694
|
+
* Provides direct access to service object. Should be used only in rare cases.
|
|
695
|
+
*
|
|
696
|
+
* @component
|
|
697
|
+
* @example
|
|
698
|
+
* ```tsx
|
|
699
|
+
* <Service.Raw>
|
|
700
|
+
* {({ service, isLoading, error }) => (
|
|
701
|
+
* <div>
|
|
702
|
+
* {isLoading && <div>Loading...</div>}
|
|
703
|
+
* {error && <div>Error: {error}</div>}
|
|
704
|
+
* {service && <pre>{JSON.stringify(service, null, 2)}</pre>}
|
|
705
|
+
* </div>
|
|
706
|
+
* )}
|
|
707
|
+
* </Service.Raw>
|
|
708
|
+
* ```
|
|
709
|
+
*/
|
|
710
|
+
export const Raw = React.forwardRef((props, ref) => {
|
|
711
|
+
const { asChild, children, className } = props;
|
|
712
|
+
return (_jsx(CoreService.Service, { children: ({ service, isLoading, error }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceRaw, customElement: children, customElementProps: { service, isLoading, error }, children: _jsxs("div", { children: [isLoading && _jsx("div", { children: "Loading..." }), error && _jsxs("div", { children: ["Error: ", error] }), service && _jsx("pre", { children: JSON.stringify(service, null, 2) })] }) })) }));
|
|
713
|
+
});
|
|
714
|
+
Raw.displayName = 'Service.Raw';
|
|
91
715
|
/**
|
|
92
716
|
* Actions namespace with individual action components
|
|
93
717
|
*/
|
|
@@ -107,25 +731,36 @@ export var Actions;
|
|
|
107
731
|
* <Button variant="primary">Select Service</Button>
|
|
108
732
|
* </Service.Actions.Select>
|
|
109
733
|
*
|
|
110
|
-
* //
|
|
111
|
-
* <Service.Actions.Select
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* <Button variant="primary">Select Service</Button>
|
|
734
|
+
* // Using render prop pattern to access bookable state
|
|
735
|
+
* <Service.Actions.Select>
|
|
736
|
+
* {({ bookable, selected, onClick }) => (
|
|
737
|
+
* <button onClick={onClick} disabled={!bookable}>
|
|
738
|
+
* {selected ? 'Selected' : 'Select Service'}
|
|
739
|
+
* </button>
|
|
740
|
+
* )}
|
|
118
741
|
* </Service.Actions.Select>
|
|
119
742
|
* ```
|
|
120
743
|
*/
|
|
121
744
|
Actions.Select = React.forwardRef((props, ref) => {
|
|
122
|
-
const { asChild, children, className, label = 'Select Service'
|
|
123
|
-
return (_jsx(CoreService.Actions, { children: ({ select,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
745
|
+
const { asChild, children, className, label = 'Select Service' } = props;
|
|
746
|
+
return (_jsx(CoreService.Actions, { children: ({ select, rawService, bookable, selected, requiresAvailability, }) => {
|
|
747
|
+
// If children is a function, call it with bookable, selected, requiresAvailability and other props
|
|
748
|
+
if (typeof children === 'function') {
|
|
749
|
+
return children({
|
|
750
|
+
bookable,
|
|
751
|
+
selected,
|
|
752
|
+
requiresAvailability,
|
|
753
|
+
onClick: select,
|
|
754
|
+
service: rawService,
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceActionSelect, "data-selected": selected, "data-bookable": bookable, "data-requires-availability": requiresAvailability, customElement: children, customElementProps: {
|
|
758
|
+
onClick: select,
|
|
759
|
+
disabled: !bookable,
|
|
760
|
+
selected,
|
|
761
|
+
bookable,
|
|
762
|
+
requiresAvailability,
|
|
763
|
+
}, children: _jsx("button", { onClick: select, disabled: !bookable, "data-selected": selected, "data-bookable": bookable, "data-requires-availability": requiresAvailability, children: label }) }));
|
|
129
764
|
} }));
|
|
130
765
|
});
|
|
131
766
|
Actions.Select.displayName = 'Service.Actions.Select';
|
|
@@ -143,23 +778,38 @@ export var Actions;
|
|
|
143
778
|
* <Button variant="secondary">Add Service</Button>
|
|
144
779
|
* </Service.Actions.Add>
|
|
145
780
|
*
|
|
146
|
-
* //
|
|
147
|
-
* <Service.Actions.Add
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
781
|
+
* // Using render prop pattern to access bookable state
|
|
782
|
+
* <Service.Actions.Add>
|
|
783
|
+
* {({ bookable, selected, onClick }) => (
|
|
784
|
+
* <button onClick={onClick} disabled={!bookable}>
|
|
785
|
+
* {selected ? 'Added' : 'Add to Booking'}
|
|
786
|
+
* </button>
|
|
787
|
+
* )}
|
|
788
|
+
* </Service.Actions.Add>
|
|
153
789
|
* ```
|
|
154
790
|
*/
|
|
155
791
|
Actions.Add = React.forwardRef((props, ref) => {
|
|
156
|
-
const { asChild, children, className, label = 'Add Service'
|
|
157
|
-
return (_jsx(CoreService.Actions, { children: ({ add,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
792
|
+
const { asChild, children, className, label = 'Add Service' } = props;
|
|
793
|
+
return (_jsx(CoreService.Actions, { children: ({ add, rawService, bookable, selected, requiresAvailability }) => {
|
|
794
|
+
// If children is a function, call it with bookable, selected, requiresAvailability and other props
|
|
795
|
+
if (typeof children === 'function') {
|
|
796
|
+
return children({
|
|
797
|
+
bookable,
|
|
798
|
+
selected,
|
|
799
|
+
requiresAvailability,
|
|
800
|
+
onClick: add,
|
|
801
|
+
service: rawService,
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
// Disabled when already selected (can't add again) or not bookable
|
|
805
|
+
const isDisabled = selected || !bookable;
|
|
806
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceActionAdd, "data-selected": selected, "data-bookable": bookable, "data-requires-availability": requiresAvailability, customElement: children, customElementProps: {
|
|
807
|
+
onClick: add,
|
|
808
|
+
disabled: isDisabled,
|
|
809
|
+
selected,
|
|
810
|
+
bookable,
|
|
811
|
+
requiresAvailability,
|
|
812
|
+
}, children: _jsx("button", { onClick: add, disabled: isDisabled, "data-selected": selected, "data-bookable": bookable, "data-requires-availability": requiresAvailability, children: label }) }));
|
|
163
813
|
} }));
|
|
164
814
|
});
|
|
165
815
|
Actions.Add.displayName = 'Service.Actions.Add';
|
|
@@ -177,26 +827,389 @@ export var Actions;
|
|
|
177
827
|
* <Button variant="destructive">Remove Service</Button>
|
|
178
828
|
* </Service.Actions.Remove>
|
|
179
829
|
*
|
|
180
|
-
* //
|
|
181
|
-
* <Service.Actions.Remove
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
* <IconButton icon="trash" />
|
|
830
|
+
* // Using render prop pattern to access bookable state
|
|
831
|
+
* <Service.Actions.Remove>
|
|
832
|
+
* {({ bookable, selected, onClick }) => (
|
|
833
|
+
* <button onClick={onClick} disabled={!bookable}>
|
|
834
|
+
* Remove Service
|
|
835
|
+
* </button>
|
|
836
|
+
* )}
|
|
188
837
|
* </Service.Actions.Remove>
|
|
189
838
|
* ```
|
|
190
839
|
*/
|
|
191
840
|
Actions.Remove = React.forwardRef((props, ref) => {
|
|
192
|
-
const { asChild, children, className, label = 'Remove Service'
|
|
193
|
-
return (_jsx(CoreService.Actions, { children: ({ remove,
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
841
|
+
const { asChild, children, className, label = 'Remove Service' } = props;
|
|
842
|
+
return (_jsx(CoreService.Actions, { children: ({ remove, rawService, bookable, selected, requiresAvailability, }) => {
|
|
843
|
+
// If children is a function, call it with bookable, selected, requiresAvailability and other props
|
|
844
|
+
if (typeof children === 'function') {
|
|
845
|
+
return children({
|
|
846
|
+
bookable,
|
|
847
|
+
selected,
|
|
848
|
+
requiresAvailability,
|
|
849
|
+
onClick: remove,
|
|
850
|
+
service: rawService,
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
// Disabled when not selected (nothing to remove) or not bookable
|
|
854
|
+
const isDisabled = !selected || !bookable;
|
|
855
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceActionRemove, "data-selected": selected, "data-bookable": bookable, "data-requires-availability": requiresAvailability, customElement: children, customElementProps: {
|
|
856
|
+
onClick: remove,
|
|
857
|
+
disabled: isDisabled,
|
|
858
|
+
selected,
|
|
859
|
+
bookable,
|
|
860
|
+
requiresAvailability,
|
|
861
|
+
}, children: _jsx("button", { onClick: remove, disabled: isDisabled, "data-selected": selected, "data-bookable": bookable, "data-requires-availability": requiresAvailability, children: label }) }));
|
|
199
862
|
} }));
|
|
200
863
|
});
|
|
201
864
|
Actions.Remove.displayName = 'Service.Actions.Remove';
|
|
202
865
|
})(Actions || (Actions = {}));
|
|
866
|
+
/**
|
|
867
|
+
* Displays latestCancellationInMinutes as a raw number.
|
|
868
|
+
* Headless component - contains zero formatting logic.
|
|
869
|
+
*
|
|
870
|
+
* Maps to: bookingPolicy.cancellationPolicy.latestCancellationInMinutes
|
|
871
|
+
*
|
|
872
|
+
* @component
|
|
873
|
+
* @example
|
|
874
|
+
* ```tsx
|
|
875
|
+
* // Default usage - displays raw number only (or null if disabled/undefined)
|
|
876
|
+
* <Service.Policy.LatestCancellationInMinutes className="text-foreground" />
|
|
877
|
+
* // Renders: <span>30</span> or null
|
|
878
|
+
* ```
|
|
879
|
+
*
|
|
880
|
+
* @example
|
|
881
|
+
* ```tsx
|
|
882
|
+
* // Consumer adds formatting logic via asChild
|
|
883
|
+
* <Service.Policy.LatestCancellationInMinutes asChild>
|
|
884
|
+
* {({ cancellationPolicyEnabled, limitLatestCancellationEnabled, latestCancellationInMinutes }) => (
|
|
885
|
+
* cancellationPolicyEnabled ? (
|
|
886
|
+
* <div className="policy-card">
|
|
887
|
+
* {limitLatestCancellationEnabled
|
|
888
|
+
* ? `Cancel up to ${latestCancellationInMinutes} minutes before`
|
|
889
|
+
* : 'Free cancellation anytime'
|
|
890
|
+
* }
|
|
891
|
+
* </div>
|
|
892
|
+
* ) : null
|
|
893
|
+
* )}
|
|
894
|
+
* </Service.Policy.LatestCancellationInMinutes>
|
|
895
|
+
* ```
|
|
896
|
+
*/
|
|
897
|
+
export const PolicyLatestCancellationInMinutes = React.forwardRef((props, ref) => {
|
|
898
|
+
const { asChild, children, className } = props;
|
|
899
|
+
return (_jsx(CoreService.Policy, { children: ({ cancellationPolicyEnabled, limitLatestCancellationEnabled, latestCancellationInMinutes, }) => {
|
|
900
|
+
// Prepare data for asChild pattern - ALWAYS pass to consumer
|
|
901
|
+
const childProps = {
|
|
902
|
+
cancellationPolicyEnabled,
|
|
903
|
+
limitLatestCancellationEnabled,
|
|
904
|
+
latestCancellationInMinutes,
|
|
905
|
+
};
|
|
906
|
+
// ALWAYS return AsChildSlot (never return null early)
|
|
907
|
+
// This allows consumer to override null behavior via asChild
|
|
908
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.servicePolicyLatestCancellationInMinutes, customElement: children, customElementProps: childProps, children: cancellationPolicyEnabled &&
|
|
909
|
+
latestCancellationInMinutes !== undefined ? (_jsx("span", { children: latestCancellationInMinutes })) : null }));
|
|
910
|
+
} }));
|
|
911
|
+
});
|
|
912
|
+
PolicyLatestCancellationInMinutes.displayName =
|
|
913
|
+
'Service.Policy.LatestCancellationInMinutes';
|
|
914
|
+
/**
|
|
915
|
+
* Displays latestBookingInMinutes as a raw number.
|
|
916
|
+
* Headless component - contains zero formatting logic.
|
|
917
|
+
*
|
|
918
|
+
* Maps to: bookingPolicy.limitLateBookingPolicy.latestBookingInMinutes
|
|
919
|
+
*
|
|
920
|
+
* @component
|
|
921
|
+
* @example
|
|
922
|
+
* ```tsx
|
|
923
|
+
* // Default usage
|
|
924
|
+
* <Service.Policy.LatestBookingInMinutes className="text-foreground" />
|
|
925
|
+
* ```
|
|
926
|
+
*/
|
|
927
|
+
export const PolicyLatestBookingInMinutes = React.forwardRef((props, ref) => {
|
|
928
|
+
const { asChild, children, className } = props;
|
|
929
|
+
return (_jsx(CoreService.Policy, { children: ({ latestBookingPolicyEnabled, latestBookingInMinutes }) => {
|
|
930
|
+
const childProps = {
|
|
931
|
+
latestBookingPolicyEnabled,
|
|
932
|
+
latestBookingInMinutes,
|
|
933
|
+
};
|
|
934
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.servicePolicyLatestBookingInMinutes, customElement: children, customElementProps: childProps, children: latestBookingPolicyEnabled &&
|
|
935
|
+
latestBookingInMinutes !== undefined ? (_jsx("span", { children: latestBookingInMinutes })) : null }));
|
|
936
|
+
} }));
|
|
937
|
+
});
|
|
938
|
+
PolicyLatestBookingInMinutes.displayName =
|
|
939
|
+
'Service.Policy.LatestBookingInMinutes';
|
|
940
|
+
/**
|
|
941
|
+
* Displays earliestBookingInMinutes as a raw number.
|
|
942
|
+
* Headless component - contains zero formatting logic.
|
|
943
|
+
*
|
|
944
|
+
* Maps to: bookingPolicy.limitEarlyBookingPolicy.earliestBookingInMinutes
|
|
945
|
+
*
|
|
946
|
+
* @component
|
|
947
|
+
* @example
|
|
948
|
+
* ```tsx
|
|
949
|
+
* // Default usage
|
|
950
|
+
* <Service.Policy.EarliestBookingInMinutes className="text-foreground" />
|
|
951
|
+
* ```
|
|
952
|
+
*/
|
|
953
|
+
export const PolicyEarliestBookingInMinutes = React.forwardRef((props, ref) => {
|
|
954
|
+
const { asChild, children, className } = props;
|
|
955
|
+
return (_jsx(CoreService.Policy, { children: ({ earliestBookingPolicyEnabled, earliestBookingInMinutes }) => {
|
|
956
|
+
const childProps = {
|
|
957
|
+
earliestBookingPolicyEnabled,
|
|
958
|
+
earliestBookingInMinutes,
|
|
959
|
+
};
|
|
960
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.servicePolicyEarliestBookingInMinutes, customElement: children, customElementProps: childProps, children: earliestBookingPolicyEnabled &&
|
|
961
|
+
earliestBookingInMinutes !== undefined ? (_jsx("span", { children: earliestBookingInMinutes })) : null }));
|
|
962
|
+
} }));
|
|
963
|
+
});
|
|
964
|
+
PolicyEarliestBookingInMinutes.displayName =
|
|
965
|
+
'Service.Policy.EarliestBookingInMinutes';
|
|
966
|
+
/**
|
|
967
|
+
* Displays latestRescheduleInMinutes as a raw number.
|
|
968
|
+
* Headless component - contains zero formatting logic.
|
|
969
|
+
*
|
|
970
|
+
* Maps to: bookingPolicy.reschedulePolicy.latestRescheduleInMinutes
|
|
971
|
+
*
|
|
972
|
+
* @component
|
|
973
|
+
* @example
|
|
974
|
+
* ```tsx
|
|
975
|
+
* // Default usage
|
|
976
|
+
* <Service.Policy.LatestRescheduleInMinutes className="text-foreground" />
|
|
977
|
+
* ```
|
|
978
|
+
*/
|
|
979
|
+
export const PolicyLatestRescheduleInMinutes = React.forwardRef((props, ref) => {
|
|
980
|
+
const { asChild, children, className } = props;
|
|
981
|
+
return (_jsx(CoreService.Policy, { children: ({ reschedulePolicyEnabled, limitLatestRescheduleEnabled, latestRescheduleInMinutes, }) => {
|
|
982
|
+
const childProps = {
|
|
983
|
+
reschedulePolicyEnabled,
|
|
984
|
+
limitLatestRescheduleEnabled,
|
|
985
|
+
latestRescheduleInMinutes,
|
|
986
|
+
};
|
|
987
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.servicePolicyLatestRescheduleInMinutes, customElement: children, customElementProps: childProps, children: reschedulePolicyEnabled &&
|
|
988
|
+
latestRescheduleInMinutes !== undefined ? (_jsx("span", { children: latestRescheduleInMinutes })) : null }));
|
|
989
|
+
} }));
|
|
990
|
+
});
|
|
991
|
+
PolicyLatestRescheduleInMinutes.displayName =
|
|
992
|
+
'Service.Policy.LatestRescheduleInMinutes';
|
|
993
|
+
/**
|
|
994
|
+
* Displays waitlist capacity as a raw number.
|
|
995
|
+
* Headless component - contains zero formatting logic.
|
|
996
|
+
*
|
|
997
|
+
* Maps to: bookingPolicy.waitlistPolicy.capacity
|
|
998
|
+
*
|
|
999
|
+
* @component
|
|
1000
|
+
* @example
|
|
1001
|
+
* ```tsx
|
|
1002
|
+
* // Default usage
|
|
1003
|
+
* <Service.Policy.WaitlistCapacity className="text-foreground" />
|
|
1004
|
+
* ```
|
|
1005
|
+
*/
|
|
1006
|
+
export const PolicyWaitlistCapacity = React.forwardRef((props, ref) => {
|
|
1007
|
+
const { asChild, children, className } = props;
|
|
1008
|
+
return (_jsx(CoreService.Policy, { children: ({ waitlistPolicyEnabled, waitlistCapacity }) => {
|
|
1009
|
+
const childProps = {
|
|
1010
|
+
waitlistPolicyEnabled,
|
|
1011
|
+
waitlistCapacity,
|
|
1012
|
+
};
|
|
1013
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.servicePolicyWaitlistCapacity, customElement: children, customElementProps: childProps, children: waitlistPolicyEnabled && waitlistCapacity !== undefined ? (_jsx("span", { children: waitlistCapacity })) : null }));
|
|
1014
|
+
} }));
|
|
1015
|
+
});
|
|
1016
|
+
PolicyWaitlistCapacity.displayName = 'Service.Policy.WaitlistCapacity';
|
|
1017
|
+
/**
|
|
1018
|
+
* Displays whether booking after start is enabled.
|
|
1019
|
+
* Headless component - contains zero formatting logic.
|
|
1020
|
+
*
|
|
1021
|
+
* Maps to: bookingPolicy.bookAfterStartPolicy.enabled
|
|
1022
|
+
*
|
|
1023
|
+
* @component
|
|
1024
|
+
* @example
|
|
1025
|
+
* ```tsx
|
|
1026
|
+
* // Default usage
|
|
1027
|
+
* <Service.Policy.BookAfterStartEnabled className="text-foreground" />
|
|
1028
|
+
* ```
|
|
1029
|
+
*/
|
|
1030
|
+
export const PolicyBookAfterStartEnabled = React.forwardRef((props, ref) => {
|
|
1031
|
+
const { asChild, children, className } = props;
|
|
1032
|
+
return (_jsx(CoreService.Policy, { children: ({ bookAfterStartEnabled }) => {
|
|
1033
|
+
const childProps = {
|
|
1034
|
+
bookAfterStartEnabled,
|
|
1035
|
+
};
|
|
1036
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.servicePolicyBookAfterStartEnabled, customElement: children, customElementProps: childProps, children: bookAfterStartEnabled ? (_jsx("span", { children: bookAfterStartEnabled ? 'true' : 'false' })) : null }));
|
|
1037
|
+
} }));
|
|
1038
|
+
});
|
|
1039
|
+
PolicyBookAfterStartEnabled.displayName =
|
|
1040
|
+
'Service.Policy.BookAfterStartEnabled';
|
|
1041
|
+
/**
|
|
1042
|
+
* Displays maximum participants per booking as a raw number.
|
|
1043
|
+
* Headless component - contains zero formatting logic.
|
|
1044
|
+
*
|
|
1045
|
+
* Maps to: bookingPolicy.participantsPolicy.maxParticipantsPerBooking
|
|
1046
|
+
*
|
|
1047
|
+
* @component
|
|
1048
|
+
* @example
|
|
1049
|
+
* ```tsx
|
|
1050
|
+
* // Default usage
|
|
1051
|
+
* <Service.Policy.MaxParticipantsPerBooking className="text-foreground" />
|
|
1052
|
+
* ```
|
|
1053
|
+
*/
|
|
1054
|
+
export const PolicyMaxParticipantsPerBooking = React.forwardRef((props, ref) => {
|
|
1055
|
+
const { asChild, children, className } = props;
|
|
1056
|
+
return (_jsx(CoreService.Policy, { children: ({ maxParticipantsPerBooking }) => {
|
|
1057
|
+
const childProps = {
|
|
1058
|
+
maxParticipantsPerBooking,
|
|
1059
|
+
};
|
|
1060
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.servicePolicyMaxParticipantsPerBooking, customElement: children, customElementProps: childProps, children: maxParticipantsPerBooking !== undefined ? (_jsx("span", { children: maxParticipantsPerBooking })) : null }));
|
|
1061
|
+
} }));
|
|
1062
|
+
});
|
|
1063
|
+
PolicyMaxParticipantsPerBooking.displayName =
|
|
1064
|
+
'Service.Policy.MaxParticipantsPerBooking';
|
|
1065
|
+
/**
|
|
1066
|
+
* Policy namespace containing all policy sub-components
|
|
1067
|
+
*/
|
|
1068
|
+
export var Policy;
|
|
1069
|
+
(function (Policy) {
|
|
1070
|
+
Policy.LatestCancellationInMinutes = PolicyLatestCancellationInMinutes;
|
|
1071
|
+
Policy.LatestBookingInMinutes = PolicyLatestBookingInMinutes;
|
|
1072
|
+
Policy.EarliestBookingInMinutes = PolicyEarliestBookingInMinutes;
|
|
1073
|
+
Policy.LatestRescheduleInMinutes = PolicyLatestRescheduleInMinutes;
|
|
1074
|
+
Policy.WaitlistCapacity = PolicyWaitlistCapacity;
|
|
1075
|
+
Policy.BookAfterStartEnabled = PolicyBookAfterStartEnabled;
|
|
1076
|
+
Policy.MaxParticipantsPerBooking = PolicyMaxParticipantsPerBooking;
|
|
1077
|
+
})(Policy || (Policy = {}));
|
|
1078
|
+
/**
|
|
1079
|
+
* Displays the first session start date as a raw Date value.
|
|
1080
|
+
* Headless component - contains zero formatting logic.
|
|
1081
|
+
*
|
|
1082
|
+
* @component
|
|
1083
|
+
* @example
|
|
1084
|
+
* ```tsx
|
|
1085
|
+
* // Default usage - displays ISO string
|
|
1086
|
+
* <Service.Schedule.FirstSessionStart className="text-foreground" />
|
|
1087
|
+
*
|
|
1088
|
+
* // With custom formatting
|
|
1089
|
+
* <Service.Schedule.FirstSessionStart asChild>
|
|
1090
|
+
* {({ firstSessionStart }) => (
|
|
1091
|
+
* firstSessionStart ? (
|
|
1092
|
+
* <span>Starts: {formatDate(firstSessionStart)}</span>
|
|
1093
|
+
* ) : null
|
|
1094
|
+
* )}
|
|
1095
|
+
* </Service.Schedule.FirstSessionStart>
|
|
1096
|
+
* ```
|
|
1097
|
+
*/
|
|
1098
|
+
export const ScheduleFirstSessionStart = React.forwardRef((props, ref) => {
|
|
1099
|
+
const { asChild, children, className } = props;
|
|
1100
|
+
return (_jsx(CoreService.Schedule, { children: ({ schedule }) => {
|
|
1101
|
+
const firstSessionStart = schedule?.firstSessionStart;
|
|
1102
|
+
const childProps = {
|
|
1103
|
+
firstSessionStart,
|
|
1104
|
+
};
|
|
1105
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceScheduleFirstSessionStart, customElement: children, customElementProps: childProps, children: firstSessionStart ? (_jsx("span", { children: firstSessionStart.toISOString() })) : null }));
|
|
1106
|
+
} }));
|
|
1107
|
+
});
|
|
1108
|
+
ScheduleFirstSessionStart.displayName = 'Service.Schedule.FirstSessionStart';
|
|
1109
|
+
/**
|
|
1110
|
+
* Displays the last session end date as a raw Date value.
|
|
1111
|
+
* Headless component - contains zero formatting logic.
|
|
1112
|
+
*
|
|
1113
|
+
* @component
|
|
1114
|
+
* @example
|
|
1115
|
+
* ```tsx
|
|
1116
|
+
* // Default usage - displays ISO string
|
|
1117
|
+
* <Service.Schedule.LastSessionEnd className="text-foreground" />
|
|
1118
|
+
*
|
|
1119
|
+
* // With custom formatting
|
|
1120
|
+
* <Service.Schedule.LastSessionEnd asChild>
|
|
1121
|
+
* {({ lastSessionEnd }) => (
|
|
1122
|
+
* lastSessionEnd ? (
|
|
1123
|
+
* <span>Ends: {formatDate(lastSessionEnd)}</span>
|
|
1124
|
+
* ) : null
|
|
1125
|
+
* )}
|
|
1126
|
+
* </Service.Schedule.LastSessionEnd>
|
|
1127
|
+
* ```
|
|
1128
|
+
*/
|
|
1129
|
+
export const ScheduleLastSessionEnd = React.forwardRef((props, ref) => {
|
|
1130
|
+
const { asChild, children, className } = props;
|
|
1131
|
+
return (_jsx(CoreService.Schedule, { children: ({ schedule }) => {
|
|
1132
|
+
const lastSessionEnd = schedule?.lastSessionEnd;
|
|
1133
|
+
const childProps = {
|
|
1134
|
+
lastSessionEnd,
|
|
1135
|
+
};
|
|
1136
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceScheduleLastSessionEnd, customElement: children, customElementProps: childProps, children: lastSessionEnd ? (_jsx("span", { children: lastSessionEnd.toISOString() })) : null }));
|
|
1137
|
+
} }));
|
|
1138
|
+
});
|
|
1139
|
+
ScheduleLastSessionEnd.displayName = 'Service.Schedule.LastSessionEnd';
|
|
1140
|
+
/**
|
|
1141
|
+
* Displays the session duration in minutes as a raw number.
|
|
1142
|
+
* Headless component - contains zero formatting logic.
|
|
1143
|
+
*
|
|
1144
|
+
* @component
|
|
1145
|
+
* @example
|
|
1146
|
+
* ```tsx
|
|
1147
|
+
* // Default usage - displays raw minutes
|
|
1148
|
+
* <Service.Schedule.SessionDuration className="text-foreground" />
|
|
1149
|
+
*
|
|
1150
|
+
* // With custom formatting
|
|
1151
|
+
* <Service.Schedule.SessionDuration asChild>
|
|
1152
|
+
* {({ sessionDuration }) => (
|
|
1153
|
+
* sessionDuration ? (
|
|
1154
|
+
* <span>{formatDuration(sessionDuration)}</span>
|
|
1155
|
+
* ) : null
|
|
1156
|
+
* )}
|
|
1157
|
+
* </Service.Schedule.SessionDuration>
|
|
1158
|
+
* ```
|
|
1159
|
+
*/
|
|
1160
|
+
export const ScheduleSessionDuration = React.forwardRef((props, ref) => {
|
|
1161
|
+
const { asChild, children, className } = props;
|
|
1162
|
+
return (_jsx(CoreService.Schedule, { children: ({ schedule }) => {
|
|
1163
|
+
const sessionDuration = schedule?.availabilityConstraints?.sessionDurations?.[0];
|
|
1164
|
+
const childProps = {
|
|
1165
|
+
sessionDuration,
|
|
1166
|
+
};
|
|
1167
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceScheduleSessionDuration, customElement: children, customElementProps: childProps, children: sessionDuration !== undefined ? (_jsx("span", { children: sessionDuration })) : null }));
|
|
1168
|
+
} }));
|
|
1169
|
+
});
|
|
1170
|
+
ScheduleSessionDuration.displayName = 'Service.Schedule.SessionDuration';
|
|
1171
|
+
/**
|
|
1172
|
+
* Schedule namespace containing all schedule sub-components
|
|
1173
|
+
*/
|
|
1174
|
+
export var Schedule;
|
|
1175
|
+
(function (Schedule) {
|
|
1176
|
+
Schedule.FirstSessionStart = ScheduleFirstSessionStart;
|
|
1177
|
+
Schedule.LastSessionEnd = ScheduleLastSessionEnd;
|
|
1178
|
+
Schedule.SessionDuration = ScheduleSessionDuration;
|
|
1179
|
+
})(Schedule || (Schedule = {}));
|
|
1180
|
+
/**
|
|
1181
|
+
* Displays the service default capacity with customizable rendering.
|
|
1182
|
+
* Only renders for CLASS or COURSE service types.
|
|
1183
|
+
*
|
|
1184
|
+
* @component
|
|
1185
|
+
* @example
|
|
1186
|
+
* ```tsx
|
|
1187
|
+
* // Default usage
|
|
1188
|
+
* <Service.DefaultCapacity className="text-sm" />
|
|
1189
|
+
*
|
|
1190
|
+
* // asChild with custom component
|
|
1191
|
+
* <Service.DefaultCapacity asChild>
|
|
1192
|
+
* {({ defaultCapacity, isClassOrCourse }) => isClassOrCourse ? (
|
|
1193
|
+
* <span>Max participants: {defaultCapacity}</span>
|
|
1194
|
+
* ) : null}
|
|
1195
|
+
* </Service.DefaultCapacity>
|
|
1196
|
+
* ```
|
|
1197
|
+
*/
|
|
1198
|
+
export const DefaultCapacity = React.forwardRef((props, ref) => {
|
|
1199
|
+
const { asChild, children, className } = props;
|
|
1200
|
+
return (_jsx(CoreService.Info, { children: ({ type, defaultCapacity }) => {
|
|
1201
|
+
const isClassOrCourse = type === 'CLASS' || type === 'COURSE';
|
|
1202
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceDefaultCapacity, customElement: children, customElementProps: { defaultCapacity, isClassOrCourse }, children: isClassOrCourse && defaultCapacity ? (_jsxs("span", { children: ["Max ", defaultCapacity, " participants"] })) : null }));
|
|
1203
|
+
} }));
|
|
1204
|
+
});
|
|
1205
|
+
DefaultCapacity.displayName = 'Service.DefaultCapacity';
|
|
1206
|
+
// Create Locations with nested components
|
|
1207
|
+
export const Locations = Object.assign(LocationsBase, {
|
|
1208
|
+
List: LocationsList,
|
|
1209
|
+
LocationRepeater,
|
|
1210
|
+
});
|
|
1211
|
+
// Create StaffMembers with nested components
|
|
1212
|
+
export const StaffMembers = Object.assign(StaffMembersBase, {
|
|
1213
|
+
List: StaffMembersList,
|
|
1214
|
+
StaffMemberRepeater,
|
|
1215
|
+
});
|