@sonic-equipment/ui 133.0.0 → 134.0.0
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/dist/algolia/{algolia-intialization.js → algolia-initialization.js} +7 -0
- package/dist/algolia/algolia-insights-provider.js +7 -0
- package/dist/algolia/algolia-search-provider.js +19 -0
- package/dist/algolia/use-algolia-insights.d.ts +13 -6
- package/dist/algolia/use-algolia-insights.js +93 -10
- package/dist/buttons/button/button.d.ts +4 -1
- package/dist/buttons/button/button.js +2 -2
- package/dist/country-selector/country-select/country-select.d.ts +1 -0
- package/dist/country-selector/country-select/country-select.js +2 -2
- package/dist/delivery-time/delivery-time.js +1 -1
- package/dist/exports.d.ts +7 -2
- package/dist/forms/checkbox/checkbox.d.ts +2 -1
- package/dist/forms/checkbox/checkbox.js +2 -2
- package/dist/forms/field-error/field-error.d.ts +2 -1
- package/dist/forms/field-error/field-error.js +3 -2
- package/dist/forms/input/input.d.ts +1 -0
- package/dist/forms/input/input.js +2 -2
- package/dist/forms/label/label.d.ts +3 -1
- package/dist/forms/label/label.js +3 -2
- package/dist/forms/switch/switch.d.ts +2 -1
- package/dist/forms/switch/switch.js +2 -2
- package/dist/forms/text-field/text-field.d.ts +3 -1
- package/dist/forms/text-field/text-field.js +4 -3
- package/dist/forms/text-field/text-field.module.css.js +1 -1
- package/dist/forms/textarea/textarea.d.ts +1 -0
- package/dist/forms/textarea/textarea.js +3 -2
- package/dist/global-search/plugins/categories-plugin.js +2 -1
- package/dist/global-search/plugins/popular-categories-plugin.js +2 -0
- package/dist/global-search/plugins/query-suggestions-plugin.js +1 -0
- package/dist/global-search/plugins/quick-access-plugin.js +2 -2
- package/dist/global-search/search-result-panel/sections/with-results.js +0 -1
- package/dist/index.js +8 -3
- package/dist/info-icon-tooltip/info-icon-tooltip.d.ts +7 -0
- package/dist/info-icon-tooltip/info-icon-tooltip.js +20 -0
- package/dist/info-icon-tooltip/info-icon-tooltip.module.css.js +3 -0
- package/dist/intl/translation-id.d.ts +1 -1
- package/dist/pages/checkout/order-confirmation-page/order-confirmation-page-content.d.ts +5 -0
- package/dist/pages/checkout/order-confirmation-page/order-confirmation-page-content.js +83 -0
- package/dist/pages/checkout/order-confirmation-page/order-confirmation-page.js +3 -77
- package/dist/pages/checkout/payment-page/components/payment.js +49 -4
- package/dist/pages/checkout/payment-page/payment-page-content.d.ts +15 -0
- package/dist/pages/checkout/payment-page/payment-page-content.js +43 -0
- package/dist/pages/checkout/payment-page/payment-page.js +3 -37
- package/dist/pages/checkout/shipping-page/components/edit-address.js +3 -3
- package/dist/pages/checkout/shipping-page/shipping-page-content.d.ts +14 -0
- package/dist/pages/checkout/shipping-page/shipping-page-content.js +40 -0
- package/dist/pages/checkout/shipping-page/shipping-page.js +45 -54
- package/dist/pages/product/product-details-page/components/product-details-panel/product-details-panel.js +11 -1
- package/dist/pages/product/product-listing-page/product-listing-product-overview/product-listing-product-overview.js +0 -1
- package/dist/pages/product/search-result-page/search-result-product-overview/search-result-product-overview.js +0 -1
- package/dist/shared/fetch/request.d.ts +18 -13
- package/dist/shared/fetch/request.js +22 -9
- package/dist/shared/ga/use-data-layer.d.ts +7 -3
- package/dist/shared/ga/use-data-layer.js +6 -1
- package/dist/shared/utils/promise.d.ts +2 -0
- package/dist/shared/utils/promise.js +9 -0
- package/dist/sign-in-form/sign-in-form.d.ts +19 -0
- package/dist/sign-in-form/sign-in-form.js +49 -0
- package/dist/sign-in-form/sign-in-form.module.css.js +3 -0
- package/dist/styles.css +192 -44
- package/dist/tooltip/tooltip.d.ts +3 -2
- package/dist/tooltip/tooltip.js +5 -4
- package/package.json +1 -1
- package/dist/shared/utils/wait.d.ts +0 -1
- package/dist/shared/utils/wait.js +0 -5
- /package/dist/algolia/{algolia-intialization.d.ts → algolia-initialization.d.ts} +0 -0
|
@@ -1,26 +1,15 @@
|
|
|
1
|
-
import { jsx
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { useState, useCallback, useEffect } from 'react';
|
|
3
|
-
import { Button } from '../../../buttons/button/button.js';
|
|
4
|
-
import { OrderLineCard } from '../../../cards/orderline-card/orderline-card.js';
|
|
5
|
-
import { CartTotals } from '../../../cart-totals/cart-totals.js';
|
|
6
|
-
import { CartTotalsSummary } from '../../../cart-totals/cart-totals-summary.js';
|
|
7
|
-
import { FormattedMessage } from '../../../intl/formatted-message.js';
|
|
8
|
-
import { useFormattedMessage } from '../../../intl/use-formatted-message.js';
|
|
9
|
-
import { OrderLineList } from '../../../lists/orderline-list/orderline-list.js';
|
|
10
3
|
import { useIsAuthenticated } from '../../../shared/api/storefront/hooks/authentication/use-is-authenticated.js';
|
|
11
4
|
import { useFetchCurrentCheckoutAtp } from '../../../shared/api/storefront/hooks/cart/use-fetch-current-cart-checkout-atp.js';
|
|
12
5
|
import { useFetchCurrentCartWithAtp } from '../../../shared/api/storefront/hooks/cart/use-fetch-current-cart-with-atp.js';
|
|
13
6
|
import { useNavigate } from '../../../shared/routing/route-provider.js';
|
|
14
7
|
import { hasNo } from '../../../shared/utils/types.js';
|
|
15
|
-
import { Page } from '../../components/page/page.js';
|
|
16
8
|
import { ErrorPage } from '../../error-page/error-page.js';
|
|
17
9
|
import { LoadingPage } from '../../loading-page/loading-page.js';
|
|
18
10
|
import { CHECKOUT_PATHS } from '../constants.js';
|
|
19
|
-
import { CheckoutPageLayout } from '../layouts/checkout-page-layout/checkout-page-layout.js';
|
|
20
|
-
import { CheckoutPageSection } from '../layouts/checkout-page-layout/components/checkout-page-section.js';
|
|
21
|
-
import { CheckoutPageSectionContent } from '../layouts/checkout-page-layout/components/checkout-page-section-content.js';
|
|
22
|
-
import { Payment } from './components/payment.js';
|
|
23
11
|
import { useHasReturnedFromAdyen } from './hooks/use-has-returned-from-adyen.js';
|
|
12
|
+
import { PaymentPageContent } from './payment-page-content.js';
|
|
24
13
|
|
|
25
14
|
const PAYMENT_FORM_ID = 'paymentForm';
|
|
26
15
|
function PaymentPage() {
|
|
@@ -32,7 +21,6 @@ function PaymentPage() {
|
|
|
32
21
|
const { data: atp, isLoading: isAtpLoading } = useFetchCurrentCheckoutAtp();
|
|
33
22
|
const hasAtp = atp && atp.length > 1;
|
|
34
23
|
const isLoading = isLoadingCart || isAtpLoading;
|
|
35
|
-
const t = useFormattedMessage();
|
|
36
24
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
37
25
|
const [isValidating, setIsValidating] = useState(false);
|
|
38
26
|
const { isNavigating, navigate } = useNavigate();
|
|
@@ -66,29 +54,7 @@ function PaymentPage() {
|
|
|
66
54
|
cart.cartLines.length === 0 ||
|
|
67
55
|
hasNo(cart.billTo?.address1))
|
|
68
56
|
return null;
|
|
69
|
-
return (jsx(
|
|
70
|
-
{ href: CHECKOUT_PATHS.HOME, label: t('Home') },
|
|
71
|
-
{
|
|
72
|
-
href: CHECKOUT_PATHS.REVIEW_AND_SUBMIT,
|
|
73
|
-
label: t('Review and payment'),
|
|
74
|
-
},
|
|
75
|
-
], title: t('Review and payment'), children: jsxs(CheckoutPageLayout, { actions: {
|
|
76
|
-
primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutShippingCartTotalContinueButton", form: PAYMENT_FORM_ID, isDisabled: isProcessing, isLoading: isProcessing ? (jsx(FormattedMessage, { id: "Processing" })) : isValidating ? (jsx(FormattedMessage, { id: "Validating" })) : (false), type: "submit", children: jsx(FormattedMessage, { id: "Pay" }) })),
|
|
77
|
-
}, mobileSummary: jsx(CartTotalsSummary, { totalAmount: cart.orderGrandTotalDisplay }), overview: jsx(CartTotals, { deliveryDate: hasAtp ? undefined : cart.requestedDeliveryDate, fulfillmentMethod: cart.fulfillmentMethod, isPayByInvoice: (cart.paymentOptions?.paymentMethods?.length || 1) <= 1 &&
|
|
78
|
-
cart.paymentMethod?.name === 'PBI', shippingCost: cart.shippingAndHandlingDisplay, subtotal: cart.orderSubTotalDisplay, tax: cart.totalTaxDisplay, total: cart.orderGrandTotalDisplay, vatPercentage: cart.cartLines[0]?.pricing?.vatRate || 0 }), children: [jsx(CheckoutPageSection, { hasBorder: false, title: jsx(FormattedMessage, { id: "Payment" }), children: jsx(CheckoutPageSectionContent, { children: jsx(Payment, { atp: atp, cart: cart, form: PAYMENT_FORM_ID, onPaymentComplete: onPaymentComplete, onProcessing: setIsProcessing, onValidating: setIsValidating }) }) }), jsx(CheckoutPageSection, { hasBorder: false, title: jsx(FormattedMessage, { id: "Order" }), children: jsx(CheckoutPageSectionContent, { stretch: true, children: jsx(OrderLineList, { children: cart.cartLines.map(cartLine => (jsx(OrderLineCard, { deliveryDate: cartLine.atp?.date, href: cartLine.productUri, image: {
|
|
79
|
-
fit: 'contain',
|
|
80
|
-
image: {
|
|
81
|
-
'1': cartLine.smallImagePath,
|
|
82
|
-
'2': cartLine.smallImagePath,
|
|
83
|
-
'3': cartLine.smallImagePath,
|
|
84
|
-
altText: cartLine.altText,
|
|
85
|
-
},
|
|
86
|
-
title: cartLine.altText,
|
|
87
|
-
}, isReadonly: true, price: {
|
|
88
|
-
originalTotalPrice: cartLine.pricing?.extendedUnitNetPrice || 0,
|
|
89
|
-
pricePerUnit: cartLine.pricing?.unitNetPrice || 0,
|
|
90
|
-
totalPrice: cartLine.pricing?.extendedUnitNetPrice || 0,
|
|
91
|
-
}, productId: cartLine.productId || '', quantity: cartLine.qtyOrdered || 1, sku: cartLine.erpNumber || '', tags: [], title: cartLine.productName }, cartLine.id))) }) }) })] }) }));
|
|
57
|
+
return (jsx(PaymentPageContent, { atp: atp, cart: cart, formId: PAYMENT_FORM_ID, hasAtp: Boolean(hasAtp), isProcessing: isProcessing, isValidating: isValidating, onPaymentComplete: onPaymentComplete, setIsProcessing: setIsProcessing, setIsValidating: setIsValidating }));
|
|
92
58
|
}
|
|
93
59
|
|
|
94
60
|
export { PaymentPage };
|
|
@@ -4,11 +4,11 @@ import { Form } from 'react-aria-components';
|
|
|
4
4
|
import { CountrySelect } from '../../../../country-selector/country-select/country-select.js';
|
|
5
5
|
import { Checkbox } from '../../../../forms/checkbox/checkbox.js';
|
|
6
6
|
import { TextField } from '../../../../forms/text-field/text-field.js';
|
|
7
|
+
import { InfoIconTooltip } from '../../../../info-icon-tooltip/info-icon-tooltip.js';
|
|
7
8
|
import { FormattedMessage } from '../../../../intl/formatted-message.js';
|
|
8
9
|
import { useFormattedMessage } from '../../../../intl/use-formatted-message.js';
|
|
9
10
|
import { useFetchCurrentCart } from '../../../../shared/api/storefront/hooks/cart/use-fetch-current-cart.js';
|
|
10
11
|
import { validatePhone, validateEmail } from '../../../../shared/model/address.js';
|
|
11
|
-
import { Tooltip } from '../../../../tooltip/tooltip.js';
|
|
12
12
|
import { CheckoutPageSection } from '../../layouts/checkout-page-layout/components/checkout-page-section.js';
|
|
13
13
|
import { CheckoutPageSectionContent } from '../../layouts/checkout-page-layout/components/checkout-page-section-content.js';
|
|
14
14
|
import { SonicAddress } from './sonic-address.js';
|
|
@@ -43,7 +43,7 @@ function EditAddresses({ countries, isLoading, isPickup, onSubmit, }) {
|
|
|
43
43
|
},
|
|
44
44
|
notes: formData.get('notes')?.toString() || '',
|
|
45
45
|
});
|
|
46
|
-
}, children: [jsx(TextField, { isDisabled: isLoading, label: t('First name'), name: "firstName", showLabel: true }), jsx(TextField, { isDisabled: isLoading, isRequired: !companyName, label: t('Last name'), minLength: 3, name: "lastName", onChange: setLastName, showLabel: true, value: lastName }, `lastname-${Boolean(companyName)}`), jsx(TextField, { isDisabled: isLoading, label: t('Company name'), name: "companyName", onChange: setCompanyName, showLabel: true, value: companyName }), jsx(TextField, { isDisabled: isLoading, label: t('Attention'), name: "attention", showLabel: true }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isRequired: true, isDisabled: isLoading, label: `${t('Address')} 1`, maxLength: 30, minLength: 3, name: "address1", showLabel: true }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isDisabled: isLoading, label: `${t('Address')} 2`, maxLength: 30, minLength: 3, name: "address2", showLabel: true }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isDisabled: isLoading, label: `${t('Address')} 3`, maxLength: 30, minLength: 3, name: "address3", showLabel: true }) }), jsx(TextField, { isRequired: true, isDisabled: isLoading, label: t('Postal Code'), maxLength: 10, minLength: 4, name: "postalCode", showLabel: true }), jsx(TextField, { isRequired: true, isDisabled: isLoading, label: t('City'), maxLength: 30, minLength: 3, name: "city", showLabel: true }), jsx("div", { className: styles['span-2'], children: jsx(CountrySelect, { isRequired: true, countries: countries, "data-test-selector": "countrySelect", name: "countrySelect" }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isRequired: true, isDisabled: isLoading, label: t('Phone'), name: "phone", showLabel: true, validate: value => {
|
|
46
|
+
}, children: [jsx(TextField, { isDisabled: isLoading, label: t('First name'), name: "firstName", showLabel: true }), jsx(TextField, { isDisabled: isLoading, isRequired: !companyName, label: t('Last name'), minLength: 3, name: "lastName", onChange: setLastName, showLabel: true, value: lastName }, `lastname-${Boolean(companyName)}`), jsx(TextField, { isDisabled: isLoading, label: t('Company name'), name: "companyName", onChange: setCompanyName, showLabel: true, value: companyName }), jsx(TextField, { isDisabled: isLoading, label: t('Attention'), name: "attention", showLabel: true }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isRequired: true, isDisabled: isLoading, label: `${t('Address')} 1`, maxLength: 30, minLength: 3, name: "address1", showLabel: true }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isDisabled: isLoading, label: `${t('Address')} 2`, maxLength: 30, minLength: 3, name: "address2", showLabel: true }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isDisabled: isLoading, label: `${t('Address')} 3`, maxLength: 30, minLength: 3, name: "address3", showLabel: true }) }), jsx(TextField, { isRequired: true, isDisabled: isLoading, label: t('Postal Code'), maxLength: 10, minLength: 4, name: "postalCode", showLabel: true }), jsx(TextField, { isRequired: true, isDisabled: isLoading, label: t('City'), maxLength: 30, minLength: 3, name: "city", showLabel: true }), jsx("div", { className: styles['span-2'], children: jsx(CountrySelect, { isRequired: true, countries: countries, "data-test-selector": "countrySelect", isDisabled: isLoading, name: "countrySelect" }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isRequired: true, isDisabled: isLoading, label: t('Phone'), name: "phone", showLabel: true, validate: value => {
|
|
47
47
|
if (!value)
|
|
48
48
|
return value;
|
|
49
49
|
return (validatePhone(value) ||
|
|
@@ -53,7 +53,7 @@ function EditAddresses({ countries, isLoading, isPickup, onSubmit, }) {
|
|
|
53
53
|
return value;
|
|
54
54
|
return (validateEmail(value) ||
|
|
55
55
|
t('Please enter a valid e-mail address'));
|
|
56
|
-
} }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isDisabled: isLoading, isMultiline: true, label: t('Add order notes'), name: "notes", rows: 3, showLabel: true }) })] }) }) }), jsx(CheckoutPageSection, { title: jsx(FormattedMessage, { id: isPickup ? 'Pickup address' : 'Shipping address' }), children: jsx(CheckoutPageSectionContent, { children: jsx(Fragment, { children: isPickup ? (jsx(SonicAddress, {})) : (jsxs("div", { className: styles['use-invoice-checkbox'], children: [jsx(Checkbox, { "data-test-selector": "checkboxUseBillingAddress", isDisabled: true, isSelected: true, children: jsx(FormattedMessage, { id: "Use billing address" }) }), jsx(
|
|
56
|
+
} }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isDisabled: isLoading, isMultiline: true, label: t('Add order notes'), name: "notes", rows: 3, showLabel: true }) })] }) }) }), jsx(CheckoutPageSection, { title: jsx(FormattedMessage, { id: isPickup ? 'Pickup address' : 'Shipping address' }), children: jsx(CheckoutPageSectionContent, { children: jsx(Fragment, { children: isPickup ? (jsx(SonicAddress, {})) : (jsxs("div", { className: styles['use-invoice-checkbox'], children: [jsx(Checkbox, { "data-test-selector": "checkboxUseBillingAddress", isDisabled: true, isSelected: true, children: jsx(FormattedMessage, { id: "Use billing address" }) }), jsx(InfoIconTooltip, { variant: "stroke", children: t('Changing your address is currently not possible. Please contact customer support to change your address.') })] })) }) }) })] }));
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
export { EDIT_ADDRESS_FORM_ID, EditAddresses };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { CartModel } from '../../../shared/api/storefront/model/storefront.model';
|
|
3
|
+
export interface ShippingPageContentProps {
|
|
4
|
+
cart: CartModel;
|
|
5
|
+
editAddress: ReactNode;
|
|
6
|
+
errorPatchBillingAddress?: unknown;
|
|
7
|
+
fulfillmentMethods: string[] | undefined;
|
|
8
|
+
isLoadingFulfillmentMethods: boolean;
|
|
9
|
+
isPatching: boolean;
|
|
10
|
+
isPatchingSession: boolean;
|
|
11
|
+
onChangeFulfillmentMethod: (value: string) => void;
|
|
12
|
+
readOnlyAddress: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
export declare function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulfillmentMethods, isLoadingFulfillmentMethods, isPatching, isPatchingSession, onChangeFulfillmentMethod, readOnlyAddress, }: ShippingPageContentProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { Button } from '../../../buttons/button/button.js';
|
|
4
|
+
import { CartTotals } from '../../../cart-totals/cart-totals.js';
|
|
5
|
+
import { CartTotalsSummary } from '../../../cart-totals/cart-totals-summary.js';
|
|
6
|
+
import { Select } from '../../../forms/select/select.js';
|
|
7
|
+
import { FormattedMessage } from '../../../intl/formatted-message.js';
|
|
8
|
+
import { useFormattedMessage } from '../../../intl/use-formatted-message.js';
|
|
9
|
+
import { Page } from '../../components/page/page.js';
|
|
10
|
+
import { CHECKOUT_PATHS } from '../constants.js';
|
|
11
|
+
import { CheckoutPageLayout } from '../layouts/checkout-page-layout/checkout-page-layout.js';
|
|
12
|
+
import { CheckoutPageSection } from '../layouts/checkout-page-layout/components/checkout-page-section.js';
|
|
13
|
+
import { CheckoutPageSectionContent } from '../layouts/checkout-page-layout/components/checkout-page-section-content.js';
|
|
14
|
+
import { EDIT_ADDRESS_FORM_ID } from './components/edit-address.js';
|
|
15
|
+
import styles from './shipping-page.module.css.js';
|
|
16
|
+
|
|
17
|
+
function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulfillmentMethods, isLoadingFulfillmentMethods, isPatching, isPatchingSession, onChangeFulfillmentMethod, readOnlyAddress, }) {
|
|
18
|
+
const t = useFormattedMessage();
|
|
19
|
+
const fulfillmentMethodOptions = fulfillmentMethods?.reduce((acc, method) => ({
|
|
20
|
+
...acc,
|
|
21
|
+
[method]: t(`fulfillmentMethod.${method}`),
|
|
22
|
+
}), {});
|
|
23
|
+
const hasBillToAddress = useMemo(() => {
|
|
24
|
+
return Boolean(cart.billTo?.address1);
|
|
25
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26
|
+
}, [Boolean(cart)]);
|
|
27
|
+
return (jsx(Page, { breadCrumb: [
|
|
28
|
+
{ href: CHECKOUT_PATHS.HOME, label: t('Home') },
|
|
29
|
+
{
|
|
30
|
+
href: CHECKOUT_PATHS.CHECKOUT_SHIPPING,
|
|
31
|
+
label: t('Shipping details'),
|
|
32
|
+
},
|
|
33
|
+
], title: t('Shipping details'), children: jsxs(CheckoutPageLayout, { actions: {
|
|
34
|
+
primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutShippingCartTotalContinueButton", form: EDIT_ADDRESS_FORM_ID, isDisabled: isPatching, isLoading: isPatching || isPatchingSession ? (jsx(FormattedMessage, { id: "Updating address" })) : undefined, type: "submit", children: jsx(FormattedMessage, { id: "Continue shopping" }) })),
|
|
35
|
+
}, mobileSummary: jsx(CartTotalsSummary, { totalAmount: cart.orderGrandTotalDisplay }), overview: jsx(CartTotals, { fulfillmentMethod: fulfillmentMethods && fulfillmentMethods.length === 1
|
|
36
|
+
? cart.fulfillmentMethod
|
|
37
|
+
: undefined, shippingCost: cart.shippingAndHandlingDisplay, subtotal: cart.orderSubTotalDisplay, tax: cart.totalTaxDisplay, total: cart.orderGrandTotalDisplay, vatPercentage: cart.cartLines?.[0]?.pricing?.vatRate }), children: [jsxs(Fragment, { children: [fulfillmentMethods && fulfillmentMethods.length > 1 && (jsx(CheckoutPageSection, { hasBorder: true, title: t('Fulfillment method'), children: jsx(CheckoutPageSectionContent, { children: jsx("div", { className: styles['fulfillment-select-wrapper'], children: jsx(Select, { isRequired: true, showLabel: true, "data-test-selector": "fulfillmentMethodSelect", defaultSelectedOption: cart.fulfillmentMethod, isLoading: isLoadingFulfillmentMethods, label: t('Fulfillment method'), name: "fulfillmentMethod", onChange: onChangeFulfillmentMethod, options: fulfillmentMethodOptions || {}, variant: "solid" }) }) }) })), hasBillToAddress ? readOnlyAddress : editAddress] }), Boolean(errorPatchBillingAddress) && (jsx("div", { className: styles['error-message'], children: jsx(FormattedMessage, { id: "An unexpected error occured" }) }))] }) }));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { ShippingPageContent };
|
|
@@ -1,33 +1,26 @@
|
|
|
1
|
-
import { jsx
|
|
2
|
-
import {
|
|
3
|
-
import { Button } from '../../../buttons/button/button.js';
|
|
4
|
-
import { CartTotals } from '../../../cart-totals/cart-totals.js';
|
|
5
|
-
import { CartTotalsSummary } from '../../../cart-totals/cart-totals-summary.js';
|
|
6
|
-
import { Select } from '../../../forms/select/select.js';
|
|
7
|
-
import { FormattedMessage } from '../../../intl/formatted-message.js';
|
|
8
|
-
import { useFormattedMessage } from '../../../intl/use-formatted-message.js';
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useRef, useEffect } from 'react';
|
|
9
3
|
import { useFetchSession } from '../../../shared/api/storefront/hooks/authentication/use-fetch-session.js';
|
|
10
4
|
import { useIsAuthenticated } from '../../../shared/api/storefront/hooks/authentication/use-is-authenticated.js';
|
|
11
5
|
import { usePatchSession } from '../../../shared/api/storefront/hooks/authentication/use-patch-session.js';
|
|
12
6
|
import { useFetchCurrentCart } from '../../../shared/api/storefront/hooks/cart/use-fetch-current-cart.js';
|
|
13
7
|
import { useFetchFulfillmentMethodsForCurrentCart } from '../../../shared/api/storefront/hooks/customer/use-fetch-fulfillment-methods-for-current-cart.js';
|
|
14
8
|
import { useFetchCountries } from '../../../shared/api/storefront/hooks/website/use-fetch-countries.js';
|
|
9
|
+
import { useDataLayer } from '../../../shared/ga/use-data-layer.js';
|
|
15
10
|
import { useNavigate } from '../../../shared/routing/route-provider.js';
|
|
16
11
|
import { hasNo } from '../../../shared/utils/types.js';
|
|
17
|
-
import { Page } from '../../components/page/page.js';
|
|
18
12
|
import { ErrorPage } from '../../error-page/error-page.js';
|
|
19
13
|
import { LoadingPage } from '../../loading-page/loading-page.js';
|
|
20
14
|
import { CHECKOUT_PATHS } from '../constants.js';
|
|
21
|
-
import {
|
|
22
|
-
import { CheckoutPageSection } from '../layouts/checkout-page-layout/components/checkout-page-section.js';
|
|
23
|
-
import { CheckoutPageSectionContent } from '../layouts/checkout-page-layout/components/checkout-page-section-content.js';
|
|
24
|
-
import { EDIT_ADDRESS_FORM_ID, EditAddresses } from './components/edit-address.js';
|
|
15
|
+
import { EditAddresses } from './components/edit-address.js';
|
|
25
16
|
import { ReadOnlyAddresses } from './components/readonly-address.js';
|
|
26
17
|
import { usePatchShippingDetails } from './hooks/use-patch-shipping-details.js';
|
|
27
|
-
import
|
|
18
|
+
import { ShippingPageContent } from './shipping-page-content.js';
|
|
28
19
|
|
|
29
20
|
function ShippingPage() {
|
|
30
21
|
const isAuthenticated = useIsAuthenticated();
|
|
22
|
+
const { createEcommerceEvent, dataLayer } = useDataLayer();
|
|
23
|
+
const gaEventPushed = useRef(false);
|
|
31
24
|
const { data: cart, error: errorFetchCart, isLoading: isLoadingCart, refetch: refetchCart, } = useFetchCurrentCart();
|
|
32
25
|
const { data: countries, isLoading: isLoadingCountries } = useFetchCountries({
|
|
33
26
|
enabled: hasNo(cart?.billTo?.address1),
|
|
@@ -37,16 +30,7 @@ function ShippingPage() {
|
|
|
37
30
|
const { isLoading: isPatchingSession, mutate: patchSession } = usePatchSession();
|
|
38
31
|
const { error: errorPatchBillingAddress, isError, isLoading: isPatching, isSuccess, mutate: patchShippingDetails, } = usePatchShippingDetails();
|
|
39
32
|
const isLoading = isLoadingCart || isLoadingCountries || isLoadingFulfillmentMethods;
|
|
40
|
-
const t = useFormattedMessage();
|
|
41
33
|
const { isNavigating, navigate } = useNavigate();
|
|
42
|
-
const hasBillToAddress = useMemo(() => {
|
|
43
|
-
return Boolean(cart?.billTo?.address1);
|
|
44
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
45
|
-
}, [Boolean(cart)]);
|
|
46
|
-
const fulfillmentMethodOptions = fulfillmentMethods?.reduce((acc, method) => ({
|
|
47
|
-
...acc,
|
|
48
|
-
[method]: t(`fulfillmentMethod.${method}`),
|
|
49
|
-
}), {});
|
|
50
34
|
const isPickup = cart?.fulfillmentMethod === 'PickUp';
|
|
51
35
|
useEffect(() => {
|
|
52
36
|
/* Initial guards. When these are not met, we should not proceed */
|
|
@@ -77,6 +61,15 @@ function ShippingPage() {
|
|
|
77
61
|
return;
|
|
78
62
|
return navigate(CHECKOUT_PATHS.REVIEW_AND_SUBMIT);
|
|
79
63
|
}, [isSuccess, cart, navigate, isNavigating, isPatching, isError]);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (!cart || gaEventPushed.current)
|
|
66
|
+
return;
|
|
67
|
+
dataLayer.push(createEcommerceEvent({
|
|
68
|
+
cart,
|
|
69
|
+
event: { event: 'begin_checkout' },
|
|
70
|
+
}));
|
|
71
|
+
gaEventPushed.current = true;
|
|
72
|
+
}, [cart, createEcommerceEvent, dataLayer]);
|
|
80
73
|
if (errorFetchCart)
|
|
81
74
|
return jsx(ErrorPage, { error: errorFetchCart });
|
|
82
75
|
if (isLoading || isNavigating || isError || isSuccess)
|
|
@@ -88,37 +81,35 @@ function ShippingPage() {
|
|
|
88
81
|
hasNo(cart.billTo) ||
|
|
89
82
|
(hasNo(cart.billTo.address1) && hasNo(countries)))
|
|
90
83
|
return null;
|
|
91
|
-
return (jsx(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
});
|
|
121
|
-
} }))] }), Boolean(errorPatchBillingAddress) && (jsx("div", { className: styles['error-message'], children: jsx(FormattedMessage, { id: "An unexpected error occured" }) }))] }) }));
|
|
84
|
+
return (jsx(ShippingPageContent, { cart: cart, editAddress: jsx(EditAddresses, { countries: countries || [], isLoading: isPatching, isPickup: isPickup, onSubmit: async ({ address, notes }) => {
|
|
85
|
+
if (!cart.billTo)
|
|
86
|
+
return;
|
|
87
|
+
await patchShippingDetails({
|
|
88
|
+
billTo: { ...cart.billTo, ...address },
|
|
89
|
+
cart,
|
|
90
|
+
notes,
|
|
91
|
+
});
|
|
92
|
+
dataLayer.push(createEcommerceEvent({
|
|
93
|
+
cart,
|
|
94
|
+
event: { event: 'add_shipping_info' },
|
|
95
|
+
}));
|
|
96
|
+
} }), errorPatchBillingAddress: errorPatchBillingAddress, fulfillmentMethods: fulfillmentMethods, isLoadingFulfillmentMethods: isLoadingFulfillmentMethods, isPatching: isPatching, isPatchingSession: isPatchingSession, onChangeFulfillmentMethod: async (value) => {
|
|
97
|
+
await patchSession({
|
|
98
|
+
session: {
|
|
99
|
+
...session,
|
|
100
|
+
fulfillmentMethod: value,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
await refetchCart();
|
|
104
|
+
}, readOnlyAddress: jsx(ReadOnlyAddresses, { billTo: cart.billTo, isLoading: isPatching, isPickup: isPickup, notes: cart.notes, onSubmit: async ({ notes }) => {
|
|
105
|
+
if (!cart.billTo)
|
|
106
|
+
return;
|
|
107
|
+
await patchShippingDetails({ cart, notes });
|
|
108
|
+
dataLayer.push(createEcommerceEvent({
|
|
109
|
+
cart,
|
|
110
|
+
event: { event: 'add_shipping_info' },
|
|
111
|
+
}));
|
|
112
|
+
}, shipTo: cart.shipTo }) }));
|
|
122
113
|
}
|
|
123
114
|
|
|
124
115
|
export { ShippingPage };
|
|
@@ -10,10 +10,20 @@ import { FormattedMessage } from '../../../../../intl/formatted-message.js';
|
|
|
10
10
|
import { DownloadDocumentList } from '../../../../../lists/download-document-list/download-document-list.js';
|
|
11
11
|
import { FeatureList } from '../../../../../lists/feature-list/feature-list.js';
|
|
12
12
|
import { Heading } from '../../../../../typography/heading/heading.js';
|
|
13
|
+
import { useAlgoliaInsights } from '../../../../../algolia/use-algolia-insights.js';
|
|
13
14
|
import styles from './product-details-panel.module.css.js';
|
|
14
15
|
|
|
15
16
|
function ProductDetailsPanel({ priceComponent, product, }) {
|
|
16
|
-
|
|
17
|
+
const { sendAddToCartFromProductDetailsPageEvent, sendAddToWishListFromProductDetailsPageEvent, } = useAlgoliaInsights();
|
|
18
|
+
return (jsxs("div", { className: styles['product-details-panel'], children: [jsxs("div", { className: styles.heading, children: [jsx(Heading, { italic: true, size: "xs", children: product.productTitle }), jsx(ProductSku, { sku: product.productNumber })] }), jsxs("div", { className: styles['price-action-container'], children: [priceComponent || (jsx(ProductPrice, { "data-test": "productPrice_unitNetPrice", isVatIncluded: product.isVatIncluded, originalPrice: product.originalPrice, price: product.price })), jsxs("div", { className: styles['action-container'], children: [product.canAddToCart && (jsx(ConnectedAddToCartButton, { onAddToCart: ({ cartLine }) => {
|
|
19
|
+
sendAddToCartFromProductDetailsPageEvent({
|
|
20
|
+
cartLine,
|
|
21
|
+
});
|
|
22
|
+
}, productId: product.storefrontId })), product.canAddToWishlist && (jsx(ConnectedFavoriteButton, { onFavoriting: () => {
|
|
23
|
+
sendAddToWishListFromProductDetailsPageEvent({
|
|
24
|
+
objectId: product.productNumber,
|
|
25
|
+
});
|
|
26
|
+
}, productId: product.storefrontId }))] })] }), jsxs("div", { children: [jsx(Heading, { italic: true, className: styles['product-features-heading'], size: "xxs", children: jsx(FormattedMessage, { id: "Product Features" }) }), product.content.htmlContent && (jsx(ShowAll, { initialHeight: 216, children: jsx("div", { className: styles.description, dangerouslySetInnerHTML: {
|
|
17
27
|
__html: product.content.htmlContent,
|
|
18
28
|
} }) }))] }), jsx("div", { children: jsxs(Accordion, { indented: true, borderType: ['top', 'middle-accentuated'], children: [product.attributeTypes.length > 0 && (jsx(AccordionItem, { id: "specification", title: jsx(FormattedMessage, { id: "Specifications" }), children: jsx(FeatureList, { className: styles['feature-list'], features: product.attributeTypes.map(attribute => ({
|
|
19
29
|
id: `${attribute.id}`,
|
|
@@ -15,7 +15,6 @@ function ProductHitCard({ hit }) {
|
|
|
15
15
|
title: hit.name,
|
|
16
16
|
}, onAddToCart: ({ cartLine }) => sendAddToCartFromProductListPageEvent({
|
|
17
17
|
cartLine,
|
|
18
|
-
objectId: hit.objectId,
|
|
19
18
|
}), onClick: () => sendProductClickFromProductListPageEvent({
|
|
20
19
|
objectId: hit.objectId,
|
|
21
20
|
position: hit.position,
|
|
@@ -15,7 +15,6 @@ function ProductHitCard({ hit }) {
|
|
|
15
15
|
title: hit.name,
|
|
16
16
|
}, onAddToCart: ({ cartLine }) => sendAddToCartFromSearchResultPageEvent({
|
|
17
17
|
cartLine,
|
|
18
|
-
objectId: hit.objectId,
|
|
19
18
|
}), onClick: () => {
|
|
20
19
|
sendProductClickFromSearchResultPageEvent({
|
|
21
20
|
objectId: hit.objectId,
|
|
@@ -49,10 +49,10 @@ export declare class InternalServerErrorRequestError extends RequestError {
|
|
|
49
49
|
constructor(responseOrError: Response | unknown, options?: RequestErrorOptions);
|
|
50
50
|
}
|
|
51
51
|
export type RequestHeaders = Record<string, string | null | undefined>;
|
|
52
|
-
type RequestHeadersWithBody = RequestHeaders & {
|
|
52
|
+
export type RequestHeadersWithBody = RequestHeaders & {
|
|
53
53
|
'Content-Type': string;
|
|
54
54
|
};
|
|
55
|
-
interface BaseRequestOptions {
|
|
55
|
+
export interface BaseRequestOptions {
|
|
56
56
|
cache?: RequestCache;
|
|
57
57
|
credentials?: RequestCredentials;
|
|
58
58
|
headers?: RequestHeaders;
|
|
@@ -65,38 +65,43 @@ interface BaseRequestOptions {
|
|
|
65
65
|
timeout?: number;
|
|
66
66
|
url: string;
|
|
67
67
|
}
|
|
68
|
-
interface RequestOptionsWithFormData extends BaseRequestOptions {
|
|
68
|
+
export interface RequestOptionsWithFormData extends BaseRequestOptions {
|
|
69
69
|
body: FormData;
|
|
70
70
|
headers: RequestHeaders;
|
|
71
71
|
}
|
|
72
|
-
interface RequestOptionsWithBody extends BaseRequestOptions {
|
|
72
|
+
export interface RequestOptionsWithBody extends BaseRequestOptions {
|
|
73
73
|
body: unknown;
|
|
74
74
|
headers: RequestHeadersWithBody;
|
|
75
75
|
}
|
|
76
|
-
interface RequestOptionsWithoutBody extends BaseRequestOptions {
|
|
76
|
+
export interface RequestOptionsWithoutBody extends BaseRequestOptions {
|
|
77
77
|
body?: never;
|
|
78
78
|
headers?: RequestHeaders;
|
|
79
79
|
}
|
|
80
|
-
type RequestOptions = RequestOptionsWithBody | RequestOptionsWithoutBody | RequestOptionsWithFormData;
|
|
81
|
-
type
|
|
80
|
+
export type RequestOptions = RequestOptionsWithBody | RequestOptionsWithoutBody | RequestOptionsWithFormData;
|
|
81
|
+
type BeforeRequestHandler = (options?: RequestOptions) => RequestOptions | void;
|
|
82
|
+
type BeforeRequestHandlerAsync = (options?: RequestOptions) => Promise<RequestOptions | void>;
|
|
83
|
+
export interface AfterRequestHandlerArgs<T> {
|
|
82
84
|
body: T | undefined;
|
|
83
85
|
error?: RequestError;
|
|
84
86
|
options: RequestOptions;
|
|
85
87
|
response?: Response;
|
|
86
|
-
}
|
|
87
|
-
type
|
|
88
|
-
type
|
|
88
|
+
}
|
|
89
|
+
export type AfterRequestHandler<T> = (args: AfterRequestHandlerArgs<T>) => void;
|
|
90
|
+
export type AfterRequestHandlerAsync<T> = (args: AfterRequestHandlerArgs<T>) => Promise<void>;
|
|
91
|
+
export declare const isJsonBody: (options: RequestOptions) => boolean;
|
|
92
|
+
export declare const isFormData: (body: unknown) => body is FormData;
|
|
93
|
+
export type RequestReturnType<T> = Promise<{
|
|
89
94
|
body: T;
|
|
90
95
|
headers: Headers;
|
|
91
96
|
status: number;
|
|
92
97
|
statusText: string;
|
|
93
98
|
}>;
|
|
94
|
-
interface Request {
|
|
99
|
+
export interface Request {
|
|
95
100
|
<T>(options: RequestOptions): RequestReturnType<T>;
|
|
96
|
-
_afterHandlers: AfterRequestHandler<any>[];
|
|
97
|
-
_beforeHandlers: BeforeRequestHandler[];
|
|
98
101
|
after<T = any>(handler: AfterRequestHandler<T>): void;
|
|
102
|
+
after<T = any>(handler: AfterRequestHandlerAsync<T>): void;
|
|
99
103
|
before(handler: BeforeRequestHandler): void;
|
|
104
|
+
before(handler: BeforeRequestHandlerAsync): void;
|
|
100
105
|
headers: Omit<RequestHeaders, 'Content-Type'>;
|
|
101
106
|
}
|
|
102
107
|
export declare const request: Request;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import qs from 'query-string';
|
|
2
|
+
import { isPromise } from '../utils/promise.js';
|
|
2
3
|
|
|
3
4
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4
5
|
const isResponse = (response) => Boolean(response?.json);
|
|
@@ -181,17 +182,20 @@ const createBody = (options) => {
|
|
|
181
182
|
throw new Error(`request: Unknown body type for request ${url}. Unable to send request.`);
|
|
182
183
|
};
|
|
183
184
|
const createHeaders = (...headers) => {
|
|
184
|
-
const allHeaders =
|
|
185
|
+
const allHeaders = new Headers();
|
|
185
186
|
for (const header of headers) {
|
|
186
187
|
if (!header)
|
|
187
188
|
continue;
|
|
188
189
|
for (const key of Object.keys(header)) {
|
|
189
190
|
if (header[key])
|
|
190
|
-
allHeaders
|
|
191
|
+
allHeaders.append(key, String(header[key]));
|
|
191
192
|
}
|
|
192
193
|
}
|
|
193
194
|
return allHeaders;
|
|
194
195
|
};
|
|
196
|
+
const beforeHandlers = [];
|
|
197
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
198
|
+
const afterHandlers = [];
|
|
195
199
|
/* Because of a bug in the rollup dts package the following code must be put inside of a IIFE.
|
|
196
200
|
* The bug occurs when assigning properties to the request function at the top level of this file.
|
|
197
201
|
* request.headers = {}
|
|
@@ -204,7 +208,12 @@ const request = (function createRequestFunction() {
|
|
|
204
208
|
let error;
|
|
205
209
|
let isTimeout = false;
|
|
206
210
|
try {
|
|
207
|
-
|
|
211
|
+
for await (const handler of beforeHandlers) {
|
|
212
|
+
const promiseOrOptions = handler(options);
|
|
213
|
+
options = isPromise(promiseOrOptions)
|
|
214
|
+
? (await promiseOrOptions) || options
|
|
215
|
+
: promiseOrOptions || options;
|
|
216
|
+
}
|
|
208
217
|
options.timeout = options.timeout || 1000 * 60 * 2;
|
|
209
218
|
const url = qs.stringifyUrl({ query: options.params, url: options.url });
|
|
210
219
|
const controller = new AbortController();
|
|
@@ -245,19 +254,23 @@ const request = (function createRequestFunction() {
|
|
|
245
254
|
throw error;
|
|
246
255
|
}
|
|
247
256
|
finally {
|
|
248
|
-
|
|
257
|
+
for await (const handler of afterHandlers) {
|
|
258
|
+
const promiseOrVoid = handler({ body, error, options, response });
|
|
259
|
+
if (isPromise(promiseOrVoid))
|
|
260
|
+
await promiseOrVoid;
|
|
261
|
+
}
|
|
249
262
|
}
|
|
250
263
|
};
|
|
251
264
|
request.headers = {};
|
|
252
|
-
request._afterHandlers = [];
|
|
253
|
-
request._beforeHandlers = [];
|
|
254
265
|
request.after = (handler) => {
|
|
255
|
-
|
|
266
|
+
afterHandlers.push(
|
|
267
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
268
|
+
handler);
|
|
256
269
|
};
|
|
257
270
|
request.before = (handler) => {
|
|
258
|
-
|
|
271
|
+
beforeHandlers.push(handler);
|
|
259
272
|
};
|
|
260
273
|
return request;
|
|
261
274
|
})();
|
|
262
275
|
|
|
263
|
-
export { BadRequestError, ForbiddenRequestError, InternalServerErrorRequestError, NotFoundRequestError, RequestError, TimeoutRequestError, UnauthorizedRequestError, UnprocessableContentRequestError, isRequestError, request };
|
|
276
|
+
export { BadRequestError, ForbiddenRequestError, InternalServerErrorRequestError, NotFoundRequestError, RequestError, TimeoutRequestError, UnauthorizedRequestError, UnprocessableContentRequestError, isFormData, isJsonBody, isRequestError, request };
|
|
@@ -8,9 +8,13 @@ interface GAProductModel {
|
|
|
8
8
|
unitListPriceDisplay: string;
|
|
9
9
|
}
|
|
10
10
|
interface GACartModel {
|
|
11
|
-
cartLines
|
|
11
|
+
cartLines?: CartModel['cartLines'];
|
|
12
12
|
currencySymbol: string;
|
|
13
|
+
orderGrandTotal: number;
|
|
13
14
|
orderSubTotal: number;
|
|
15
|
+
shippingAndHandling: number;
|
|
16
|
+
totalTax: number;
|
|
17
|
+
trackId: string;
|
|
14
18
|
}
|
|
15
19
|
interface GACartLineModel {
|
|
16
20
|
erpNumber: string;
|
|
@@ -26,12 +30,12 @@ interface CreateEcommerceEventArgsWithCartLine {
|
|
|
26
30
|
event: GAEcommerceEvent;
|
|
27
31
|
}
|
|
28
32
|
interface CreateEcommerceEventArgsWithCart {
|
|
33
|
+
cart: GACartModel;
|
|
29
34
|
event: GAEcommerceEvent;
|
|
30
|
-
product: GAProductModel;
|
|
31
35
|
}
|
|
32
36
|
interface CreateEcommerceEventArgsWithProduct {
|
|
33
|
-
cart: GACartModel;
|
|
34
37
|
event: GAEcommerceEvent;
|
|
38
|
+
product: GAProductModel;
|
|
35
39
|
}
|
|
36
40
|
interface CreateEcommerceEvent {
|
|
37
41
|
(args: CreateEcommerceEventArgsWithCart): GAEcommerceEvent;
|
|
@@ -12,7 +12,8 @@ function useDataLayer(eventOrArgs) {
|
|
|
12
12
|
...event,
|
|
13
13
|
ecommerce: {
|
|
14
14
|
...event.ecommerce,
|
|
15
|
-
currency: event.ecommerce?.currency ??
|
|
15
|
+
currency: event.ecommerce?.currency ??
|
|
16
|
+
currencySymbolToISO[cart.currencySymbol],
|
|
16
17
|
customer: event.ecommerce?.customer ?? customerNumber,
|
|
17
18
|
items: cart.cartLines?.map(cartLine => ({
|
|
18
19
|
item_id: cartLine.erpNumber,
|
|
@@ -20,6 +21,10 @@ function useDataLayer(eventOrArgs) {
|
|
|
20
21
|
price: cartLine.pricing?.unitNetPrice,
|
|
21
22
|
quantity: cartLine.qtyOrdered ?? 0,
|
|
22
23
|
})) ?? [],
|
|
24
|
+
shipping: cart.shippingAndHandling,
|
|
25
|
+
tax: cart.totalTax,
|
|
26
|
+
transaction_id: cart.trackId,
|
|
27
|
+
value: cart.orderGrandTotal,
|
|
23
28
|
},
|
|
24
29
|
value: event.value ?? cart.orderSubTotal ?? 0,
|
|
25
30
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
function wait(ms) {
|
|
2
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
3
|
+
}
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
|
+
function isPromise(value) {
|
|
6
|
+
return value && typeof value.then === 'function';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { isPromise, wait };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
interface LoginData {
|
|
2
|
+
email: string;
|
|
3
|
+
guestSignin: false;
|
|
4
|
+
password: string;
|
|
5
|
+
remember?: boolean;
|
|
6
|
+
}
|
|
7
|
+
interface GuestLoginData {
|
|
8
|
+
guestSignin: true;
|
|
9
|
+
}
|
|
10
|
+
export interface SignInFormProps {
|
|
11
|
+
allowGuestSignIn?: boolean;
|
|
12
|
+
initialEmail?: string;
|
|
13
|
+
initialRemember?: boolean;
|
|
14
|
+
onSubmit?: ({ data }: {
|
|
15
|
+
data: LoginData | GuestLoginData;
|
|
16
|
+
}) => void;
|
|
17
|
+
}
|
|
18
|
+
export declare function SignInForm({ allowGuestSignIn, initialEmail, initialRemember, onSubmit, }: SignInFormProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export {};
|