@wix/headless-bookings 0.0.56 → 0.0.58

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 (39) hide show
  1. package/cjs/dist/react/booking/Booking.js +1 -1
  2. package/cjs/dist/react/booking-form/BookingForm.d.ts +117 -17
  3. package/cjs/dist/react/booking-form/BookingForm.js +149 -15
  4. package/cjs/dist/react/core/booking/Booking.d.ts +3 -3
  5. package/cjs/dist/react/core/booking/Booking.js +2 -2
  6. package/cjs/dist/react/core/booking-form/BookingForm.d.ts +112 -10
  7. package/cjs/dist/react/core/booking-form/BookingForm.js +204 -64
  8. package/cjs/dist/react/core/payment/Payment.d.ts +84 -5
  9. package/cjs/dist/react/core/payment/Payment.js +102 -4
  10. package/cjs/dist/react/payment/Payment.d.ts +64 -58
  11. package/cjs/dist/react/payment/Payment.js +66 -80
  12. package/cjs/dist/services/booking-form/booking-form.d.ts +22 -13
  13. package/cjs/dist/services/booking-form/booking-form.js +67 -25
  14. package/cjs/dist/services/booking-form/utils.d.ts +52 -0
  15. package/cjs/dist/services/booking-form/utils.js +47 -0
  16. package/cjs/dist/services/index.d.ts +1 -1
  17. package/cjs/dist/services/payment/payment.d.ts +4 -4
  18. package/cjs/dist/services/payment/payment.def.d.ts +4 -4
  19. package/cjs/dist/services/payment/payment.js +26 -18
  20. package/dist/react/booking/Booking.js +1 -1
  21. package/dist/react/booking-form/BookingForm.d.ts +117 -17
  22. package/dist/react/booking-form/BookingForm.js +149 -15
  23. package/dist/react/core/booking/Booking.d.ts +3 -3
  24. package/dist/react/core/booking/Booking.js +2 -2
  25. package/dist/react/core/booking-form/BookingForm.d.ts +112 -10
  26. package/dist/react/core/booking-form/BookingForm.js +204 -64
  27. package/dist/react/core/payment/Payment.d.ts +84 -5
  28. package/dist/react/core/payment/Payment.js +102 -4
  29. package/dist/react/payment/Payment.d.ts +64 -58
  30. package/dist/react/payment/Payment.js +66 -80
  31. package/dist/services/booking-form/booking-form.d.ts +22 -13
  32. package/dist/services/booking-form/booking-form.js +67 -25
  33. package/dist/services/booking-form/utils.d.ts +52 -0
  34. package/dist/services/booking-form/utils.js +47 -0
  35. package/dist/services/index.d.ts +1 -1
  36. package/dist/services/payment/payment.d.ts +4 -4
  37. package/dist/services/payment/payment.def.d.ts +4 -4
  38. package/dist/services/payment/payment.js +26 -18
  39. package/package.json +3 -3
@@ -5,8 +5,7 @@
5
5
  import React from 'react';
6
6
  import { AsChildChildren } from '@wix/headless-utils/react';
7
7
  import { MoneyData } from '@wix/headless-components/react';
8
- import type { PaymentServiceConfig, SlotService } from '../../services/payment/payment.js';
9
- import type { LineItem as CoreLineItem } from '../core/payment/Payment.js';
8
+ import type { PaymentServiceConfig, PricingServiceSelection } from '../../services/payment/payment.js';
10
9
  /**
11
10
  * Props for Payment.Root component
12
11
  */
@@ -17,8 +16,8 @@ export interface RootProps {
17
16
  }) => React.ReactNode);
18
17
  /** Service config for SSR (pre-fetched paymentDetails) */
19
18
  paymentServiceConfig?: PaymentServiceConfig;
20
- /** Slot services for lazy loading (triggers API call) */
21
- slotServices?: SlotService[];
19
+ /** Pricing service selections for lazy loading (triggers API call) */
20
+ pricingServiceSelections?: PricingServiceSelection[];
22
21
  /** Number of participants for lazy loading */
23
22
  numberOfParticipants?: number;
24
23
  asChild?: boolean;
@@ -28,7 +27,7 @@ export interface RootProps {
28
27
  * Root component that provides payment context to the entire app.
29
28
  * Supports 3 modes:
30
29
  * 1. SSR: paymentServiceConfig.paymentDetails - pre-fetched data
31
- * 2. Lazy loading: slotServices + numberOfParticipants props - calls API via useEffect
30
+ * 2. Lazy loading: pricingServiceSelections + numberOfParticipants props - calls API via useEffect
32
31
  * 3. Reactive: no config/props - reads from BookingService signals
33
32
  *
34
33
  * @order 1
@@ -64,17 +63,32 @@ export interface SubtotalProps {
64
63
  asChild?: boolean;
65
64
  children?: AsChildChildren<{
66
65
  subtotal: MoneyData | null;
66
+ priceText: string | null;
67
+ hasPriceText: boolean;
68
+ isFree: boolean;
67
69
  }>;
68
70
  className?: string;
69
71
  }
70
72
  /**
71
73
  * Displays the payment subtotal.
74
+ * Always displays the monetary value but exposes priceText, hasPriceText, and isFree for custom rendering.
72
75
  *
73
76
  * @component
74
77
  * @example
75
78
  * ```tsx
76
79
  * <Payment.Subtotal className="text-lg" />
77
80
  * ```
81
+ * @example
82
+ * ```tsx
83
+ * <Payment.Subtotal asChild>
84
+ * {({ subtotal, priceText, hasPriceText, isFree }) => (
85
+ * <div>
86
+ * <Money money={subtotal} />
87
+ * {hasPriceText && <span className="text-sm">({priceText})</span>}
88
+ * </div>
89
+ * )}
90
+ * </Payment.Subtotal>
91
+ * ```
78
92
  */
79
93
  export declare const Subtotal: React.ForwardRefExoticComponent<SubtotalProps & React.RefAttributes<HTMLElement>>;
80
94
  /**
@@ -126,17 +140,36 @@ export interface TotalProps {
126
140
  asChild?: boolean;
127
141
  children?: AsChildChildren<{
128
142
  total: MoneyData | null;
143
+ priceText: string | null;
144
+ hasPriceText: boolean;
145
+ isFree: boolean;
129
146
  }>;
130
147
  className?: string;
131
148
  }
132
149
  /**
133
150
  * Displays the payment total.
151
+ * Always displays the monetary value but exposes priceText, hasPriceText, and isFree for custom rendering.
134
152
  *
135
153
  * @component
136
154
  * @example
137
155
  * ```tsx
138
156
  * <Payment.Total className="text-2xl font-bold" />
139
157
  * ```
158
+ * @example
159
+ * ```tsx
160
+ * <Payment.Total asChild>
161
+ * {({ total, priceText, hasPriceText, isFree }) => (
162
+ * <div>
163
+ * {isFree ? (
164
+ * <span className="text-green-500">Free</span>
165
+ * ) : (
166
+ * <Money money={total} />
167
+ * )}
168
+ * {hasPriceText && <span className="text-sm">({priceText})</span>}
169
+ * </div>
170
+ * )}
171
+ * </Payment.Total>
172
+ * ```
140
173
  */
141
174
  export declare const Total: React.ForwardRefExoticComponent<TotalProps & React.RefAttributes<HTMLElement>>;
142
175
  /**
@@ -240,101 +273,74 @@ export interface LineItemsListProps {
240
273
  * ```
241
274
  */
242
275
  export declare const LineItemsList: React.ForwardRefExoticComponent<LineItemsListProps & React.RefAttributes<HTMLElement>>;
243
- /**
244
- * Render props for LineItemRepeater asChild pattern
245
- */
246
- export interface LineItemRepeaterRenderProps {
247
- items: CoreLineItem[];
248
- itemWrapper: (props: {
249
- item: CoreLineItem;
250
- index: number;
251
- children: React.ReactNode;
252
- }) => React.ReactNode;
253
- }
254
276
  /**
255
277
  * Props for Payment.LineItemRepeater component
256
278
  */
257
279
  export interface LineItemRepeaterProps {
258
- children?: React.ReactNode | ((props: LineItemRepeaterRenderProps) => React.ReactNode);
259
- asChild?: boolean;
280
+ children: React.ReactNode;
260
281
  }
261
282
  /**
262
- * Repeater component that renders LineItemRoot for each line item.
263
- * Supports asChild pattern for custom rendering.
283
+ * Repeater component that maps over line items and provides context per item.
284
+ * Uses GenericList.Repeater internally with itemWrapper that provides LineItemContext.
264
285
  *
265
286
  * @component
266
287
  * @example
267
288
  * ```tsx
268
- * // Standard usage
269
289
  * <Payment.LineItemRepeater>
270
- * <Payment.LineItemPrice />
271
- * </Payment.LineItemRepeater>
272
- *
273
- * // AsChild usage with custom list
274
- * <Payment.LineItemRepeater asChild>
275
- * {({ items, itemWrapper }) => (
276
- * <ol>
277
- * {items.map((item, index) => (
278
- * <li key={item.id}>
279
- * {itemWrapper({ item, index, children: <Payment.LineItemPrice /> })}
280
- * </li>
281
- * ))}
282
- * </ol>
283
- * )}
290
+ * <Payment.LineItemTotal />
291
+ * <Payment.LineItemDiscount />
284
292
  * </Payment.LineItemRepeater>
285
293
  * ```
286
294
  */
287
295
  export declare const LineItemRepeater: React.ForwardRefExoticComponent<LineItemRepeaterProps & React.RefAttributes<HTMLElement>>;
288
296
  /**
289
- * Props for Payment.LineItemRoot component
297
+ * Props for Payment.LineItemTotal component
290
298
  */
291
- export interface LineItemRootProps {
292
- lineItem: CoreLineItem;
293
- currency: string;
294
- children?: React.ReactNode | AsChildChildren<{
295
- lineItem: CoreLineItem;
296
- currency: string;
297
- }>;
299
+ export interface LineItemTotalProps {
298
300
  asChild?: boolean;
301
+ children?: AsChildChildren<{
302
+ totalPrice: MoneyData | null;
303
+ priceText: string | null;
304
+ hasPriceText: boolean;
305
+ isFree: boolean;
306
+ }>;
299
307
  className?: string;
300
- 'data-testid'?: string;
301
308
  }
302
309
  /**
303
- * Root component for a single line item.
304
- * Provides context for child components.
310
+ * Displays the line item total (total price after tax).
311
+ * Shows priceText for CUSTOM rate type services, otherwise shows totalPrice.
305
312
  *
306
313
  * @component
307
314
  * @example
308
315
  * ```tsx
309
- * <Payment.LineItemRoot lineItem={item} currency="USD">
310
- * <Payment.LineItemPrice />
311
- * <Payment.LineItemDiscount />
312
- * </Payment.LineItemRoot>
316
+ * <Payment.LineItemTotal className="text-2xl font-bold" />
313
317
  * ```
314
318
  */
315
- export declare const LineItemRoot: React.ForwardRefExoticComponent<LineItemRootProps & React.RefAttributes<HTMLElement>>;
319
+ export declare const LineItemTotal: React.ForwardRefExoticComponent<LineItemTotalProps & React.RefAttributes<HTMLElement>>;
316
320
  /**
317
- * Props for Payment.LineItemPrice component
321
+ * Props for Payment.LineItemSubtotal component
318
322
  */
319
- export interface LineItemPriceProps {
323
+ export interface LineItemSubtotalProps {
320
324
  asChild?: boolean;
321
325
  children?: AsChildChildren<{
322
- totalPrice: MoneyData | null;
326
+ subtotal: MoneyData | null;
323
327
  priceText: string | null;
328
+ hasPriceText: boolean;
329
+ isFree: boolean;
324
330
  }>;
325
331
  className?: string;
326
332
  }
327
333
  /**
328
- * Displays the line item price.
329
- * Shows priceText for CUSTOM rate type services, otherwise shows totalPrice.
334
+ * Displays the line item subtotal (full price before discounts).
335
+ * Shows priceText for CUSTOM rate type services, otherwise shows subtotal.
330
336
  *
331
337
  * @component
332
338
  * @example
333
339
  * ```tsx
334
- * <Payment.LineItemPrice className="text-lg font-bold" />
340
+ * <Payment.LineItemSubtotal className="text-lg" />
335
341
  * ```
336
342
  */
337
- export declare const LineItemPrice: React.ForwardRefExoticComponent<LineItemPriceProps & React.RefAttributes<HTMLElement>>;
343
+ export declare const LineItemSubtotal: React.ForwardRefExoticComponent<LineItemSubtotalProps & React.RefAttributes<HTMLElement>>;
338
344
  /**
339
345
  * Props for Payment.LineItemDiscount component
340
346
  */
@@ -19,8 +19,8 @@ var TestIds;
19
19
  TestIds["paymentLineItems"] = "payment-line-items";
20
20
  TestIds["paymentLineItemsList"] = "payment-line-items-list";
21
21
  TestIds["paymentLineItemRepeater"] = "payment-line-item-repeater";
22
- TestIds["paymentLineItemRoot"] = "payment-line-item-root";
23
- TestIds["paymentLineItemPrice"] = "payment-line-item-price";
22
+ TestIds["paymentLineItemTotal"] = "payment-line-item-total";
23
+ TestIds["paymentLineItemSubtotal"] = "payment-line-item-subtotal";
24
24
  TestIds["paymentLineItemDiscount"] = "payment-line-item-discount";
25
25
  TestIds["paymentLineItemDeposit"] = "payment-line-item-deposit";
26
26
  })(TestIds || (TestIds = {}));
@@ -28,7 +28,7 @@ var TestIds;
28
28
  * Root component that provides payment context to the entire app.
29
29
  * Supports 3 modes:
30
30
  * 1. SSR: paymentServiceConfig.paymentDetails - pre-fetched data
31
- * 2. Lazy loading: slotServices + numberOfParticipants props - calls API via useEffect
31
+ * 2. Lazy loading: pricingServiceSelections + numberOfParticipants props - calls API via useEffect
32
32
  * 3. Reactive: no config/props - reads from BookingService signals
33
33
  *
34
34
  * @order 1
@@ -57,24 +57,36 @@ var TestIds;
57
57
  * ```
58
58
  */
59
59
  export const Root = React.forwardRef((props, ref) => {
60
- const { children, paymentServiceConfig, slotServices, numberOfParticipants, asChild, className, ...attrs } = props;
61
- return (_jsx(CorePayment.Root, { paymentServiceConfig: paymentServiceConfig, slotServices: slotServices, numberOfParticipants: numberOfParticipants, children: ({ isLoading, hasError }) => {
60
+ const { children, paymentServiceConfig, pricingServiceSelections, numberOfParticipants, asChild, className, ...attrs } = props;
61
+ return (_jsx(CorePayment.Root, { paymentServiceConfig: paymentServiceConfig, pricingServiceSelections: pricingServiceSelections, numberOfParticipants: numberOfParticipants, children: ({ isLoading, hasError }) => {
62
62
  return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentRoot, "data-loading": isLoading, "data-has-error": hasError, customElement: children, customElementProps: { isLoading, hasError }, ...attrs, children: children }));
63
63
  } }));
64
64
  });
65
65
  Root.displayName = 'Payment.Root';
66
66
  /**
67
67
  * Displays the payment subtotal.
68
+ * Always displays the monetary value but exposes priceText, hasPriceText, and isFree for custom rendering.
68
69
  *
69
70
  * @component
70
71
  * @example
71
72
  * ```tsx
72
73
  * <Payment.Subtotal className="text-lg" />
73
74
  * ```
75
+ * @example
76
+ * ```tsx
77
+ * <Payment.Subtotal asChild>
78
+ * {({ subtotal, priceText, hasPriceText, isFree }) => (
79
+ * <div>
80
+ * <Money money={subtotal} />
81
+ * {hasPriceText && <span className="text-sm">({priceText})</span>}
82
+ * </div>
83
+ * )}
84
+ * </Payment.Subtotal>
85
+ * ```
74
86
  */
75
87
  export const Subtotal = React.forwardRef((props, ref) => {
76
88
  const { asChild, children, className } = props;
77
- return (_jsx(CorePayment.Data, { children: ({ subtotal }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentSubtotal, customElement: children, customElementProps: { subtotal }, children: subtotal ? _jsx(Money, { money: subtotal }) : null })) }));
89
+ return (_jsx(CorePayment.Data, { children: ({ subtotal, priceText, hasPriceText, isFree }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentSubtotal, "data-has-price-text": hasPriceText, "data-is-free": isFree, customElement: children, customElementProps: { subtotal, priceText, hasPriceText, isFree }, children: subtotal && _jsx(Money, { money: subtotal }) })) }));
78
90
  });
79
91
  Subtotal.displayName = 'Payment.Subtotal';
80
92
  /**
@@ -89,10 +101,7 @@ Subtotal.displayName = 'Payment.Subtotal';
89
101
  */
90
102
  export const Tax = React.forwardRef((props, ref) => {
91
103
  const { asChild, children, className } = props;
92
- return (_jsx(CorePayment.Data, { children: ({ tax }) => {
93
- const hasTax = tax !== null && tax.amount > 0;
94
- return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentTax, "data-has-tax": hasTax, customElement: children, customElementProps: { tax }, children: tax ? _jsx(Money, { money: tax }) : null }));
95
- } }));
104
+ return (_jsx(CorePayment.Data, { children: ({ tax, hasTax }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentTax, "data-has-tax": hasTax, customElement: children, customElementProps: { tax }, children: hasTax && _jsx(Money, { money: tax }) })) }));
96
105
  });
97
106
  Tax.displayName = 'Payment.Tax';
98
107
  /**
@@ -107,24 +116,37 @@ Tax.displayName = 'Payment.Tax';
107
116
  */
108
117
  export const Discount = React.forwardRef((props, ref) => {
109
118
  const { asChild, children, className } = props;
110
- return (_jsx(CorePayment.Data, { children: ({ discount }) => {
111
- const hasDiscount = discount !== null && discount.amount > 0;
112
- return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentDiscount, "data-has-discount": hasDiscount, customElement: children, customElementProps: { discount }, children: discount ? _jsx(Money, { money: discount }) : null }));
113
- } }));
119
+ return (_jsx(CorePayment.Data, { children: ({ discount, hasDiscount }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentDiscount, "data-has-discount": hasDiscount, customElement: children, customElementProps: { discount }, children: hasDiscount && _jsx(Money, { money: discount }) })) }));
114
120
  });
115
121
  Discount.displayName = 'Payment.Discount';
116
122
  /**
117
123
  * Displays the payment total.
124
+ * Always displays the monetary value but exposes priceText, hasPriceText, and isFree for custom rendering.
118
125
  *
119
126
  * @component
120
127
  * @example
121
128
  * ```tsx
122
129
  * <Payment.Total className="text-2xl font-bold" />
123
130
  * ```
131
+ * @example
132
+ * ```tsx
133
+ * <Payment.Total asChild>
134
+ * {({ total, priceText, hasPriceText, isFree }) => (
135
+ * <div>
136
+ * {isFree ? (
137
+ * <span className="text-green-500">Free</span>
138
+ * ) : (
139
+ * <Money money={total} />
140
+ * )}
141
+ * {hasPriceText && <span className="text-sm">({priceText})</span>}
142
+ * </div>
143
+ * )}
144
+ * </Payment.Total>
145
+ * ```
124
146
  */
125
147
  export const Total = React.forwardRef((props, ref) => {
126
148
  const { asChild, children, className } = props;
127
- return (_jsx(CorePayment.Data, { children: ({ total }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentTotal, customElement: children, customElementProps: { total }, children: total ? _jsx(Money, { money: total }) : null })) }));
149
+ return (_jsx(CorePayment.Data, { children: ({ total, priceText, hasPriceText, isFree }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentTotal, "data-has-price-text": hasPriceText, "data-is-free": isFree, customElement: children, customElementProps: { total, priceText, hasPriceText, isFree }, children: total && _jsx(Money, { money: total }) })) }));
128
150
  });
129
151
  Total.displayName = 'Payment.Total';
130
152
  /**
@@ -139,10 +161,7 @@ Total.displayName = 'Payment.Total';
139
161
  */
140
162
  export const PayNow = React.forwardRef((props, ref) => {
141
163
  const { asChild, children, className } = props;
142
- return (_jsx(CorePayment.Data, { children: ({ payNow, total }) => {
143
- const isDeposit = payNow !== null && total !== null && payNow.amount < total.amount;
144
- return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentPayNow, "data-has-deposit": isDeposit, customElement: children, customElementProps: { payNow }, children: payNow ? _jsx(Money, { money: payNow }) : null }));
145
- } }));
164
+ return (_jsx(CorePayment.Data, { children: ({ payNow, isDeposit }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentPayNow, "data-has-deposit": isDeposit, customElement: children, customElementProps: { payNow }, children: payNow && payNow.amount > 0 && _jsx(Money, { money: payNow }) })) }));
146
165
  });
147
166
  PayNow.displayName = 'Payment.PayNow';
148
167
  /**
@@ -157,10 +176,7 @@ PayNow.displayName = 'Payment.PayNow';
157
176
  */
158
177
  export const PayLater = React.forwardRef((props, ref) => {
159
178
  const { asChild, children, className } = props;
160
- return (_jsx(CorePayment.Data, { children: ({ payLater, payNow, total }) => {
161
- const isDeposit = payNow !== null && total !== null && payNow.amount < total.amount;
162
- return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentPayLater, "data-has-deposit": isDeposit, customElement: children, customElementProps: { payLater }, children: payLater ? _jsx(Money, { money: payLater }) : null }));
163
- } }));
179
+ return (_jsx(CorePayment.Data, { children: ({ payLater, isDeposit }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentPayLater, "data-has-deposit": isDeposit, customElement: children, customElementProps: { payLater }, children: payLater && payLater.amount > 0 && _jsx(Money, { money: payLater }) })) }));
164
180
  });
165
181
  PayLater.displayName = 'Payment.PayLater';
166
182
  /**
@@ -219,84 +235,60 @@ export const LineItemsList = React.forwardRef((props, ref) => {
219
235
  });
220
236
  LineItemsList.displayName = 'Payment.LineItemsList';
221
237
  /**
222
- * Repeater component that renders LineItemRoot for each line item.
223
- * Supports asChild pattern for custom rendering.
238
+ * Internal component that wraps each line item with context provider.
239
+ */
240
+ const LineItemWrapper = ({ item, currency, children, }) => {
241
+ return (_jsx(CorePayment.LineItemProvider, { lineItem: item, currency: currency, children: children }));
242
+ };
243
+ /**
244
+ * Repeater component that maps over line items and provides context per item.
245
+ * Uses GenericList.Repeater internally with itemWrapper that provides LineItemContext.
224
246
  *
225
247
  * @component
226
248
  * @example
227
249
  * ```tsx
228
- * // Standard usage
229
250
  * <Payment.LineItemRepeater>
230
- * <Payment.LineItemPrice />
231
- * </Payment.LineItemRepeater>
232
- *
233
- * // AsChild usage with custom list
234
- * <Payment.LineItemRepeater asChild>
235
- * {({ items, itemWrapper }) => (
236
- * <ol>
237
- * {items.map((item, index) => (
238
- * <li key={item.id}>
239
- * {itemWrapper({ item, index, children: <Payment.LineItemPrice /> })}
240
- * </li>
241
- * ))}
242
- * </ol>
243
- * )}
251
+ * <Payment.LineItemTotal />
252
+ * <Payment.LineItemDiscount />
244
253
  * </Payment.LineItemRepeater>
245
254
  * ```
246
255
  */
247
256
  export const LineItemRepeater = React.forwardRef((props, ref) => {
248
- const { children, asChild } = props;
257
+ const { children } = props;
249
258
  const { currency } = useLineItemsContext();
250
- // Custom itemWrapper that renders LineItemRoot for each line item
251
- const lineItemWrapper = ({ item, children: itemChildren, }) => {
252
- return (_jsx(LineItemRoot, { lineItem: item, currency: currency, "data-testid": TestIds.paymentLineItemRepeater, children: itemChildren || undefined }, item.id));
253
- };
254
- return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: lineItemWrapper, asChild: asChild, children: children }));
259
+ return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: ({ item }) => (_jsx(LineItemWrapper, { item: item, currency: currency, children: children }, item.id)), children: undefined }));
255
260
  });
256
261
  LineItemRepeater.displayName = 'Payment.LineItemRepeater';
257
- const LineItemContext = React.createContext(null);
258
- function useLineItemContext() {
259
- const context = React.useContext(LineItemContext);
260
- if (!context) {
261
- throw new Error('useLineItemContext must be used within a Payment.LineItemRoot component');
262
- }
263
- return context;
264
- }
265
262
  /**
266
- * Root component for a single line item.
267
- * Provides context for child components.
263
+ * Displays the line item total (total price after tax).
264
+ * Shows priceText for CUSTOM rate type services, otherwise shows totalPrice.
268
265
  *
269
266
  * @component
270
267
  * @example
271
268
  * ```tsx
272
- * <Payment.LineItemRoot lineItem={item} currency="USD">
273
- * <Payment.LineItemPrice />
274
- * <Payment.LineItemDiscount />
275
- * </Payment.LineItemRoot>
269
+ * <Payment.LineItemTotal className="text-2xl font-bold" />
276
270
  * ```
277
271
  */
278
- export const LineItemRoot = React.forwardRef((props, ref) => {
279
- const { lineItem, currency, children, asChild, className, ...attrs } = props;
280
- return (_jsx(LineItemContext.Provider, { value: { lineItem, currency }, children: _jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": attrs['data-testid'] || TestIds.paymentLineItemRoot, customElement: children, customElementProps: { lineItem, currency }, ...attrs, children: _jsx("div", { children: React.isValidElement(children) ? children : null }) }) }));
272
+ export const LineItemTotal = React.forwardRef((props, ref) => {
273
+ const { asChild, children, className } = props;
274
+ return (_jsx(CorePayment.LineItemInfo, { children: ({ totalPrice, priceText, hasPriceText, isFree }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentLineItemTotal, "data-has-price-text": hasPriceText, "data-is-free": isFree, customElement: children, customElementProps: { totalPrice, priceText, hasPriceText, isFree }, children: priceText ? (_jsx("span", { children: priceText })) : (totalPrice && _jsx(Money, { money: totalPrice })) })) }));
281
275
  });
282
- LineItemRoot.displayName = 'Payment.LineItemRoot';
276
+ LineItemTotal.displayName = 'Payment.LineItemTotal';
283
277
  /**
284
- * Displays the line item price.
285
- * Shows priceText for CUSTOM rate type services, otherwise shows totalPrice.
278
+ * Displays the line item subtotal (full price before discounts).
279
+ * Shows priceText for CUSTOM rate type services, otherwise shows subtotal.
286
280
  *
287
281
  * @component
288
282
  * @example
289
283
  * ```tsx
290
- * <Payment.LineItemPrice className="text-lg font-bold" />
284
+ * <Payment.LineItemSubtotal className="text-lg" />
291
285
  * ```
292
286
  */
293
- export const LineItemPrice = React.forwardRef((props, ref) => {
287
+ export const LineItemSubtotal = React.forwardRef((props, ref) => {
294
288
  const { asChild, children, className } = props;
295
- const { lineItem } = useLineItemContext();
296
- const { totalPrice, priceText } = lineItem;
297
- return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentLineItemPrice, "data-has-price-text": !!priceText, customElement: children, customElementProps: { totalPrice, priceText }, children: priceText ? (_jsx("span", { children: priceText })) : totalPrice ? (_jsx(Money, { money: totalPrice })) : null }));
289
+ return (_jsx(CorePayment.LineItemInfo, { children: ({ subtotal, priceText, hasPriceText, isFree }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentLineItemSubtotal, "data-has-price-text": hasPriceText, "data-is-free": isFree, customElement: children, customElementProps: { subtotal, priceText, hasPriceText, isFree }, children: priceText ? (_jsx("span", { children: priceText })) : (subtotal && _jsx(Money, { money: subtotal })) })) }));
298
290
  });
299
- LineItemPrice.displayName = 'Payment.LineItemPrice';
291
+ LineItemSubtotal.displayName = 'Payment.LineItemSubtotal';
300
292
  /**
301
293
  * Displays the line item discount.
302
294
  * Uses data-has-discount attribute for conditional visibility.
@@ -309,10 +301,7 @@ LineItemPrice.displayName = 'Payment.LineItemPrice';
309
301
  */
310
302
  export const LineItemDiscount = React.forwardRef((props, ref) => {
311
303
  const { asChild, children, className } = props;
312
- const { lineItem } = useLineItemContext();
313
- const { discount } = lineItem;
314
- const hasDiscount = discount !== null && discount.amount > 0;
315
- return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentLineItemDiscount, "data-has-discount": hasDiscount, customElement: children, customElementProps: { discount }, children: discount ? _jsx(Money, { money: discount }) : null }));
304
+ return (_jsx(CorePayment.LineItemInfo, { children: ({ discount, hasDiscount }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentLineItemDiscount, "data-has-discount": hasDiscount, customElement: children, customElementProps: { discount }, children: hasDiscount && _jsx(Money, { money: discount }) })) }));
316
305
  });
317
306
  LineItemDiscount.displayName = 'Payment.LineItemDiscount';
318
307
  /**
@@ -327,9 +316,6 @@ LineItemDiscount.displayName = 'Payment.LineItemDiscount';
327
316
  */
328
317
  export const LineItemDeposit = React.forwardRef((props, ref) => {
329
318
  const { asChild, children, className } = props;
330
- const { lineItem } = useLineItemContext();
331
- const { deposit } = lineItem;
332
- const hasDeposit = deposit !== null && deposit.amount > 0;
333
- return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentLineItemDeposit, "data-has-deposit": hasDeposit, customElement: children, customElementProps: { deposit }, children: deposit ? _jsx(Money, { money: deposit }) : null }));
319
+ return (_jsx(CorePayment.LineItemInfo, { children: ({ deposit, hasDeposit }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentLineItemDeposit, "data-has-deposit": hasDeposit, customElement: children, customElementProps: { deposit }, children: hasDeposit && _jsx(Money, { money: deposit }) })) }));
334
320
  });
335
321
  LineItemDeposit.displayName = 'Payment.LineItemDeposit';
@@ -25,24 +25,44 @@ export interface ValidationResult {
25
25
  /** Array of validation failure messages */
26
26
  validationFailures: string[];
27
27
  }
28
+ /**
29
+ * Error thrown when BookingFormService cannot be initialized due to missing configuration.
30
+ * This occurs when:
31
+ * - No config (formId or form) was provided
32
+ * - AND the component is not wrapped with Booking.Root (no BookingService available)
33
+ */
34
+ export declare class BookingFormConfigurationError extends Error {
35
+ constructor(message?: string);
36
+ }
28
37
  /**
29
38
  * Configuration for BookingFormService.
30
39
  * Supports two modes:
31
40
  * 1. Client-side loading: Provide formId to fetch the form dynamically
32
41
  * 2. SSR/SSG: Provide a pre-loaded form object (must be from bookings namespace)
33
42
  *
43
+ * Note: The config itself is optional. If not provided, the formId will be
44
+ * extracted from the selected service if available.
45
+ *
34
46
  * @example
35
47
  * ```tsx
36
48
  * // Pattern 1: Client-side loading
37
49
  * const config = { formId: 'form-123' };
38
50
  *
51
+ * // Pattern 1b: Client-side loading with service IDs
52
+ * const config = { formId: 'form-123', serviceIds: ['service-1', 'service-2'] };
53
+ *
39
54
  * // Pattern 2: Pre-loaded form (SSR/SSG)
40
55
  * const config = { form: preloadedForm };
56
+ *
57
+ * // Pattern 3: No config (formId extracted from service)
58
+ * // config = undefined
41
59
  * ```
42
60
  */
43
61
  export type BookingFormServiceConfig = {
44
62
  /** The form ID to load (client-side loading) */
45
63
  formId: string;
64
+ /** Optional list of service IDs associated with this booking form */
65
+ serviceIds?: string[];
46
66
  } | {
47
67
  /** Pre-loaded form object (SSR/SSG) - must be from bookings namespace */
48
68
  form: forms.Form;
@@ -79,18 +99,7 @@ export interface BookingFormServiceInternalAPI extends BookingFormServiceAPI {
79
99
  /** Internal: Register validate callback (called by core component) */
80
100
  _setValidateCallback: (callback: () => Promise<ValidationResult>) => void;
81
101
  }
82
- /**
83
- * Type guard to check if config has formId
84
- */
85
- export declare function hasFormId(config: BookingFormServiceConfig): config is {
86
- formId: string;
87
- };
88
- /**
89
- * Type guard to check if config has pre-loaded form
90
- */
91
- export declare function hasForm(config: BookingFormServiceConfig): config is {
92
- form: forms.Form;
93
- };
102
+ export { hasFormId, hasForm, extractFormIdFromForm, extractFormIdFromConfig, type FormIdConfig, } from './utils.js';
94
103
  /**
95
104
  * Service definition for BookingForm.
96
105
  * Defines the contract that the BookingFormService must implement.
@@ -137,4 +146,4 @@ export declare const BookingFormService: import("@wix/services-definitions").Ser
137
146
  __api: BookingFormServiceAPI;
138
147
  __config: {};
139
148
  isServiceDefinition?: boolean;
140
- } & BookingFormServiceAPI, BookingFormServiceConfig>;
149
+ } & BookingFormServiceAPI, BookingFormServiceConfig | undefined>;