@wix/headless-bookings 0.0.38 → 0.0.40
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/core/payment/Payment.d.ts +36 -104
- package/cjs/dist/react/core/payment/Payment.js +29 -111
- package/cjs/dist/react/core/time-slot-list/TimeSlot.d.ts +14 -22
- package/cjs/dist/react/core/time-slot-list/TimeSlot.js +30 -34
- package/cjs/dist/react/index.d.ts +0 -1
- package/cjs/dist/react/index.js +0 -1
- package/cjs/dist/react/payment/Payment.d.ts +119 -82
- package/cjs/dist/react/payment/Payment.js +126 -81
- package/cjs/dist/react/time-slot-list/TimeSlot.d.ts +24 -2
- package/cjs/dist/react/time-slot-list/TimeSlot.js +18 -2
- package/cjs/dist/react/time-slot-list/TimeSlotList.js +3 -5
- package/cjs/dist/services/index.d.ts +1 -1
- package/cjs/dist/services/index.js +1 -1
- package/cjs/dist/services/payment/payment.def.d.ts +2 -1
- package/cjs/dist/services/payment/payment.js +8 -2
- package/cjs/dist/services/time-slot-list/index.d.ts +1 -0
- package/cjs/dist/services/time-slot-list/index.js +1 -0
- package/cjs/dist/services/time-slot-list/time-slot.d.ts +35 -0
- package/cjs/dist/services/time-slot-list/time-slot.js +20 -0
- package/cjs/dist/utils/guid.d.ts +7 -0
- package/cjs/dist/utils/guid.js +12 -0
- package/dist/react/core/payment/Payment.d.ts +36 -104
- package/dist/react/core/payment/Payment.js +29 -111
- package/dist/react/core/time-slot-list/TimeSlot.d.ts +14 -22
- package/dist/react/core/time-slot-list/TimeSlot.js +30 -34
- package/dist/react/index.d.ts +0 -1
- package/dist/react/index.js +0 -1
- package/dist/react/payment/Payment.d.ts +119 -82
- package/dist/react/payment/Payment.js +126 -81
- package/dist/react/time-slot-list/TimeSlot.d.ts +24 -2
- package/dist/react/time-slot-list/TimeSlot.js +18 -2
- package/dist/react/time-slot-list/TimeSlotList.js +3 -5
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/payment/payment.def.d.ts +2 -1
- package/dist/services/payment/payment.js +8 -2
- package/dist/services/time-slot-list/index.d.ts +1 -0
- package/dist/services/time-slot-list/index.js +1 -0
- package/dist/services/time-slot-list/time-slot.d.ts +35 -0
- package/dist/services/time-slot-list/time-slot.js +20 -0
- package/dist/utils/guid.d.ts +7 -0
- package/dist/utils/guid.js +12 -0
- package/package.json +2 -2
- package/cjs/dist/react/payment/PaymentLineItem.d.ts +0 -144
- package/cjs/dist/react/payment/PaymentLineItem.js +0 -141
- package/dist/react/payment/PaymentLineItem.d.ts +0 -144
- package/dist/react/payment/PaymentLineItem.js +0 -141
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* Payment - High-level component for displaying payment information
|
|
4
4
|
* Provides components for displaying payment summary, totals, and line items
|
|
5
5
|
*/
|
|
6
6
|
import React from 'react';
|
|
7
7
|
import * as CorePayment from '../core/payment/Payment.js';
|
|
8
|
-
import * as PaymentLineItem from './PaymentLineItem.js';
|
|
9
8
|
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
10
9
|
import { Money, GenericList } from '@wix/headless-components/react';
|
|
11
10
|
var TestIds;
|
|
12
11
|
(function (TestIds) {
|
|
13
12
|
TestIds["paymentRoot"] = "payment-root";
|
|
14
|
-
TestIds["paymentSummary"] = "payment-summary";
|
|
15
13
|
TestIds["paymentSubtotal"] = "payment-subtotal";
|
|
16
14
|
TestIds["paymentTax"] = "payment-tax";
|
|
17
15
|
TestIds["paymentDiscount"] = "payment-discount";
|
|
@@ -21,6 +19,10 @@ var TestIds;
|
|
|
21
19
|
TestIds["paymentLineItems"] = "payment-line-items";
|
|
22
20
|
TestIds["paymentLineItemsList"] = "payment-line-items-list";
|
|
23
21
|
TestIds["paymentLineItemRepeater"] = "payment-line-item-repeater";
|
|
22
|
+
TestIds["paymentLineItemRoot"] = "payment-line-item-root";
|
|
23
|
+
TestIds["paymentLineItemPrice"] = "payment-line-item-price";
|
|
24
|
+
TestIds["paymentLineItemDiscount"] = "payment-line-item-discount";
|
|
25
|
+
TestIds["paymentLineItemDeposit"] = "payment-line-item-deposit";
|
|
24
26
|
})(TestIds || (TestIds = {}));
|
|
25
27
|
/**
|
|
26
28
|
* Root component that provides payment context to the entire app.
|
|
@@ -33,13 +35,13 @@ var TestIds;
|
|
|
33
35
|
* @component
|
|
34
36
|
* @example
|
|
35
37
|
* ```tsx
|
|
36
|
-
* import { Payment
|
|
38
|
+
* import { Payment } from '@wix/bookings/components';
|
|
37
39
|
*
|
|
38
40
|
* // SSR mode
|
|
39
41
|
* function PaymentPage({ paymentDetails }) {
|
|
40
42
|
* return (
|
|
41
43
|
* <Payment.Root paymentServiceConfig={{ paymentDetails }}>
|
|
42
|
-
* <Payment.
|
|
44
|
+
* <Payment.Total />
|
|
43
45
|
* </Payment.Root>
|
|
44
46
|
* );
|
|
45
47
|
* }
|
|
@@ -48,7 +50,7 @@ var TestIds;
|
|
|
48
50
|
* function LazyPayment({ slotServices }) {
|
|
49
51
|
* return (
|
|
50
52
|
* <Payment.Root slotServices={slotServices} numberOfParticipants={2}>
|
|
51
|
-
* {({ isLoading }) => isLoading ? <div>Loading...</div> : <Payment.
|
|
53
|
+
* {({ isLoading }) => isLoading ? <div>Loading...</div> : <Payment.Total />}
|
|
52
54
|
* </Payment.Root>
|
|
53
55
|
* );
|
|
54
56
|
* }
|
|
@@ -61,40 +63,6 @@ export const Root = React.forwardRef((props, ref) => {
|
|
|
61
63
|
} }));
|
|
62
64
|
});
|
|
63
65
|
Root.displayName = 'Payment.Root';
|
|
64
|
-
/**
|
|
65
|
-
* Displays the payment summary with totals.
|
|
66
|
-
* Uses data-attributes for conditional visibility via CSS.
|
|
67
|
-
*
|
|
68
|
-
* @component
|
|
69
|
-
* @example
|
|
70
|
-
* ```tsx
|
|
71
|
-
* // Default usage - renders subtotal, tax, discount, total
|
|
72
|
-
* <Payment.Summary className="space-y-2" />
|
|
73
|
-
*
|
|
74
|
-
* // Custom rendering with full summary data
|
|
75
|
-
* <Payment.Summary asChild>
|
|
76
|
-
* {({ subtotal, tax, hasTax, discount, hasDiscount, total, payNow, isDeposit }) => (
|
|
77
|
-
* <div>
|
|
78
|
-
* <div>Subtotal: <Money money={subtotal} /></div>
|
|
79
|
-
* <div data-has-tax={hasTax}>Tax: <Money money={tax} /></div>
|
|
80
|
-
* <div data-has-discount={hasDiscount}>Discount: <Money money={discount} /></div>
|
|
81
|
-
* <div>Total: <Money money={total} /></div>
|
|
82
|
-
* <div data-has-deposit={isDeposit}>Pay Now: <Money money={payNow} /></div>
|
|
83
|
-
* </div>
|
|
84
|
-
* )}
|
|
85
|
-
* </Payment.Summary>
|
|
86
|
-
* ```
|
|
87
|
-
*/
|
|
88
|
-
export const Summary = React.forwardRef((props, ref) => {
|
|
89
|
-
const { asChild, children, className } = props;
|
|
90
|
-
return (_jsx(CorePayment.Summary, { children: (summaryData) => {
|
|
91
|
-
const { subtotal, total, tax, discount, payNow, payLater, isDeposit, } = summaryData;
|
|
92
|
-
// Default rendering
|
|
93
|
-
const renderDefaultSummary = () => (_jsxs("div", { className: className, "data-testid": TestIds.paymentSummary, children: [_jsx("div", { "data-testid": TestIds.paymentSubtotal, children: subtotal && _jsx(Money, { money: subtotal }) }), _jsx("div", { "data-testid": TestIds.paymentTax, "data-has-tax": tax !== null && tax.amount > 0, children: tax && _jsx(Money, { money: tax }) }), _jsx("div", { "data-testid": TestIds.paymentDiscount, "data-has-discount": discount !== null && discount.amount > 0, children: discount && _jsx(Money, { money: discount }) }), _jsx("div", { "data-testid": TestIds.paymentTotal, children: total && _jsx(Money, { money: total }) }), _jsx("div", { "data-testid": TestIds.paymentPayNow, "data-has-deposit": isDeposit, children: payNow && _jsx(Money, { money: payNow }) }), _jsx("div", { "data-testid": TestIds.paymentPayLater, "data-has-deposit": isDeposit, children: payLater && _jsx(Money, { money: payLater }) })] }));
|
|
94
|
-
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentSummary, "data-has-tax": tax !== null && tax.amount > 0, "data-has-discount": discount !== null && discount.amount > 0, "data-has-deposit": isDeposit, customElement: children, customElementProps: summaryData, children: renderDefaultSummary() }));
|
|
95
|
-
} }));
|
|
96
|
-
});
|
|
97
|
-
Summary.displayName = 'Payment.Summary';
|
|
98
66
|
/**
|
|
99
67
|
* Displays the payment subtotal.
|
|
100
68
|
*
|
|
@@ -106,7 +74,7 @@ Summary.displayName = 'Payment.Summary';
|
|
|
106
74
|
*/
|
|
107
75
|
export const Subtotal = React.forwardRef((props, ref) => {
|
|
108
76
|
const { asChild, children, className } = props;
|
|
109
|
-
return (_jsx(CorePayment.
|
|
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 })) }));
|
|
110
78
|
});
|
|
111
79
|
Subtotal.displayName = 'Payment.Subtotal';
|
|
112
80
|
/**
|
|
@@ -121,7 +89,10 @@ Subtotal.displayName = 'Payment.Subtotal';
|
|
|
121
89
|
*/
|
|
122
90
|
export const Tax = React.forwardRef((props, ref) => {
|
|
123
91
|
const { asChild, children, className } = props;
|
|
124
|
-
return (_jsx(CorePayment.
|
|
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
|
+
} }));
|
|
125
96
|
});
|
|
126
97
|
Tax.displayName = 'Payment.Tax';
|
|
127
98
|
/**
|
|
@@ -136,7 +107,10 @@ Tax.displayName = 'Payment.Tax';
|
|
|
136
107
|
*/
|
|
137
108
|
export const Discount = React.forwardRef((props, ref) => {
|
|
138
109
|
const { asChild, children, className } = props;
|
|
139
|
-
return (_jsx(CorePayment.
|
|
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
|
+
} }));
|
|
140
114
|
});
|
|
141
115
|
Discount.displayName = 'Payment.Discount';
|
|
142
116
|
/**
|
|
@@ -150,7 +124,7 @@ Discount.displayName = 'Payment.Discount';
|
|
|
150
124
|
*/
|
|
151
125
|
export const Total = React.forwardRef((props, ref) => {
|
|
152
126
|
const { asChild, children, className } = props;
|
|
153
|
-
return (_jsx(CorePayment.
|
|
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 })) }));
|
|
154
128
|
});
|
|
155
129
|
Total.displayName = 'Payment.Total';
|
|
156
130
|
/**
|
|
@@ -165,7 +139,10 @@ Total.displayName = 'Payment.Total';
|
|
|
165
139
|
*/
|
|
166
140
|
export const PayNow = React.forwardRef((props, ref) => {
|
|
167
141
|
const { asChild, children, className } = props;
|
|
168
|
-
return (_jsx(CorePayment.
|
|
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
|
+
} }));
|
|
169
146
|
});
|
|
170
147
|
PayNow.displayName = 'Payment.PayNow';
|
|
171
148
|
/**
|
|
@@ -180,51 +157,36 @@ PayNow.displayName = 'Payment.PayNow';
|
|
|
180
157
|
*/
|
|
181
158
|
export const PayLater = React.forwardRef((props, ref) => {
|
|
182
159
|
const { asChild, children, className } = props;
|
|
183
|
-
return (_jsx(CorePayment.
|
|
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
|
+
} }));
|
|
184
164
|
});
|
|
185
165
|
PayLater.displayName = 'Payment.PayLater';
|
|
186
166
|
/**
|
|
187
167
|
* Container component for line items.
|
|
188
168
|
* Follows the 3-level List/Options/Repeater pattern.
|
|
189
|
-
* Provides context and
|
|
169
|
+
* Provides context and handles loading/error states via GenericList.
|
|
190
170
|
*
|
|
191
171
|
* @component
|
|
192
172
|
* @example
|
|
193
173
|
* ```tsx
|
|
194
174
|
* <Payment.LineItems>
|
|
195
|
-
* <Payment.LineItemsList
|
|
175
|
+
* <Payment.LineItemsList
|
|
176
|
+
* emptyState={<div>No items</div>}
|
|
177
|
+
* loadingState={<div>Loading...</div>}
|
|
178
|
+
* errorState={<div>Failed to load</div>}
|
|
179
|
+
* >
|
|
196
180
|
* <Payment.LineItemRepeater>
|
|
197
|
-
* <
|
|
181
|
+
* <Payment.LineItemPrice />
|
|
198
182
|
* </Payment.LineItemRepeater>
|
|
199
183
|
* </Payment.LineItemsList>
|
|
200
184
|
* </Payment.LineItems>
|
|
201
|
-
*
|
|
202
|
-
* // With asChild pattern for custom container
|
|
203
|
-
* <Payment.LineItems asChild>
|
|
204
|
-
* {({ lineItems, currency }) => (
|
|
205
|
-
* <div className="border rounded p-4">
|
|
206
|
-
* <Payment.LineItemsList>
|
|
207
|
-
* <Payment.LineItemRepeater>
|
|
208
|
-
* <LineItem.Price />
|
|
209
|
-
* </Payment.LineItemRepeater>
|
|
210
|
-
* </Payment.LineItemsList>
|
|
211
|
-
* </div>
|
|
212
|
-
* )}
|
|
213
|
-
* </Payment.LineItems>
|
|
214
185
|
* ```
|
|
215
186
|
*/
|
|
216
187
|
export const LineItems = React.forwardRef((props, ref) => {
|
|
217
188
|
const { asChild, children, className, ...attributes } = props;
|
|
218
|
-
return (_jsx(CorePayment.LineItems, { children: ({ lineItems, currency }) => {
|
|
219
|
-
if (!lineItems.length)
|
|
220
|
-
return null;
|
|
221
|
-
// Map line items to include required id field for GenericList
|
|
222
|
-
const items = lineItems.map((item, index) => ({
|
|
223
|
-
...item,
|
|
224
|
-
id: item.sdkLineItem.lineItemId || String(index),
|
|
225
|
-
}));
|
|
226
|
-
return (_jsx(GenericList.Root, { items: items, children: _jsx(LineItemsContext.Provider, { value: { currency }, children: _jsx(AsChildSlot, { ...attributes, ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentLineItems, customElement: children, customElementProps: { lineItems, currency }, children: _jsx("div", { children: React.isValidElement(children) ? children : null }) }) }) }));
|
|
227
|
-
} }));
|
|
189
|
+
return (_jsx(CorePayment.LineItems, { children: ({ lineItems, currency, isLoading, error }) => (_jsx(GenericList.Root, { items: lineItems, isLoading: isLoading, error: error, children: _jsx(LineItemsContext.Provider, { value: { currency }, children: _jsx(AsChildSlot, { ...attributes, ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentLineItems, "data-loading": isLoading, "data-error": !!error, customElement: children, customElementProps: { lineItems, currency, isLoading, error }, children: _jsx("div", { children: React.isValidElement(children) ? children : null }) }) }) })) }));
|
|
228
190
|
});
|
|
229
191
|
LineItems.displayName = 'Payment.LineItems';
|
|
230
192
|
// Context for line items currency
|
|
@@ -237,23 +199,27 @@ function useLineItemsContext() {
|
|
|
237
199
|
return context;
|
|
238
200
|
}
|
|
239
201
|
/**
|
|
240
|
-
* List container for line items with empty state support.
|
|
202
|
+
* List container for line items with empty/loading/error state support.
|
|
241
203
|
*
|
|
242
204
|
* @component
|
|
243
205
|
* @example
|
|
244
206
|
* ```tsx
|
|
245
|
-
* <Payment.LineItemsList
|
|
207
|
+
* <Payment.LineItemsList
|
|
208
|
+
* emptyState={<div>No items</div>}
|
|
209
|
+
* loadingState={<div>Loading...</div>}
|
|
210
|
+
* errorState={<div>Failed to load payment details</div>}
|
|
211
|
+
* >
|
|
246
212
|
* <Payment.LineItemRepeater />
|
|
247
213
|
* </Payment.LineItemsList>
|
|
248
214
|
* ```
|
|
249
215
|
*/
|
|
250
216
|
export const LineItemsList = React.forwardRef((props, ref) => {
|
|
251
|
-
const { children, emptyState, className, ...otherProps } = props;
|
|
252
|
-
return (_jsx(GenericList.Items, { ref: ref, emptyState: emptyState, className: className, "data-testid": TestIds.paymentLineItemsList, ...otherProps, children: children }));
|
|
217
|
+
const { children, emptyState, loadingState, errorState, className, ...otherProps } = props;
|
|
218
|
+
return (_jsx(GenericList.Items, { ref: ref, emptyState: emptyState, loadingState: loadingState, errorState: errorState, className: className, "data-testid": TestIds.paymentLineItemsList, ...otherProps, children: children }));
|
|
253
219
|
});
|
|
254
220
|
LineItemsList.displayName = 'Payment.LineItemsList';
|
|
255
221
|
/**
|
|
256
|
-
* Repeater component that renders
|
|
222
|
+
* Repeater component that renders LineItemRoot for each line item.
|
|
257
223
|
* Supports asChild pattern for custom rendering.
|
|
258
224
|
*
|
|
259
225
|
* @component
|
|
@@ -261,7 +227,7 @@ LineItemsList.displayName = 'Payment.LineItemsList';
|
|
|
261
227
|
* ```tsx
|
|
262
228
|
* // Standard usage
|
|
263
229
|
* <Payment.LineItemRepeater>
|
|
264
|
-
* <
|
|
230
|
+
* <Payment.LineItemPrice />
|
|
265
231
|
* </Payment.LineItemRepeater>
|
|
266
232
|
*
|
|
267
233
|
* // AsChild usage with custom list
|
|
@@ -270,7 +236,7 @@ LineItemsList.displayName = 'Payment.LineItemsList';
|
|
|
270
236
|
* <ol>
|
|
271
237
|
* {items.map((item, index) => (
|
|
272
238
|
* <li key={item.id}>
|
|
273
|
-
* {itemWrapper({ item, index, children: <
|
|
239
|
+
* {itemWrapper({ item, index, children: <Payment.LineItemPrice /> })}
|
|
274
240
|
* </li>
|
|
275
241
|
* ))}
|
|
276
242
|
* </ol>
|
|
@@ -281,10 +247,89 @@ LineItemsList.displayName = 'Payment.LineItemsList';
|
|
|
281
247
|
export const LineItemRepeater = React.forwardRef((props, ref) => {
|
|
282
248
|
const { children, asChild } = props;
|
|
283
249
|
const { currency } = useLineItemsContext();
|
|
284
|
-
// Custom itemWrapper that renders
|
|
250
|
+
// Custom itemWrapper that renders LineItemRoot for each line item
|
|
285
251
|
const lineItemWrapper = ({ item, children: itemChildren, }) => {
|
|
286
|
-
return (_jsx(
|
|
252
|
+
return (_jsx(LineItemRoot, { lineItem: item, currency: currency, "data-testid": TestIds.paymentLineItemRepeater, children: itemChildren || undefined }, item.id));
|
|
287
253
|
};
|
|
288
254
|
return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: lineItemWrapper, asChild: asChild, children: children }));
|
|
289
255
|
});
|
|
290
256
|
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
|
+
/**
|
|
266
|
+
* Root component for a single line item.
|
|
267
|
+
* Provides context for child components.
|
|
268
|
+
*
|
|
269
|
+
* @component
|
|
270
|
+
* @example
|
|
271
|
+
* ```tsx
|
|
272
|
+
* <Payment.LineItemRoot lineItem={item} currency="USD">
|
|
273
|
+
* <Payment.LineItemPrice />
|
|
274
|
+
* <Payment.LineItemDiscount />
|
|
275
|
+
* </Payment.LineItemRoot>
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
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 }) }) }));
|
|
281
|
+
});
|
|
282
|
+
LineItemRoot.displayName = 'Payment.LineItemRoot';
|
|
283
|
+
/**
|
|
284
|
+
* Displays the line item price.
|
|
285
|
+
* Shows priceText for CUSTOM rate type services, otherwise shows totalPrice.
|
|
286
|
+
*
|
|
287
|
+
* @component
|
|
288
|
+
* @example
|
|
289
|
+
* ```tsx
|
|
290
|
+
* <Payment.LineItemPrice className="text-lg font-bold" />
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
export const LineItemPrice = React.forwardRef((props, ref) => {
|
|
294
|
+
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 }));
|
|
298
|
+
});
|
|
299
|
+
LineItemPrice.displayName = 'Payment.LineItemPrice';
|
|
300
|
+
/**
|
|
301
|
+
* Displays the line item discount.
|
|
302
|
+
* Uses data-has-discount attribute for conditional visibility.
|
|
303
|
+
*
|
|
304
|
+
* @component
|
|
305
|
+
* @example
|
|
306
|
+
* ```tsx
|
|
307
|
+
* <Payment.LineItemDiscount className="text-green-500" />
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
export const LineItemDiscount = React.forwardRef((props, ref) => {
|
|
311
|
+
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 }));
|
|
316
|
+
});
|
|
317
|
+
LineItemDiscount.displayName = 'Payment.LineItemDiscount';
|
|
318
|
+
/**
|
|
319
|
+
* Displays the line item deposit amount.
|
|
320
|
+
* Uses data-has-deposit attribute for conditional visibility.
|
|
321
|
+
*
|
|
322
|
+
* @component
|
|
323
|
+
* @example
|
|
324
|
+
* ```tsx
|
|
325
|
+
* <Payment.LineItemDeposit className="font-semibold" />
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
export const LineItemDeposit = React.forwardRef((props, ref) => {
|
|
329
|
+
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 }));
|
|
334
|
+
});
|
|
335
|
+
LineItemDeposit.displayName = 'Payment.LineItemDeposit';
|
|
@@ -7,9 +7,31 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import React from 'react';
|
|
9
9
|
import { AsChildChildren } from '@wix/headless-utils/react';
|
|
10
|
-
|
|
11
|
-
export type { TimeSlotProviderProps } from '../core/time-slot-list/TimeSlot.js';
|
|
10
|
+
import type { TimeSlot as TimeSlotType } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
12
11
|
export type { StaffMemberData } from '../core/time-slot-list/TimeSlot.js';
|
|
12
|
+
/**
|
|
13
|
+
* Props for TimeSlot.Root component
|
|
14
|
+
*/
|
|
15
|
+
export interface RootProps {
|
|
16
|
+
children?: React.ReactNode;
|
|
17
|
+
timeSlot: TimeSlotType;
|
|
18
|
+
asChild?: boolean;
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Root component that provides time slot context.
|
|
23
|
+
*
|
|
24
|
+
* @order 1
|
|
25
|
+
* @component
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* <TimeSlot.Root timeSlot={timeSlot}>
|
|
29
|
+
* <TimeSlot.StartDate />
|
|
30
|
+
* <TimeSlot.Duration />
|
|
31
|
+
* </TimeSlot.Root>
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare const Root: React.ForwardRefExoticComponent<RootProps & React.RefAttributes<HTMLElement>>;
|
|
13
35
|
/**
|
|
14
36
|
* Props for TimeSlot.StartDate component
|
|
15
37
|
*/
|
|
@@ -10,8 +10,24 @@ import React from 'react';
|
|
|
10
10
|
import { GenericList } from '@wix/headless-components/react';
|
|
11
11
|
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
12
12
|
import * as CoreTimeSlot from '../core/time-slot-list/TimeSlot.js';
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Root component that provides time slot context.
|
|
15
|
+
*
|
|
16
|
+
* @order 1
|
|
17
|
+
* @component
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* <TimeSlot.Root timeSlot={timeSlot}>
|
|
21
|
+
* <TimeSlot.StartDate />
|
|
22
|
+
* <TimeSlot.Duration />
|
|
23
|
+
* </TimeSlot.Root>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export const Root = React.forwardRef((props, ref) => {
|
|
27
|
+
const { children, timeSlot, asChild, className, ...attrs } = props;
|
|
28
|
+
return (_jsx(CoreTimeSlot.Root, { config: { timeSlot }, children: _jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, customElement: children, ...attrs, children: children }) }));
|
|
29
|
+
});
|
|
30
|
+
Root.displayName = 'TimeSlot.Root';
|
|
15
31
|
// ============================================================================
|
|
16
32
|
// TestIds
|
|
17
33
|
// ============================================================================
|
|
@@ -7,8 +7,8 @@ import React from 'react';
|
|
|
7
7
|
import { GenericList } from '@wix/headless-components/react';
|
|
8
8
|
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
9
9
|
import * as CoreTimeSlotList from '../core/time-slot-list/TimeSlotList.js';
|
|
10
|
-
import
|
|
11
|
-
import { StartDate as TimeSlotStartDate, EndDate as TimeSlotEndDate, Duration, Actions as TimeSlotActions, Location, StaffMembers, StaffMemberRepeater, StaffMember, } from './TimeSlot.js';
|
|
10
|
+
import * as CoreTimeSlot from '../core/time-slot-list/TimeSlot.js';
|
|
11
|
+
import { StartDate as TimeSlotStartDate, EndDate as TimeSlotEndDate, Duration, Actions as TimeSlotActions, Location, StaffMembers, StaffMemberRepeater, StaffMember, Root as TimeSlotRoot, } from './TimeSlot.js';
|
|
12
12
|
// ============================================================================
|
|
13
13
|
// Utilities
|
|
14
14
|
// ============================================================================
|
|
@@ -122,9 +122,7 @@ TimeSlots.displayName = 'TimeSlotList.TimeSlots';
|
|
|
122
122
|
* Supports both ReactNode and function children patterns.
|
|
123
123
|
*/
|
|
124
124
|
const TimeSlotItemWrapper = ({ timeSlot, children, }) => {
|
|
125
|
-
return (_jsx(
|
|
126
|
-
return (_jsx("div", { "data-testid": TestIds.timeSlotListTimeSlot, "data-bookable": props.bookable, "data-selected": props.isSelected, children: typeof children === 'function' ? children(props) : children }));
|
|
127
|
-
} }) }));
|
|
125
|
+
return (_jsx(TimeSlotRoot, { timeSlot: timeSlot, children: _jsx(CoreTimeSlot.Info, { children: (props) => (_jsx("div", { "data-testid": TestIds.timeSlotListTimeSlot, "data-bookable": props.bookable, "data-selected": props.isSelected, children: typeof children === 'function' ? children(props) : children })) }) }));
|
|
128
126
|
};
|
|
129
127
|
/**
|
|
130
128
|
* Repeater component that renders each time slot.
|
package/dist/services/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export { ServiceService, ServiceServiceDefinition, type ServiceServiceAPI, type ServiceServiceConfig, type ServiceActions, type ServicePaymentData, loadServiceServiceInitialData, type SuccessServiceServiceConfigResult, type NotFoundServiceServiceConfigResult, } from './service/service.js';
|
|
6
6
|
export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type BookingServiceActions, type ServiceSelection, type ServiceSelectionTimeSlot, } from './booking/booking.js';
|
|
7
|
-
export { TimeSlotListService, TimeSlotListServiceDefinition, ViewMode, loadTimeSlotListConfig, type TimeSlotListServiceAPI, type TimeSlotListServiceActions, type TimeSlotListServiceConfig, type LoadTimeSlotListConfigOptions, type LoadTimeSlotListConfigResult, } from './time-slot-list/index.js';
|
|
7
|
+
export { TimeSlotListService, TimeSlotListServiceDefinition, TimeSlotService, TimeSlotServiceDefinition, ViewMode, loadTimeSlotListConfig, type TimeSlotListServiceAPI, type TimeSlotListServiceActions, type TimeSlotListServiceConfig, type TimeSlotServiceAPI, type TimeSlotServiceConfig, type LoadTimeSlotListConfigOptions, type LoadTimeSlotListConfigResult, } from './time-slot-list/index.js';
|
|
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';
|
package/dist/services/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export { ServiceService, ServiceServiceDefinition, loadServiceServiceInitialData, } from './service/service.js';
|
|
6
6
|
export { BookingService, BookingServiceDefinition, } from './booking/booking.js';
|
|
7
|
-
export { TimeSlotListService, TimeSlotListServiceDefinition, ViewMode, loadTimeSlotListConfig, } from './time-slot-list/index.js';
|
|
7
|
+
export { TimeSlotListService, TimeSlotListServiceDefinition, TimeSlotService, TimeSlotServiceDefinition, ViewMode, loadTimeSlotListConfig, } from './time-slot-list/index.js';
|
|
8
8
|
export { ServiceListService, ServiceListServiceDefinition, loadServiceListServiceInitialData, } from './service-list/service-list.js';
|
|
9
9
|
export { executeBookAction, canBook, buildBookingRequest, buildCheckoutRequest, } from './booking/book-action/index.js';
|
|
10
10
|
export { BookingFormService, BookingFormServiceDefinition, } from './booking-form/booking-form.js';
|
|
@@ -34,7 +34,8 @@ export interface PaymentDetails {
|
|
|
34
34
|
*/
|
|
35
35
|
export interface SlotService {
|
|
36
36
|
service: Service;
|
|
37
|
-
|
|
37
|
+
/** Optional line item ID. If not provided, one will be generated. */
|
|
38
|
+
lineItemId?: string;
|
|
38
39
|
}
|
|
39
40
|
/**
|
|
40
41
|
* Public config for PaymentService (SSR mode only):
|
|
@@ -9,6 +9,7 @@ import { calculateTotals, } from '@wix/auto_sdk_ecom_totals-calculator';
|
|
|
9
9
|
import { BookingServiceDefinition } from '../booking/booking.js';
|
|
10
10
|
import { RateType } from '@wix/auto_sdk_bookings_services';
|
|
11
11
|
import { PaymentServiceDefinition, } from './payment.def.js';
|
|
12
|
+
import { generateLineItemId } from '../../utils/guid.js';
|
|
12
13
|
export { PaymentServiceDefinition, } from './payment.def.js';
|
|
13
14
|
// ============================================================================
|
|
14
15
|
// Constants
|
|
@@ -54,11 +55,16 @@ function buildLineItem(service, numberOfParticipants, lineItemId) {
|
|
|
54
55
|
};
|
|
55
56
|
}
|
|
56
57
|
async function calculatePaymentDetails(slotServices, numberOfParticipants) {
|
|
57
|
-
|
|
58
|
+
// Ensure all slot services have a lineItemId
|
|
59
|
+
const data = slotServices.map((slot) => ({
|
|
60
|
+
...slot,
|
|
61
|
+
lineItemId: slot.lineItemId || generateLineItemId(),
|
|
62
|
+
}));
|
|
63
|
+
const lineItems = data.map((item) => buildLineItem(item.service, numberOfParticipants, item.lineItemId));
|
|
58
64
|
const response = await calculateTotals({
|
|
59
65
|
lineItems,
|
|
60
66
|
});
|
|
61
|
-
const additionalInfoList =
|
|
67
|
+
const additionalInfoList = data.map((item) => getAdditionalInfo(item.service, item.lineItemId));
|
|
62
68
|
return {
|
|
63
69
|
response,
|
|
64
70
|
additionalInfo: {
|
|
@@ -4,3 +4,4 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export { TimeSlotListServiceDefinition, ViewMode, type DateRange, type TimeSlotListServiceAPI, type TimeSlotListServiceActions, type TimeSlotListServiceConfig, type TimeSlotsFilters, } from './time-slot-list.def.js';
|
|
6
6
|
export { TimeSlotListService, loadTimeSlotListConfig, type LoadTimeSlotListConfigOptions, type LoadTimeSlotListConfigResult, } from './time-slot-list.js';
|
|
7
|
+
export { TimeSlotService, TimeSlotServiceDefinition, type TimeSlotServiceAPI, type TimeSlotServiceConfig, } from './time-slot.js';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TimeSlot Service
|
|
3
|
+
* Manages individual time slot data
|
|
4
|
+
*/
|
|
5
|
+
import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
6
|
+
import type { TimeSlot } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
7
|
+
/**
|
|
8
|
+
* API interface for the TimeSlot service
|
|
9
|
+
*/
|
|
10
|
+
export interface TimeSlotServiceAPI {
|
|
11
|
+
/** Reactive signal containing the time slot data */
|
|
12
|
+
timeSlotSignal: Signal<TimeSlot>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Service definition for TimeSlot
|
|
16
|
+
*/
|
|
17
|
+
export declare const TimeSlotServiceDefinition: string & {
|
|
18
|
+
__api: TimeSlotServiceAPI;
|
|
19
|
+
__config: {};
|
|
20
|
+
isServiceDefinition?: boolean;
|
|
21
|
+
} & TimeSlotServiceAPI;
|
|
22
|
+
/**
|
|
23
|
+
* Configuration for TimeSlotService
|
|
24
|
+
*/
|
|
25
|
+
export interface TimeSlotServiceConfig {
|
|
26
|
+
timeSlot: TimeSlot;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Implementation of TimeSlotService
|
|
30
|
+
*/
|
|
31
|
+
export declare const TimeSlotService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
32
|
+
__api: TimeSlotServiceAPI;
|
|
33
|
+
__config: {};
|
|
34
|
+
isServiceDefinition?: boolean;
|
|
35
|
+
} & TimeSlotServiceAPI, TimeSlotServiceConfig>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TimeSlot Service
|
|
3
|
+
* Manages individual time slot data
|
|
4
|
+
*/
|
|
5
|
+
import { defineService, implementService } from '@wix/services-definitions';
|
|
6
|
+
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
7
|
+
/**
|
|
8
|
+
* Service definition for TimeSlot
|
|
9
|
+
*/
|
|
10
|
+
export const TimeSlotServiceDefinition = defineService('time-slot');
|
|
11
|
+
/**
|
|
12
|
+
* Implementation of TimeSlotService
|
|
13
|
+
*/
|
|
14
|
+
export const TimeSlotService = implementService.withConfig()(TimeSlotServiceDefinition, ({ getService, config }) => {
|
|
15
|
+
const signalsService = getService(SignalsServiceDefinition);
|
|
16
|
+
const timeSlotSignal = signalsService.signal(config.timeSlot);
|
|
17
|
+
return {
|
|
18
|
+
timeSlotSignal,
|
|
19
|
+
};
|
|
20
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ID generation utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Generates a unique line item ID in Ecom's GUID format
|
|
6
|
+
*/
|
|
7
|
+
export function generateLineItemId() {
|
|
8
|
+
const s4 = () => Math.floor((1 + Math.random()) * 0x10000)
|
|
9
|
+
.toString(16)
|
|
10
|
+
.substring(1);
|
|
11
|
+
return `${s4()}${s4()}-${s4()}-${s4()}-${s4()}-${s4()}${s4()}${s4()}`;
|
|
12
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/headless-bookings",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.40",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"groupId": "com.wixpress.headless-components"
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
|
-
"falconPackageHash": "
|
|
75
|
+
"falconPackageHash": "74b83da9361fcd8b13b0615fe645d53672b0f2db9714094ec5026205"
|
|
76
76
|
}
|