@wix/headless-bookings 0.0.57 → 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.
- package/cjs/dist/react/booking/Booking.js +1 -1
- package/cjs/dist/react/core/booking/Booking.d.ts +3 -3
- package/cjs/dist/react/core/booking/Booking.js +2 -2
- package/cjs/dist/react/core/payment/Payment.d.ts +84 -5
- package/cjs/dist/react/core/payment/Payment.js +102 -4
- package/cjs/dist/react/payment/Payment.d.ts +64 -58
- package/cjs/dist/react/payment/Payment.js +66 -80
- package/cjs/dist/services/index.d.ts +1 -1
- package/cjs/dist/services/payment/payment.d.ts +4 -4
- package/cjs/dist/services/payment/payment.def.d.ts +4 -4
- package/cjs/dist/services/payment/payment.js +26 -18
- package/dist/react/booking/Booking.js +1 -1
- package/dist/react/core/booking/Booking.d.ts +3 -3
- package/dist/react/core/booking/Booking.js +2 -2
- package/dist/react/core/payment/Payment.d.ts +84 -5
- package/dist/react/core/payment/Payment.js +102 -4
- package/dist/react/payment/Payment.d.ts +64 -58
- package/dist/react/payment/Payment.js +66 -80
- package/dist/services/index.d.ts +1 -1
- package/dist/services/payment/payment.d.ts +4 -4
- package/dist/services/payment/payment.def.d.ts +4 -4
- package/dist/services/payment/payment.js +26 -18
- package/package.json +2 -2
|
@@ -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["
|
|
23
|
-
TestIds["
|
|
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:
|
|
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,
|
|
61
|
-
return (_jsx(CorePayment.Root, { paymentServiceConfig: paymentServiceConfig,
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
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
|
-
*
|
|
223
|
-
|
|
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.
|
|
231
|
-
*
|
|
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
|
|
257
|
+
const { children } = props;
|
|
249
258
|
const { currency } = useLineItemsContext();
|
|
250
|
-
|
|
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
|
-
*
|
|
267
|
-
*
|
|
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.
|
|
273
|
-
* <Payment.LineItemPrice />
|
|
274
|
-
* <Payment.LineItemDiscount />
|
|
275
|
-
* </Payment.LineItemRoot>
|
|
269
|
+
* <Payment.LineItemTotal className="text-2xl font-bold" />
|
|
276
270
|
* ```
|
|
277
271
|
*/
|
|
278
|
-
export const
|
|
279
|
-
const {
|
|
280
|
-
return (_jsx(
|
|
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
|
-
|
|
276
|
+
LineItemTotal.displayName = 'Payment.LineItemTotal';
|
|
283
277
|
/**
|
|
284
|
-
* Displays the line item price.
|
|
285
|
-
* Shows priceText for CUSTOM rate type services, otherwise shows
|
|
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.
|
|
284
|
+
* <Payment.LineItemSubtotal className="text-lg" />
|
|
291
285
|
* ```
|
|
292
286
|
*/
|
|
293
|
-
export const
|
|
287
|
+
export const LineItemSubtotal = React.forwardRef((props, ref) => {
|
|
294
288
|
const { asChild, children, className } = props;
|
|
295
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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';
|
|
@@ -8,6 +8,6 @@ export { TimeSlotListService, TimeSlotListServiceDefinition, TimeSlotService, Ti
|
|
|
8
8
|
export { ServiceListService, ServiceListServiceDefinition, type ServiceListServiceAPI, type ServiceListServiceConfig, type ServiceListFilters, type ServiceListActions, type QueryOptions, loadServiceListServiceInitialData, type SuccessServiceListServiceConfigResult, type ErrorServiceListServiceConfigResult, } from './service-list/service-list.js';
|
|
9
9
|
export { executeBookAction, canBook, buildBookingRequest, buildCheckoutRequest, type CanBookParams, type BookResult, type BookingError, type BookActionParams, type BookChildProps, type BookProps, type BuildCheckoutParams, } from './booking/book-action/index.js';
|
|
10
10
|
export { BookingFormService, BookingFormServiceDefinition, type BookingFormServiceAPI, type BookingFormServiceConfig, type BookingFormServiceInternalAPI, type ValidationResult, } from './booking-form/booking-form.js';
|
|
11
|
-
export { PaymentService, PaymentServiceDefinition, type PaymentServiceAPI, type PaymentServiceConfig, type PaymentDetails, type
|
|
11
|
+
export { PaymentService, PaymentServiceDefinition, type PaymentServiceAPI, type PaymentServiceConfig, type PaymentDetails, type PricingServiceSelection, type LineItemAdditionalInfo, loadPaymentConfig, type SuccessPaymentConfigResult, type ErrorPaymentConfigResult, } from './payment/payment.js';
|
|
12
12
|
export { LocationListService, LocationListServiceDefinition, LocationType, loadLocationListServiceInitialData, locationListServiceBinding, type LocationListServiceAPI, type LocationListServiceConfig, type LocationListActions, type LocationData, type DisplayLocation, type LoadLocationListServiceResult, } from './location-list/location-list.js';
|
|
13
13
|
export { StaffMemberListService, StaffMemberListServiceDefinition, loadStaffMemberListServiceInitialData, staffMemberListServiceBinding, type StaffMemberListServiceAPI, type StaffMemberListServiceConfig, type StaffMemberListActions, type StaffMemberData, type LoadStaffMemberListServiceResult, } from './staff-member-list/staff-member-list.js';
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Handles calculating total prices, taxes, discounts, and deposit information
|
|
4
4
|
* Supports two modes: SSR (config with pre-fetched data) and lazy loading (reactive)
|
|
5
5
|
*/
|
|
6
|
-
import { type PaymentServiceConfig, type PaymentServiceInternalConfig, type
|
|
7
|
-
export { PaymentServiceDefinition, type PaymentServiceConfig, type PaymentDetails, type LineItemAdditionalInfo, type
|
|
6
|
+
import { type PaymentServiceConfig, type PaymentServiceInternalConfig, type PricingServiceSelection } from './payment.def.js';
|
|
7
|
+
export { PaymentServiceDefinition, type PaymentServiceConfig, type PaymentDetails, type LineItemAdditionalInfo, type PricingServiceSelection, } from './payment.def.js';
|
|
8
8
|
export type { PaymentServiceAPI, PaymentServiceInternalConfig, } from './payment.def.js';
|
|
9
9
|
export declare const PaymentService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
10
10
|
__api: import("./payment.def.js").PaymentServiceAPI;
|
|
@@ -23,10 +23,10 @@ export type ErrorPaymentConfigResult = {
|
|
|
23
23
|
* Load payment configuration for Server-Side Rendering (SSR).
|
|
24
24
|
* Calls the pricing APIs and returns pre-calculated payment details.
|
|
25
25
|
*
|
|
26
|
-
* @param params.
|
|
26
|
+
* @param params.pricingServiceSelections - Pricing service selections for calculation
|
|
27
27
|
* @param params.numberOfParticipants - Number of participants (default: 1)
|
|
28
28
|
*/
|
|
29
29
|
export declare function loadPaymentConfig(params: {
|
|
30
|
-
|
|
30
|
+
pricingServiceSelections: PricingServiceSelection[];
|
|
31
31
|
numberOfParticipants?: number;
|
|
32
32
|
}): Promise<SuccessPaymentConfigResult | ErrorPaymentConfigResult>;
|
|
@@ -30,9 +30,9 @@ export interface PaymentDetails {
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
* Input for calculating payment for a
|
|
33
|
+
* Input for calculating payment for a booking service
|
|
34
34
|
*/
|
|
35
|
-
export interface
|
|
35
|
+
export interface PricingServiceSelection {
|
|
36
36
|
service: Service;
|
|
37
37
|
/** Optional line item ID. If not provided, one will be generated. */
|
|
38
38
|
lineItemId?: string;
|
|
@@ -50,8 +50,8 @@ export interface PaymentServiceConfig {
|
|
|
50
50
|
* Not exposed publicly - Core merges this with PaymentServiceConfig
|
|
51
51
|
*/
|
|
52
52
|
export interface PaymentServiceInternalConfig extends PaymentServiceConfig {
|
|
53
|
-
/**
|
|
54
|
-
|
|
53
|
+
/** Booking services for lazy loading (internal use) */
|
|
54
|
+
pricingServiceSelections?: PricingServiceSelection[];
|
|
55
55
|
/** Number of participants for lazy loading (internal use) */
|
|
56
56
|
numberOfParticipants?: number;
|
|
57
57
|
}
|
|
@@ -60,11 +60,11 @@ function buildLineItem(service, numberOfParticipants, lineItemId) {
|
|
|
60
60
|
paymentOption,
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
-
async function calculatePaymentDetails(
|
|
64
|
-
// Ensure all
|
|
65
|
-
const data =
|
|
66
|
-
...
|
|
67
|
-
lineItemId:
|
|
63
|
+
async function calculatePaymentDetails(pricingServiceSelections, numberOfParticipants) {
|
|
64
|
+
// Ensure all booking services have a lineItemId
|
|
65
|
+
const data = pricingServiceSelections.map((selection) => ({
|
|
66
|
+
...selection,
|
|
67
|
+
lineItemId: selection.lineItemId || generateLineItemId(),
|
|
68
68
|
}));
|
|
69
69
|
const lineItems = data.map((item) => buildLineItem(item.service, numberOfParticipants, item.lineItemId));
|
|
70
70
|
const response = await calculateTotals({
|
|
@@ -96,15 +96,15 @@ export const PaymentService = implementService.withConfig()(PaymentServiceDefini
|
|
|
96
96
|
const isLoadingSignal = signalsService.signal(false);
|
|
97
97
|
const errorSignal = signalsService.signal(null);
|
|
98
98
|
// Internal calculate function
|
|
99
|
-
const calculate = async (
|
|
100
|
-
if (!
|
|
99
|
+
const calculate = async (pricingServiceSelections, numberOfParticipants) => {
|
|
100
|
+
if (!pricingServiceSelections.length) {
|
|
101
101
|
paymentDetailsSignal.set(null);
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
104
|
isLoadingSignal.set(true);
|
|
105
105
|
errorSignal.set(null);
|
|
106
106
|
try {
|
|
107
|
-
const paymentDetails = await calculatePaymentDetails(
|
|
107
|
+
const paymentDetails = await calculatePaymentDetails(pricingServiceSelections, numberOfParticipants);
|
|
108
108
|
paymentDetailsSignal.set(paymentDetails);
|
|
109
109
|
}
|
|
110
110
|
catch (error) {
|
|
@@ -122,22 +122,30 @@ export const PaymentService = implementService.withConfig()(PaymentServiceDefini
|
|
|
122
122
|
if (config.paymentDetails) {
|
|
123
123
|
// No-op - data is pre-fetched
|
|
124
124
|
}
|
|
125
|
-
// Mode 2: Lazy loading -
|
|
126
|
-
else if (config.
|
|
127
|
-
void calculate(config.
|
|
125
|
+
// Mode 2: Lazy loading - pricingServiceSelections provided via internal config
|
|
126
|
+
else if (config.pricingServiceSelections?.length) {
|
|
127
|
+
void calculate(config.pricingServiceSelections, config.numberOfParticipants ?? 1);
|
|
128
128
|
}
|
|
129
129
|
// Mode 3: Reactive - observe BookingService signals (client-side only)
|
|
130
130
|
else if (typeof window !== 'undefined' && bookingService) {
|
|
131
|
-
|
|
131
|
+
// Computed signal that only changes when services change (not participants)
|
|
132
|
+
const servicesKey = signalsService.computed(() => {
|
|
132
133
|
const selections = bookingService?.serviceSelections.get() || [];
|
|
134
|
+
return selections.map((s) => s.service._id).join(',');
|
|
135
|
+
});
|
|
136
|
+
signalsService.effect(() => {
|
|
137
|
+
// Subscribe to servicesKey to trigger effect only when services change
|
|
138
|
+
servicesKey.get();
|
|
139
|
+
// Read current selections without subscribing (peek)
|
|
140
|
+
const selections = bookingService?.serviceSelections.peek() || [];
|
|
133
141
|
// For single service mode, take the first selection
|
|
134
142
|
const firstSelection = selections[0];
|
|
135
143
|
const numParticipants = firstSelection?.totalParticipants || 1;
|
|
136
|
-
const
|
|
144
|
+
const pricingServiceSelections = selections.map((selection) => ({
|
|
137
145
|
service: selection.service,
|
|
138
146
|
lineItemId: selection.instanceId,
|
|
139
147
|
}));
|
|
140
|
-
void calculate(
|
|
148
|
+
void calculate(pricingServiceSelections, numParticipants);
|
|
141
149
|
});
|
|
142
150
|
}
|
|
143
151
|
return {
|
|
@@ -150,19 +158,19 @@ export const PaymentService = implementService.withConfig()(PaymentServiceDefini
|
|
|
150
158
|
* Load payment configuration for Server-Side Rendering (SSR).
|
|
151
159
|
* Calls the pricing APIs and returns pre-calculated payment details.
|
|
152
160
|
*
|
|
153
|
-
* @param params.
|
|
161
|
+
* @param params.pricingServiceSelections - Pricing service selections for calculation
|
|
154
162
|
* @param params.numberOfParticipants - Number of participants (default: 1)
|
|
155
163
|
*/
|
|
156
164
|
export async function loadPaymentConfig(params) {
|
|
157
165
|
try {
|
|
158
|
-
const {
|
|
159
|
-
if (!
|
|
166
|
+
const { pricingServiceSelections, numberOfParticipants = 1 } = params;
|
|
167
|
+
if (!pricingServiceSelections.length) {
|
|
160
168
|
return {
|
|
161
169
|
type: 'success',
|
|
162
170
|
config: { paymentDetails: undefined },
|
|
163
171
|
};
|
|
164
172
|
}
|
|
165
|
-
const paymentDetails = await calculatePaymentDetails(
|
|
173
|
+
const paymentDetails = await calculatePaymentDetails(pricingServiceSelections, numberOfParticipants);
|
|
166
174
|
return {
|
|
167
175
|
type: 'success',
|
|
168
176
|
config: { paymentDetails },
|
|
@@ -227,7 +227,7 @@ export function TimeSlot(props) {
|
|
|
227
227
|
*/
|
|
228
228
|
export function Payment(props) {
|
|
229
229
|
const { children } = props;
|
|
230
|
-
return (_jsx(CoreBooking.PaymentData, { children: ({
|
|
230
|
+
return (_jsx(CoreBooking.PaymentData, { children: ({ pricingServiceSelections }) => (_jsx(PaymentComponent.Root, { pricingServiceSelections: pricingServiceSelections, children: children })) }));
|
|
231
231
|
}
|
|
232
232
|
/**
|
|
233
233
|
* Wraps Location context with the location from the booking context.
|
|
@@ -7,7 +7,7 @@ import { type BookingServiceConfig, type ServiceSelection, type BookingServiceAc
|
|
|
7
7
|
import type { FormValues } from '@wix/form-public';
|
|
8
8
|
import type { TimeSlot, Resource } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
9
9
|
import type { Service, Location as ServiceLocationType } from '@wix/auto_sdk_bookings_services';
|
|
10
|
-
import type {
|
|
10
|
+
import type { PricingServiceSelection } from '../../../services/payment/payment.js';
|
|
11
11
|
/**
|
|
12
12
|
* Props for Booking.Root component
|
|
13
13
|
*/
|
|
@@ -167,8 +167,8 @@ export declare function ItemsData(props: ItemsDataProps): React.ReactNode;
|
|
|
167
167
|
* Data exposed by PaymentData render prop
|
|
168
168
|
*/
|
|
169
169
|
export interface PaymentDataRenderProps {
|
|
170
|
-
/**
|
|
171
|
-
|
|
170
|
+
/** Pricing service selections array for Payment.Root */
|
|
171
|
+
pricingServiceSelections: PricingServiceSelection[];
|
|
172
172
|
}
|
|
173
173
|
/**
|
|
174
174
|
* Props for PaymentData render prop component
|
|
@@ -267,9 +267,9 @@ export function PaymentData(props) {
|
|
|
267
267
|
const { children } = props;
|
|
268
268
|
const bookingService = useService(BookingServiceDefinition);
|
|
269
269
|
const serviceSelections = bookingService.serviceSelections.get();
|
|
270
|
-
const
|
|
270
|
+
const pricingServiceSelections = serviceSelections.map((selection) => ({
|
|
271
271
|
service: selection.service,
|
|
272
272
|
lineItemId: selection.instanceId,
|
|
273
273
|
}));
|
|
274
|
-
return children({
|
|
274
|
+
return children({ pricingServiceSelections });
|
|
275
275
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Note: Currently supports single service only
|
|
5
5
|
*/
|
|
6
6
|
import React from 'react';
|
|
7
|
-
import { type PaymentServiceConfig, type
|
|
7
|
+
import { type PaymentServiceConfig, type PricingServiceSelection } from '../../../services/payment/payment.js';
|
|
8
8
|
import type { MoneyData } from '@wix/headless-components/react';
|
|
9
9
|
/**
|
|
10
10
|
* Props for Payment.Root component
|
|
@@ -16,8 +16,8 @@ export interface RootProps {
|
|
|
16
16
|
}) => React.ReactNode);
|
|
17
17
|
/** Service config - SSR only (paymentDetails) */
|
|
18
18
|
paymentServiceConfig?: PaymentServiceConfig;
|
|
19
|
-
/**
|
|
20
|
-
|
|
19
|
+
/** Pricing service selections for lazy loading (triggers API call) */
|
|
20
|
+
pricingServiceSelections?: PricingServiceSelection[];
|
|
21
21
|
/** Number of participants for lazy loading */
|
|
22
22
|
numberOfParticipants?: number;
|
|
23
23
|
}
|
|
@@ -25,7 +25,7 @@ export interface RootProps {
|
|
|
25
25
|
* Root component that provides payment context.
|
|
26
26
|
* Supports 3 modes:
|
|
27
27
|
* 1. SSR: paymentServiceConfig.paymentDetails - pre-fetched data
|
|
28
|
-
* 2. Lazy loading:
|
|
28
|
+
* 2. Lazy loading: pricingServiceSelections + numberOfParticipants props - calls API on init
|
|
29
29
|
* 3. Reactive: no config/props - reads from BookingService signals
|
|
30
30
|
*
|
|
31
31
|
* @component
|
|
@@ -37,7 +37,7 @@ export interface RootProps {
|
|
|
37
37
|
* </Payment.Root>
|
|
38
38
|
*
|
|
39
39
|
* // Lazy loading mode
|
|
40
|
-
* <Payment.Root
|
|
40
|
+
* <Payment.Root pricingServiceSelections={[...]} numberOfParticipants={2}>
|
|
41
41
|
* {({ isLoading }) => isLoading ? <div>Loading...</div> : <Payment.Total />}
|
|
42
42
|
* </Payment.Root>
|
|
43
43
|
*
|
|
@@ -59,6 +59,12 @@ export interface DataProps {
|
|
|
59
59
|
discount: MoneyData | null;
|
|
60
60
|
payNow: MoneyData | null;
|
|
61
61
|
payLater: MoneyData | null;
|
|
62
|
+
priceText: string | null;
|
|
63
|
+
hasPriceText: boolean;
|
|
64
|
+
isFree: boolean;
|
|
65
|
+
hasTax: boolean;
|
|
66
|
+
hasDiscount: boolean;
|
|
67
|
+
isDeposit: boolean;
|
|
62
68
|
currency: string;
|
|
63
69
|
isLoading: boolean;
|
|
64
70
|
error: string | null;
|
|
@@ -123,3 +129,76 @@ export interface LineItemsProps {
|
|
|
123
129
|
* ```
|
|
124
130
|
*/
|
|
125
131
|
export declare function LineItems(props: LineItemsProps): React.ReactNode;
|
|
132
|
+
/**
|
|
133
|
+
* Context value for LineItem components
|
|
134
|
+
*/
|
|
135
|
+
export interface LineItemContextValue {
|
|
136
|
+
lineItem: LineItem;
|
|
137
|
+
currency: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Hook to access the current LineItem from context.
|
|
141
|
+
* Must be used within LineItemProvider.
|
|
142
|
+
*
|
|
143
|
+
* @throws Error if used outside of LineItemProvider context
|
|
144
|
+
*/
|
|
145
|
+
export declare function useLineItemContext(): LineItemContextValue;
|
|
146
|
+
/**
|
|
147
|
+
* Props for LineItemProvider
|
|
148
|
+
*/
|
|
149
|
+
export interface LineItemProviderProps {
|
|
150
|
+
children: React.ReactNode;
|
|
151
|
+
lineItem: LineItem;
|
|
152
|
+
currency: string;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Provider component used by repeaters to provide LineItem context.
|
|
156
|
+
* Can be used by core consumers to create their own repeater.
|
|
157
|
+
*
|
|
158
|
+
* @component
|
|
159
|
+
* @example
|
|
160
|
+
* ```tsx
|
|
161
|
+
* {lineItems.map((item) => (
|
|
162
|
+
* <LineItemProvider key={item.id} lineItem={item} currency={currency}>
|
|
163
|
+
* {children}
|
|
164
|
+
* </LineItemProvider>
|
|
165
|
+
* ))}
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
export declare function LineItemProvider(props: LineItemProviderProps): React.ReactNode;
|
|
169
|
+
/**
|
|
170
|
+
* Props for LineItemInfo render prop component
|
|
171
|
+
*/
|
|
172
|
+
export interface LineItemInfoProps {
|
|
173
|
+
children: (data: {
|
|
174
|
+
lineItem: LineItem;
|
|
175
|
+
currency: string;
|
|
176
|
+
totalPrice: MoneyData | null;
|
|
177
|
+
subtotal: MoneyData | null;
|
|
178
|
+
tax: MoneyData | null;
|
|
179
|
+
discount: MoneyData | null;
|
|
180
|
+
deposit: MoneyData | null;
|
|
181
|
+
priceText: string | null;
|
|
182
|
+
hasPriceText: boolean;
|
|
183
|
+
isFree: boolean;
|
|
184
|
+
hasDiscount: boolean;
|
|
185
|
+
hasDeposit: boolean;
|
|
186
|
+
}) => React.ReactNode;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Core component that provides access to line item info via render props.
|
|
190
|
+
* Must be used within LineItemProvider.
|
|
191
|
+
*
|
|
192
|
+
* @component
|
|
193
|
+
* @example
|
|
194
|
+
* ```tsx
|
|
195
|
+
* <LineItemInfo>
|
|
196
|
+
* {({ totalPrice, priceText, lineItem }) => (
|
|
197
|
+
* <div>
|
|
198
|
+
* {priceText ? <span>{priceText}</span> : <Money money={totalPrice} />}
|
|
199
|
+
* </div>
|
|
200
|
+
* )}
|
|
201
|
+
* </LineItemInfo>
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
export declare function LineItemInfo(props: LineItemInfoProps): React.ReactNode;
|