@wix/headless-bookings 0.0.30 → 0.0.31

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 (33) hide show
  1. package/cjs/dist/react/core/payment/Payment.d.ts +193 -0
  2. package/cjs/dist/react/core/payment/Payment.js +202 -0
  3. package/cjs/dist/react/index.d.ts +2 -0
  4. package/cjs/dist/react/index.js +2 -0
  5. package/cjs/dist/react/payment/Payment.d.ts +342 -0
  6. package/cjs/dist/react/payment/Payment.js +294 -0
  7. package/cjs/dist/react/payment/PaymentLineItem.d.ts +144 -0
  8. package/cjs/dist/react/payment/PaymentLineItem.js +141 -0
  9. package/cjs/dist/services/index.d.ts +1 -0
  10. package/cjs/dist/services/index.js +1 -0
  11. package/cjs/dist/services/payment/payment.d.ts +32 -0
  12. package/cjs/dist/services/payment/payment.def.d.ts +66 -0
  13. package/cjs/dist/services/payment/payment.def.js +9 -0
  14. package/cjs/dist/services/payment/payment.js +167 -0
  15. package/cjs/dist/utils/money.d.ts +11 -0
  16. package/cjs/dist/utils/money.js +16 -0
  17. package/dist/react/core/payment/Payment.d.ts +193 -0
  18. package/dist/react/core/payment/Payment.js +202 -0
  19. package/dist/react/index.d.ts +2 -0
  20. package/dist/react/index.js +2 -0
  21. package/dist/react/payment/Payment.d.ts +342 -0
  22. package/dist/react/payment/Payment.js +294 -0
  23. package/dist/react/payment/PaymentLineItem.d.ts +144 -0
  24. package/dist/react/payment/PaymentLineItem.js +141 -0
  25. package/dist/services/index.d.ts +1 -0
  26. package/dist/services/index.js +1 -0
  27. package/dist/services/payment/payment.d.ts +32 -0
  28. package/dist/services/payment/payment.def.d.ts +66 -0
  29. package/dist/services/payment/payment.def.js +9 -0
  30. package/dist/services/payment/payment.js +167 -0
  31. package/dist/utils/money.d.ts +11 -0
  32. package/dist/utils/money.js +16 -0
  33. package/package.json +2 -2
@@ -0,0 +1,144 @@
1
+ /**
2
+ * PaymentLineItem - Component for displaying individual line item information
3
+ * Used within Payment.LineItemRepeater to display price, discount, deposit, etc.
4
+ */
5
+ import React from 'react';
6
+ import { AsChildChildren } from '@wix/headless-utils/react';
7
+ import { MoneyData } from '@wix/headless-components/react';
8
+ import type { CombinedLineItem } from '../core/payment/Payment.js';
9
+ /**
10
+ * Props for PaymentLineItem.Root component
11
+ */
12
+ export interface RootProps {
13
+ lineItem: CombinedLineItem;
14
+ currency: string;
15
+ children?: React.ReactNode | AsChildChildren<{
16
+ lineItem: CombinedLineItem;
17
+ currency: string;
18
+ }>;
19
+ asChild?: boolean;
20
+ className?: string;
21
+ 'data-testid'?: string;
22
+ }
23
+ /**
24
+ * Root component for a single line item.
25
+ * Provides context for child components.
26
+ *
27
+ * @component
28
+ * @example
29
+ * ```tsx
30
+ * <PaymentLineItem.Root lineItem={item} currency="USD">
31
+ * <PaymentLineItem.Price />
32
+ * <PaymentLineItem.Discount />
33
+ * </PaymentLineItem.Root>
34
+ * ```
35
+ */
36
+ export declare const Root: React.ForwardRefExoticComponent<RootProps & React.RefAttributes<HTMLElement>>;
37
+ /**
38
+ * Props for PaymentLineItem.Price component
39
+ */
40
+ export interface PriceProps {
41
+ asChild?: boolean;
42
+ children?: AsChildChildren<{
43
+ totalPrice: MoneyData | null;
44
+ subtotal: MoneyData | null;
45
+ tax: MoneyData | null;
46
+ discount: MoneyData | null;
47
+ deposit: MoneyData | null;
48
+ priceText: string | null;
49
+ }>;
50
+ className?: string;
51
+ }
52
+ /**
53
+ * Displays the line item price with support for different price types.
54
+ * Uses data-attributes for conditional visibility.
55
+ *
56
+ * For CUSTOM rate type services, displays priceText instead of monetary value.
57
+ *
58
+ * @component
59
+ * @example
60
+ * ```tsx
61
+ * // Default usage - renders total price or price text
62
+ * <PaymentLineItem.Price className="text-lg font-bold" />
63
+ *
64
+ * // Custom rendering with full price data
65
+ * <PaymentLineItem.Price asChild>
66
+ * {({ totalPrice, subtotal, tax, discount, priceText }) => (
67
+ * <div>
68
+ * {priceText ? (
69
+ * <span>{priceText}</span>
70
+ * ) : (
71
+ * <>
72
+ * <span><Money money={totalPrice} /></span>
73
+ * <span data-has-discount={!!discount?.amount}><Money money={discount} /></span>
74
+ * </>
75
+ * )}
76
+ * </div>
77
+ * )}
78
+ * </PaymentLineItem.Price>
79
+ * ```
80
+ */
81
+ export declare const Price: React.ForwardRefExoticComponent<PriceProps & React.RefAttributes<HTMLElement>>;
82
+ /**
83
+ * Props for PaymentLineItem.Discount component
84
+ */
85
+ export interface DiscountProps {
86
+ asChild?: boolean;
87
+ children?: AsChildChildren<{
88
+ discount: MoneyData | null;
89
+ }>;
90
+ className?: string;
91
+ }
92
+ /**
93
+ * Displays the line item discount.
94
+ * Uses data-has-discount attribute for conditional visibility.
95
+ *
96
+ * @component
97
+ * @example
98
+ * ```tsx
99
+ * <PaymentLineItem.Discount className="text-green-500" />
100
+ * ```
101
+ */
102
+ export declare const Discount: React.ForwardRefExoticComponent<DiscountProps & React.RefAttributes<HTMLElement>>;
103
+ /**
104
+ * Props for PaymentLineItem.Deposit component
105
+ */
106
+ export interface DepositProps {
107
+ asChild?: boolean;
108
+ children?: AsChildChildren<{
109
+ deposit: MoneyData | null;
110
+ }>;
111
+ className?: string;
112
+ }
113
+ /**
114
+ * Displays the line item deposit amount.
115
+ * Uses data-has-deposit attribute for conditional visibility.
116
+ *
117
+ * @component
118
+ * @example
119
+ * ```tsx
120
+ * <PaymentLineItem.Deposit className="font-semibold" />
121
+ * ```
122
+ */
123
+ export declare const Deposit: React.ForwardRefExoticComponent<DepositProps & React.RefAttributes<HTMLElement>>;
124
+ /**
125
+ * Props for PaymentLineItem.PriceText component
126
+ */
127
+ export interface PriceTextProps {
128
+ asChild?: boolean;
129
+ children?: AsChildChildren<{
130
+ priceText: string | null;
131
+ }>;
132
+ className?: string;
133
+ }
134
+ /**
135
+ * Displays the custom price text (for CUSTOM rate type services).
136
+ * Uses data-has-price-text attribute for conditional visibility.
137
+ *
138
+ * @component
139
+ * @example
140
+ * ```tsx
141
+ * <PaymentLineItem.PriceText className="text-foreground" />
142
+ * ```
143
+ */
144
+ export declare const PriceText: React.ForwardRefExoticComponent<PriceTextProps & React.RefAttributes<HTMLElement>>;
@@ -0,0 +1,141 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * PaymentLineItem - Component for displaying individual line item information
4
+ * Used within Payment.LineItemRepeater to display price, discount, deposit, etc.
5
+ */
6
+ import React from 'react';
7
+ import * as CorePayment from '../core/payment/Payment.js';
8
+ import { AsChildSlot } from '@wix/headless-utils/react';
9
+ import { Money } from '@wix/headless-components/react';
10
+ var TestIds;
11
+ (function (TestIds) {
12
+ TestIds["paymentLineItemRoot"] = "payment-line-item-root";
13
+ TestIds["paymentLineItemPrice"] = "payment-line-item-price";
14
+ TestIds["paymentLineItemDiscount"] = "payment-line-item-discount";
15
+ TestIds["paymentLineItemDeposit"] = "payment-line-item-deposit";
16
+ TestIds["paymentLineItemPriceText"] = "payment-line-item-price-text";
17
+ })(TestIds || (TestIds = {}));
18
+ const PaymentLineItemContext = React.createContext(null);
19
+ /**
20
+ * Hook to access PaymentLineItem context
21
+ */
22
+ function usePaymentLineItemContext() {
23
+ const context = React.useContext(PaymentLineItemContext);
24
+ if (!context) {
25
+ throw new Error('usePaymentLineItemContext must be used within a PaymentLineItem.Root component');
26
+ }
27
+ return context;
28
+ }
29
+ /**
30
+ * Root component for a single line item.
31
+ * Provides context for child components.
32
+ *
33
+ * @component
34
+ * @example
35
+ * ```tsx
36
+ * <PaymentLineItem.Root lineItem={item} currency="USD">
37
+ * <PaymentLineItem.Price />
38
+ * <PaymentLineItem.Discount />
39
+ * </PaymentLineItem.Root>
40
+ * ```
41
+ */
42
+ export const Root = React.forwardRef((props, ref) => {
43
+ const { lineItem, currency, children, asChild, className, ...attrs } = props;
44
+ return (_jsx(PaymentLineItemContext.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 }) }) }));
45
+ });
46
+ Root.displayName = 'PaymentLineItem.Root';
47
+ /**
48
+ * Displays the line item price with support for different price types.
49
+ * Uses data-attributes for conditional visibility.
50
+ *
51
+ * For CUSTOM rate type services, displays priceText instead of monetary value.
52
+ *
53
+ * @component
54
+ * @example
55
+ * ```tsx
56
+ * // Default usage - renders total price or price text
57
+ * <PaymentLineItem.Price className="text-lg font-bold" />
58
+ *
59
+ * // Custom rendering with full price data
60
+ * <PaymentLineItem.Price asChild>
61
+ * {({ totalPrice, subtotal, tax, discount, priceText }) => (
62
+ * <div>
63
+ * {priceText ? (
64
+ * <span>{priceText}</span>
65
+ * ) : (
66
+ * <>
67
+ * <span><Money money={totalPrice} /></span>
68
+ * <span data-has-discount={!!discount?.amount}><Money money={discount} /></span>
69
+ * </>
70
+ * )}
71
+ * </div>
72
+ * )}
73
+ * </PaymentLineItem.Price>
74
+ * ```
75
+ */
76
+ export const Price = React.forwardRef((props, ref) => {
77
+ const { asChild, children, className } = props;
78
+ const { lineItem, currency } = usePaymentLineItemContext();
79
+ return (_jsx(CorePayment.LineItem, { lineItem: lineItem, currency: currency, children: (priceData) => {
80
+ const { totalPrice, discount, deposit, priceText } = priceData;
81
+ // Default rendering based on price type
82
+ const renderDefaultPrice = () => {
83
+ // If custom price text (CUSTOM rate type), show text
84
+ if (priceText) {
85
+ return (_jsx("span", { className: className, "data-testid": TestIds.paymentLineItemPrice, children: priceText }));
86
+ }
87
+ // Otherwise show monetary price
88
+ return totalPrice ? (_jsx(Money, { money: totalPrice, className: className })) : null;
89
+ };
90
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentLineItemPrice, "data-has-discount": discount !== null && discount.amount > 0, "data-has-deposit": deposit !== null && deposit.amount > 0, "data-has-price-text": !!priceText, customElement: children, customElementProps: priceData, children: renderDefaultPrice() }));
91
+ } }));
92
+ });
93
+ Price.displayName = 'PaymentLineItem.Price';
94
+ /**
95
+ * Displays the line item discount.
96
+ * Uses data-has-discount attribute for conditional visibility.
97
+ *
98
+ * @component
99
+ * @example
100
+ * ```tsx
101
+ * <PaymentLineItem.Discount className="text-green-500" />
102
+ * ```
103
+ */
104
+ export const Discount = React.forwardRef((props, ref) => {
105
+ const { asChild, children, className } = props;
106
+ const { lineItem, currency } = usePaymentLineItemContext();
107
+ return (_jsx(CorePayment.LineItem, { lineItem: lineItem, currency: currency, children: ({ discount }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentLineItemDiscount, "data-has-discount": discount !== null && discount.amount > 0, customElement: children, customElementProps: { discount }, children: discount ? _jsx(Money, { money: discount }) : null })) }));
108
+ });
109
+ Discount.displayName = 'PaymentLineItem.Discount';
110
+ /**
111
+ * Displays the line item deposit amount.
112
+ * Uses data-has-deposit attribute for conditional visibility.
113
+ *
114
+ * @component
115
+ * @example
116
+ * ```tsx
117
+ * <PaymentLineItem.Deposit className="font-semibold" />
118
+ * ```
119
+ */
120
+ export const Deposit = React.forwardRef((props, ref) => {
121
+ const { asChild, children, className } = props;
122
+ const { lineItem, currency } = usePaymentLineItemContext();
123
+ return (_jsx(CorePayment.LineItem, { lineItem: lineItem, currency: currency, children: ({ deposit }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentLineItemDeposit, "data-has-deposit": deposit !== null && deposit.amount > 0, customElement: children, customElementProps: { deposit }, children: deposit ? _jsx(Money, { money: deposit }) : null })) }));
124
+ });
125
+ Deposit.displayName = 'PaymentLineItem.Deposit';
126
+ /**
127
+ * Displays the custom price text (for CUSTOM rate type services).
128
+ * Uses data-has-price-text attribute for conditional visibility.
129
+ *
130
+ * @component
131
+ * @example
132
+ * ```tsx
133
+ * <PaymentLineItem.PriceText className="text-foreground" />
134
+ * ```
135
+ */
136
+ export const PriceText = React.forwardRef((props, ref) => {
137
+ const { asChild, children, className } = props;
138
+ const { lineItem, currency } = usePaymentLineItemContext();
139
+ return (_jsx(CorePayment.LineItem, { lineItem: lineItem, currency: currency, children: ({ priceText }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.paymentLineItemPriceText, "data-has-price-text": !!priceText, customElement: children, customElementProps: { priceText }, children: priceText ? _jsx("span", { children: priceText }) : null })) }));
140
+ });
141
+ PriceText.displayName = 'PaymentLineItem.PriceText';
@@ -8,3 +8,4 @@ export { TimeSlotListService, TimeSlotListServiceDefinition, ViewMode, loadTimeS
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 SlotService, type LineItemAdditionalInfo, loadPaymentConfig, type SuccessPaymentConfigResult, type ErrorPaymentConfigResult, } from './payment/payment.js';
@@ -8,3 +8,4 @@ export { TimeSlotListService, TimeSlotListServiceDefinition, ViewMode, loadTimeS
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';
11
+ export { PaymentService, PaymentServiceDefinition, loadPaymentConfig, } from './payment/payment.js';
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Payment Service - Pricing calculation and payment details management
3
+ * Handles calculating total prices, taxes, discounts, and deposit information
4
+ * Supports two modes: SSR (config with pre-fetched data) and lazy loading (reactive)
5
+ */
6
+ import { type PaymentServiceConfig, type PaymentServiceInternalConfig, type SlotService } from './payment.def.js';
7
+ export { PaymentServiceDefinition, type PaymentServiceConfig, type PaymentDetails, type LineItemAdditionalInfo, type SlotService, } from './payment.def.js';
8
+ export type { PaymentServiceAPI, PaymentServiceInternalConfig } from './payment.def.js';
9
+ export declare const PaymentService: import("@wix/services-definitions").ServiceFactory<string & {
10
+ __api: import("./payment.def.js").PaymentServiceAPI;
11
+ __config: {};
12
+ isServiceDefinition?: boolean;
13
+ } & import("./payment.def.js").PaymentServiceAPI, PaymentServiceInternalConfig>;
14
+ export type SuccessPaymentConfigResult = {
15
+ type: 'success';
16
+ config: PaymentServiceConfig;
17
+ };
18
+ export type ErrorPaymentConfigResult = {
19
+ type: 'error';
20
+ error: string;
21
+ };
22
+ /**
23
+ * Load payment configuration for Server-Side Rendering (SSR).
24
+ * Calls the pricing APIs and returns pre-calculated payment details.
25
+ *
26
+ * @param params.slotServices - Slot/service inputs for calculation
27
+ * @param params.numberOfParticipants - Number of participants (default: 1)
28
+ */
29
+ export declare function loadPaymentConfig(params: {
30
+ slotServices: SlotService[];
31
+ numberOfParticipants?: number;
32
+ }): Promise<SuccessPaymentConfigResult | ErrorPaymentConfigResult>;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Payment Service Definition
3
+ * Defines interfaces and service contract for payment calculation management
4
+ */
5
+ import type { Signal } from '@wix/services-definitions/core-services/signals';
6
+ import type { CalculateTotalsResponse } from '@wix/auto_sdk_ecom_totals-calculator';
7
+ import type { Service } from '@wix/auto_sdk_bookings_services';
8
+ /**
9
+ * Payment option for line items
10
+ */
11
+ export type PaymentOption = 'FULL_PAYMENT_ONLINE' | 'FULL_PAYMENT_OFFLINE';
12
+ /**
13
+ * Additional computed info for a line item (not in SDK response)
14
+ */
15
+ export interface LineItemAdditionalInfo {
16
+ /** Line item ID to match with SDK's calculatedLineItems */
17
+ lineItemId: string;
18
+ /** Custom price text (for CUSTOM rate type services) */
19
+ priceText?: string;
20
+ }
21
+ /**
22
+ * Payment calculation result with SDK response and additional computed info
23
+ */
24
+ export interface PaymentDetails {
25
+ /** The raw SDK CalculateTotals response */
26
+ response: CalculateTotalsResponse;
27
+ /** Additional computed information per line item */
28
+ additionalInfo: {
29
+ lineItems: LineItemAdditionalInfo[];
30
+ };
31
+ }
32
+ /**
33
+ * Input for calculating payment for a slot/service
34
+ */
35
+ export interface SlotService {
36
+ service: Service;
37
+ lineItemId: string;
38
+ }
39
+ /**
40
+ * Public config for PaymentService (SSR mode only):
41
+ * Pass `paymentDetails` pre-fetched via loadPaymentConfig
42
+ */
43
+ export interface PaymentServiceConfig {
44
+ /** Pre-calculated payment details for SSR (no API call) */
45
+ paymentDetails?: PaymentDetails;
46
+ }
47
+ /**
48
+ * Internal config used by Core component to pass lazy loading data
49
+ * Not exposed publicly - Core merges this with PaymentServiceConfig
50
+ */
51
+ export interface PaymentServiceInternalConfig extends PaymentServiceConfig {
52
+ /** Slot services for lazy loading (internal use) */
53
+ slotServices?: SlotService[];
54
+ /** Number of participants for lazy loading (internal use) */
55
+ numberOfParticipants?: number;
56
+ }
57
+ export interface PaymentServiceAPI {
58
+ paymentDetailsSignal: Signal<PaymentDetails | null>;
59
+ isLoadingSignal: Signal<boolean>;
60
+ errorSignal: Signal<string | null>;
61
+ }
62
+ export declare const PaymentServiceDefinition: string & {
63
+ __api: PaymentServiceAPI;
64
+ __config: {};
65
+ isServiceDefinition?: boolean;
66
+ } & PaymentServiceAPI;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Payment Service Definition
3
+ * Defines interfaces and service contract for payment calculation management
4
+ */
5
+ import { defineService } from '@wix/services-definitions';
6
+ // ============================================================================
7
+ // Service Definition
8
+ // ============================================================================
9
+ export const PaymentServiceDefinition = defineService('payment');
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Payment Service - Pricing calculation and payment details management
3
+ * Handles calculating total prices, taxes, discounts, and deposit information
4
+ * Supports two modes: SSR (config with pre-fetched data) and lazy loading (reactive)
5
+ */
6
+ import { implementService } from '@wix/services-definitions';
7
+ import { SignalsServiceDefinition } from '@wix/services-definitions/core-services/signals';
8
+ import { calculateTotals, } from '@wix/auto_sdk_ecom_totals-calculator';
9
+ import { BookingServiceDefinition } from '../booking/booking.js';
10
+ import { RateType } from '@wix/auto_sdk_bookings_services';
11
+ import { PaymentServiceDefinition, } from './payment.def.js';
12
+ export { PaymentServiceDefinition, } from './payment.def.js';
13
+ // ============================================================================
14
+ // Constants
15
+ // ============================================================================
16
+ const BOOKINGS_APP_DEF_ID = '13d21c63-b5ec-5912-8397-c3a5ddb27a97';
17
+ // ============================================================================
18
+ // Helper Functions
19
+ // ============================================================================
20
+ function getAdditionalInfo(service, lineItemId) {
21
+ const payment = service.payment;
22
+ const priceText = payment?.rateType === RateType.CUSTOM && payment.custom?.description
23
+ ? payment.custom.description
24
+ : undefined;
25
+ return { lineItemId, priceText };
26
+ }
27
+ function getPaymentOption(service) {
28
+ const options = service.payment?.options;
29
+ if (options?.inPerson) {
30
+ return 'FULL_PAYMENT_OFFLINE';
31
+ }
32
+ return 'FULL_PAYMENT_ONLINE';
33
+ }
34
+ function buildLineItem(service, numberOfParticipants, lineItemId) {
35
+ // Get fixed price from service
36
+ const servicePrice = service.payment?.fixed?.price?.value;
37
+ const price = Number(servicePrice || 0) * numberOfParticipants;
38
+ // Get deposit if configured
39
+ const deposit = service.payment?.fixed?.deposit?.value
40
+ ? Number(service.payment.fixed.deposit.value) * numberOfParticipants
41
+ : undefined;
42
+ // Get payment option from service configuration
43
+ const paymentOption = getPaymentOption(service);
44
+ return {
45
+ _id: lineItemId,
46
+ catalogReference: {
47
+ catalogItemId: service._id || '',
48
+ appId: BOOKINGS_APP_DEF_ID,
49
+ },
50
+ price: String(price),
51
+ ...(deposit ? { depositAmount: String(deposit) } : {}),
52
+ quantity: 1,
53
+ paymentOption,
54
+ };
55
+ }
56
+ async function calculatePaymentDetails(slotServices, numberOfParticipants) {
57
+ const lineItems = slotServices.map((input) => buildLineItem(input.service, numberOfParticipants, input.lineItemId));
58
+ const response = await calculateTotals({
59
+ lineItems,
60
+ });
61
+ const additionalInfoList = slotServices.map((input) => getAdditionalInfo(input.service, input.lineItemId));
62
+ return {
63
+ response,
64
+ additionalInfo: {
65
+ lineItems: additionalInfoList,
66
+ },
67
+ };
68
+ }
69
+ // ============================================================================
70
+ // Service Implementation
71
+ // ============================================================================
72
+ export const PaymentService = implementService.withConfig()(PaymentServiceDefinition, ({ getService, config }) => {
73
+ const signalsService = getService(SignalsServiceDefinition);
74
+ // Try to get BookingService (optional - for reactive mode)
75
+ let bookingService = null;
76
+ try {
77
+ bookingService = getService(BookingServiceDefinition);
78
+ }
79
+ catch {
80
+ bookingService = null;
81
+ }
82
+ // Initialize signals
83
+ const paymentDetailsSignal = signalsService.signal(config.paymentDetails || null);
84
+ const isLoadingSignal = signalsService.signal(false);
85
+ const errorSignal = signalsService.signal(null);
86
+ // Internal calculate function
87
+ const calculate = async (slotServices, numberOfParticipants) => {
88
+ if (!slotServices.length) {
89
+ paymentDetailsSignal.set(null);
90
+ return;
91
+ }
92
+ isLoadingSignal.set(true);
93
+ errorSignal.set(null);
94
+ try {
95
+ const paymentDetails = await calculatePaymentDetails(slotServices, numberOfParticipants);
96
+ paymentDetailsSignal.set(paymentDetails);
97
+ }
98
+ catch (error) {
99
+ const errorMessage = error instanceof Error
100
+ ? error.message
101
+ : 'Failed to calculate payment';
102
+ errorSignal.set(errorMessage);
103
+ console.error('Payment calculation error:', error);
104
+ }
105
+ finally {
106
+ isLoadingSignal.set(false);
107
+ }
108
+ };
109
+ // Mode 1: SSR - paymentDetails already set in signal initialization
110
+ if (config.paymentDetails) {
111
+ // No-op - data is pre-fetched
112
+ }
113
+ // Mode 2: Lazy loading - slotServices provided via internal config
114
+ else if (config.slotServices?.length) {
115
+ void calculate(config.slotServices, config.numberOfParticipants ?? 1);
116
+ }
117
+ // Mode 3: Reactive - observe BookingService signals (client-side only)
118
+ else if (typeof window !== 'undefined' && bookingService) {
119
+ signalsService.effect(() => {
120
+ const selections = bookingService?.serviceSelections.get() || [];
121
+ // For single service mode, take the first selection
122
+ const firstSelection = selections[0];
123
+ const numParticipants = firstSelection?.totalParticipants || 1;
124
+ const services = selections.map((selection) => ({
125
+ service: selection.service,
126
+ lineItemId: selection.instanceId,
127
+ }));
128
+ void calculate(services, numParticipants);
129
+ });
130
+ }
131
+ return {
132
+ paymentDetailsSignal,
133
+ isLoadingSignal,
134
+ errorSignal,
135
+ };
136
+ });
137
+ /**
138
+ * Load payment configuration for Server-Side Rendering (SSR).
139
+ * Calls the pricing APIs and returns pre-calculated payment details.
140
+ *
141
+ * @param params.slotServices - Slot/service inputs for calculation
142
+ * @param params.numberOfParticipants - Number of participants (default: 1)
143
+ */
144
+ export async function loadPaymentConfig(params) {
145
+ try {
146
+ const { slotServices, numberOfParticipants = 1 } = params;
147
+ if (!slotServices.length) {
148
+ return {
149
+ type: 'success',
150
+ config: { paymentDetails: undefined },
151
+ };
152
+ }
153
+ const paymentDetails = await calculatePaymentDetails(slotServices, numberOfParticipants);
154
+ return {
155
+ type: 'success',
156
+ config: { paymentDetails },
157
+ };
158
+ }
159
+ catch (error) {
160
+ const errorMessage = error instanceof Error ? error.message : 'Failed to load payment config';
161
+ console.error('Failed to load payment config:', error);
162
+ return {
163
+ type: 'error',
164
+ error: errorMessage,
165
+ };
166
+ }
167
+ }
@@ -19,3 +19,14 @@ export declare function convertToMoneyData(sdkMoney: {
19
19
  currency?: string;
20
20
  formattedValue?: string | null;
21
21
  } | undefined): MoneyData | null;
22
+ /**
23
+ * Converts ecom MultiCurrencyPrice format to MoneyData format
24
+ * MultiCurrencyPrice uses 'amount' as string, while MoneyData uses 'amount' as number
25
+ *
26
+ * @param price - The MultiCurrencyPrice object with amount as string
27
+ * @param currency - The currency code (from response level)
28
+ * @returns MoneyData object or null if conversion fails
29
+ */
30
+ export declare function convertMultiCurrencyPriceToMoneyData(price: {
31
+ amount?: string;
32
+ } | undefined, currency: string): MoneyData | null;
@@ -32,3 +32,19 @@ export function convertToMoneyData(sdkMoney) {
32
32
  }
33
33
  return null;
34
34
  }
35
+ /**
36
+ * Converts ecom MultiCurrencyPrice format to MoneyData format
37
+ * MultiCurrencyPrice uses 'amount' as string, while MoneyData uses 'amount' as number
38
+ *
39
+ * @param price - The MultiCurrencyPrice object with amount as string
40
+ * @param currency - The currency code (from response level)
41
+ * @returns MoneyData object or null if conversion fails
42
+ */
43
+ export function convertMultiCurrencyPriceToMoneyData(price, currency) {
44
+ if (!price?.amount)
45
+ return null;
46
+ const parsed = parseFloat(price.amount);
47
+ if (isNaN(parsed) || parsed < 0)
48
+ return null;
49
+ return { amount: parsed, currency };
50
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/headless-bookings",
3
- "version": "0.0.30",
3
+ "version": "0.0.31",
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": "d466b4eaebfa6f1258b0d9f3bfa7928fa0f0a6df920e8c143ebb52d0"
75
+ "falconPackageHash": "7f0622f4f250d712f40cd5c74b49c920e2e55e5b19b7e1a86f572158"
76
76
  }