@sonic-equipment/ui 148.0.0 → 149.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/address-info-display/address-info-display.js +1 -2
- package/dist/algolia/algolia-hit-type.d.ts +2 -0
- package/dist/algolia/use-algolia-insights.js +3 -3
- package/dist/cards/orderline-card/orderline-card.js +2 -2
- package/dist/cards/orderline-card/orderline-card.module.css.js +1 -1
- package/dist/cards/product-card/product-card.js +3 -2
- package/dist/cards/product-card/product-card.module.css.js +1 -1
- package/dist/cart-totals/cart-totals-summary.d.ts +4 -2
- package/dist/cart-totals/cart-totals-summary.js +3 -2
- package/dist/cart-totals/cart-totals.d.ts +7 -5
- package/dist/cart-totals/cart-totals.js +3 -2
- package/dist/delivery-time/delivery-time.js +2 -2
- package/dist/display/price/price.d.ts +18 -0
- package/dist/display/price/price.js +30 -0
- package/dist/display/price/price.module.css.js +3 -0
- package/dist/display/product-sku/product-sku.d.ts +2 -1
- package/dist/display/product-sku/product-sku.js +3 -2
- package/dist/exports.d.ts +4 -2
- package/dist/global-search/search-result-panel/sections/with-results.js +1 -0
- package/dist/index.js +8 -6
- package/dist/intl/intl-context.d.ts +10 -4
- package/dist/intl/intl-context.js +4 -0
- package/dist/intl/intl-provider.d.ts +4 -2
- package/dist/intl/intl-provider.js +18 -4
- package/dist/intl/missing-translation-provider.js +3 -2
- package/dist/intl/translation-id.d.ts +1 -1
- package/dist/intl/types.d.ts +2 -0
- package/dist/intl/types.js +6 -1
- package/dist/intl/use-country-code.d.ts +3 -0
- package/dist/intl/use-country-code.js +15 -0
- package/dist/intl/use-culture-code.d.ts +2 -1
- package/dist/intl/use-culture-code.js +5 -4
- package/dist/intl/use-currency-code.d.ts +4 -0
- package/dist/intl/use-currency-code.js +15 -0
- package/dist/intl/use-formatted-message.js +2 -3
- package/dist/intl/use-intl.d.ts +1 -0
- package/dist/intl/use-intl.js +9 -0
- package/dist/intl/use-language-code.js +2 -3
- package/dist/pages/checkout/cart-page/cart-page.js +6 -1
- package/dist/pages/checkout/order-confirmation-page/order-confirmation-page-content.js +6 -1
- package/dist/pages/checkout/payment-page/components/adyen-payment.d.ts +3 -2
- package/dist/pages/checkout/payment-page/components/payment.js +22 -22
- package/dist/pages/checkout/payment-page/payment-page-content.js +7 -2
- package/dist/pages/checkout/payment-page/utils/parse-amount.d.ts +2 -1
- package/dist/pages/checkout/shipping-page/shipping-page-content.js +6 -2
- package/dist/pages/product/product-details-page/components/product-details-panel/product-details-panel.js +2 -2
- package/dist/pages/product/product-details-page/components/product-details-panel/product-details-panel.module.css.js +1 -1
- package/dist/pages/product/product-listing-page/product-listing-product-overview/product-listing-product-overview.js +1 -0
- package/dist/pages/product/search-result-page/search-result-product-overview/search-result-product-overview.js +1 -0
- package/dist/shared/api/bff/model/bff.model.d.ts +3 -0
- package/dist/shared/api/storefront/hooks/cart/use-place-order.d.ts +1 -1
- package/dist/shared/api/storefront/services/cart-service.d.ts +1 -1
- package/dist/shared/api/storefront/services/cart-service.js +1 -1
- package/dist/shared/ga/use-data-layer.js +4 -4
- package/dist/shared/model/currency.d.ts +8 -1
- package/dist/shared/model/currency.js +28 -30
- package/dist/shared/model/hit.d.ts +2 -0
- package/dist/shared/model/hit.js +1 -0
- package/dist/shared/model/price.d.ts +5 -2
- package/dist/shared/utils/price.d.ts +19 -5
- package/dist/shared/utils/price.js +36 -7
- package/dist/shared/utils/string.d.ts +0 -1
- package/dist/shared/utils/string.js +1 -4
- package/dist/styles.css +467 -278
- package/package.json +1 -1
- package/dist/display/product-price/product-price.d.ts +0 -7
- package/dist/display/product-price/product-price.js +0 -19
- package/dist/display/product-price/product-price.module.css.js +0 -3
- package/dist/display/product-price/product-total-price.d.ts +0 -7
- package/dist/display/product-price/product-total-price.js +0 -16
- package/dist/display/product-price/product-total-price.module.css.js +0 -3
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useIntl } from './use-intl.js';
|
|
3
|
+
|
|
4
|
+
function useCurrencyCode() {
|
|
5
|
+
const { currencyCode } = useIntl();
|
|
6
|
+
return currencyCode;
|
|
7
|
+
}
|
|
8
|
+
function useUpdateCurrencyCode() {
|
|
9
|
+
const { updateCurrencyCode } = useIntl();
|
|
10
|
+
if (!updateCurrencyCode)
|
|
11
|
+
throw new Error('updateCurrencyCode is not defined');
|
|
12
|
+
return updateCurrencyCode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { useCurrencyCode, useUpdateCurrencyCode };
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import { IntlContext } from './intl-context.js';
|
|
2
|
+
import { useIntl } from './use-intl.js';
|
|
4
3
|
|
|
5
4
|
function useFormattedMessage() {
|
|
6
|
-
const { formattedMessage } =
|
|
5
|
+
const { formattedMessage } = useIntl();
|
|
7
6
|
const formatFunction = (id, options) => formattedMessage(id, options);
|
|
8
7
|
function pluralize(translationIdOrPrefix, translationIdOrCount, count) {
|
|
9
8
|
return formatFunction((typeof translationIdOrCount === 'number'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useIntl(): import("./intl-context").IntlContextType;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import { IntlContext } from './intl-context.js';
|
|
2
|
+
import { useIntl } from './use-intl.js';
|
|
4
3
|
import { getLanguageCodeFromCultureCode } from './utils.js';
|
|
5
4
|
|
|
6
5
|
function useLanguageCode() {
|
|
7
|
-
const { cultureCode } =
|
|
6
|
+
const { cultureCode } = useIntl();
|
|
8
7
|
return getLanguageCodeFromCultureCode(cultureCode);
|
|
9
8
|
}
|
|
10
9
|
|
|
@@ -17,6 +17,7 @@ import { RouteButton } from '../../../shared/routing/route-button.js';
|
|
|
17
17
|
import { useToast } from '../../../toast/use-toast.js';
|
|
18
18
|
import { useFetchCurrentCartLinesWithAtp } from '../../../shared/api/storefront/hooks/cart/use-fetch-current-cart-lines-with-atp.js';
|
|
19
19
|
import { useFetchCurrentCartWithAtp } from '../../../shared/api/storefront/hooks/cart/use-fetch-current-cart-with-atp.js';
|
|
20
|
+
import { getCurrencyCodeBySymbol } from '../../../shared/model/currency.js';
|
|
20
21
|
import { PATHS } from '../../paths.js';
|
|
21
22
|
import { EmptyCart } from './components/empty-cart-page.js';
|
|
22
23
|
|
|
@@ -74,6 +75,9 @@ function CartContent({ cartLines }) {
|
|
|
74
75
|
const isAuthenticated = useIsAuthenticated();
|
|
75
76
|
if (!currentCart)
|
|
76
77
|
return null;
|
|
78
|
+
const currencyCode = getCurrencyCodeBySymbol(currentCart.currencySymbol);
|
|
79
|
+
if (!currencyCode)
|
|
80
|
+
throw new Error(`Currency code not found for symbol ${currentCart.currencySymbol}`);
|
|
77
81
|
return (jsx(CheckoutPageLayout, { actions: {
|
|
78
82
|
primary: (jsx(RouteButton, { withArrow: true, "data-test-selector": "checkoutShippingCartTotalContinueButton", href: "/CheckoutShipping", children: jsx(FormattedMessage, { id: "Continue shopping" }) })),
|
|
79
83
|
secondary: (jsx(RouteButton, { color: "secondary", href: isAuthenticated ? undefined : PATHS.SIGN_IN, onClick: () => {
|
|
@@ -81,7 +85,7 @@ function CartContent({ cartLines }) {
|
|
|
81
85
|
return;
|
|
82
86
|
saveCartForLater.mutate({ cart: currentCart });
|
|
83
87
|
}, variant: "outline", children: jsx(FormattedMessage, { id: "Save order" }) })),
|
|
84
|
-
}, mobileSummary: jsx(CartTotalsSummary, { totalAmount: currentCart.
|
|
88
|
+
}, mobileSummary: jsx(CartTotalsSummary, { currencyCode: currencyCode, totalAmount: currentCart.orderGrandTotal }), overview: jsx(CartTotals, { currencyCode: currencyCode, shippingCost: currentCart.shippingAndHandling, subtotal: currentCart.orderSubTotal, tax: currentCart.totalTax, total: currentCart.orderGrandTotal, vatPercentage: cartLines[0]?.pricing?.vatRate || 0 }), children: jsx(OrderLineList, { onRemoveAll: () => deleteCurrentCart.mutate(), children: cartLines.map(cartLine => (jsx(ConnectedOrderLineCard, { deliveryDate: cartLine.atp?.date, href: cartLine.productUri, image: {
|
|
85
89
|
fit: 'contain',
|
|
86
90
|
image: {
|
|
87
91
|
'1': cartLine.smallImagePath,
|
|
@@ -91,6 +95,7 @@ function CartContent({ cartLines }) {
|
|
|
91
95
|
},
|
|
92
96
|
title: cartLine.altText,
|
|
93
97
|
}, isReadonly: false, onRemove: () => deleteCartLine.mutate({ cartLineId: cartLine.id }), orderLineId: cartLine.id, price: {
|
|
98
|
+
currencyCode,
|
|
94
99
|
originalTotalPrice: cartLine.pricing?.extendedUnitNetPrice || 0,
|
|
95
100
|
pricePerUnit: cartLine.pricing?.unitNetPrice || 0,
|
|
96
101
|
totalPrice: cartLine.pricing?.extendedUnitNetPrice || 0,
|
|
@@ -8,6 +8,7 @@ import { useCultureCode } from '../../../intl/use-culture-code.js';
|
|
|
8
8
|
import { useFormattedMessage } from '../../../intl/use-formatted-message.js';
|
|
9
9
|
import { OrderLineList } from '../../../lists/orderline-list/orderline-list.js';
|
|
10
10
|
import { useSaveCartForLater } from '../../../shared/api/storefront/hooks/cart/use-save-cart-for-later.js';
|
|
11
|
+
import { getCurrencyCodeBySymbol } from '../../../shared/model/currency.js';
|
|
11
12
|
import { RouteButton } from '../../../shared/routing/route-button.js';
|
|
12
13
|
import { formatDateToLocaleString } from '../../../shared/utils/date.js';
|
|
13
14
|
import { useToast } from '../../../toast/use-toast.js';
|
|
@@ -39,6 +40,9 @@ function OrderConfirmationPageContent({ cart, }) {
|
|
|
39
40
|
});
|
|
40
41
|
},
|
|
41
42
|
});
|
|
43
|
+
const currencyCode = getCurrencyCodeBySymbol(cart.currencySymbol);
|
|
44
|
+
if (!currencyCode)
|
|
45
|
+
throw new Error(`Currency code not found for symbol ${cart.currencySymbol}`);
|
|
42
46
|
return (jsx(Page, { breadcrumb: [
|
|
43
47
|
{ href: PATHS.HOME, label: t('Home') },
|
|
44
48
|
{
|
|
@@ -50,7 +54,7 @@ function OrderConfirmationPageContent({ cart, }) {
|
|
|
50
54
|
secondary: (jsxs(Fragment, { children: [cart.canSaveOrder && (jsx(RouteButton, { color: "secondary", onClick: () => {
|
|
51
55
|
saveCartForLater.mutate({ cart });
|
|
52
56
|
}, variant: "outline", children: jsx(FormattedMessage, { id: "Save order" }) })), jsx(PrintButton, {})] })),
|
|
53
|
-
}, overview: jsx(CartTotals, { fulfillmentMethod: t(`fulfillmentmethod.${cart.fulfillmentMethod}`), orderNumber: cart.orderNumber, shippingCost: cart.
|
|
57
|
+
}, overview: jsx(CartTotals, { currencyCode: currencyCode, fulfillmentMethod: t(`fulfillmentmethod.${cart.fulfillmentMethod}`), orderNumber: cart.orderNumber, shippingCost: cart.shippingAndHandling, subtotal: cart.orderSubTotal, tax: cart.totalTax, total: cart.orderGrandTotal, vatPercentage: cart.cartLines?.[0]?.pricing?.vatRate }), children: jsxs("div", { children: [jsx(CheckoutPageSection, { hasBorder: false, title: t('General'), children: jsx(CheckoutPageSectionContent, { children: jsxs("div", { className: styles['general-order-info'], children: [cart.orderDate && (jsx(InfoDisplay, { id: "order-date", label: t('Order date'), value: formatDateToLocaleString(new Date(cart.orderDate), cultureCode) })), cart.requestedDeliveryDateDisplay && (jsx(InfoDisplay, { id: "requested-delivery-date", label: t('Requested delivery date'), value: formatDateToLocaleString(new Date(cart.requestedDeliveryDateDisplay.toString()), cultureCode) })), cart.poNumber && (jsx(InfoDisplay, { id: "po-number", label: t('PO Number'), value: cart.poNumber }))] }) }) }), jsx(CheckoutPageSection, { hasBorder: false, title: t('Billing and shipping information'), children: jsx(CheckoutPageSectionContent, { children: jsx(BillingAndInvoiceInformation, { billToAddress: {
|
|
54
58
|
address1: cart.billTo?.address1,
|
|
55
59
|
address2: cart.billTo?.address2,
|
|
56
60
|
address3: cart.billTo?.address3,
|
|
@@ -80,6 +84,7 @@ function OrderConfirmationPageContent({ cart, }) {
|
|
|
80
84
|
},
|
|
81
85
|
title: cartLine.altText,
|
|
82
86
|
}, isReadonly: true, price: {
|
|
87
|
+
currencyCode,
|
|
83
88
|
originalTotalPrice: cartLine.pricing?.extendedUnitNetPrice || 0,
|
|
84
89
|
pricePerUnit: cartLine.pricing?.unitNetPrice || 0,
|
|
85
90
|
totalPrice: cartLine.pricing?.extendedUnitNetPrice || 0,
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { MutableRefObject } from 'react';
|
|
2
2
|
import Dropin from '@adyen/adyen-web/dist/types/components/Dropin';
|
|
3
3
|
import { AdyenPaymentModel } from 'shared/api/storefront/model/storefront.model';
|
|
4
|
+
import { CountryCode, CurrencyCode } from '../../../../intl/types';
|
|
4
5
|
import '@adyen/adyen-web/dist/adyen.css';
|
|
5
6
|
interface AdyenPaymentProps {
|
|
6
7
|
amount: number;
|
|
7
8
|
cartId: string;
|
|
8
|
-
countryCode:
|
|
9
|
-
currencyCode:
|
|
9
|
+
countryCode: CountryCode;
|
|
10
|
+
currencyCode: CurrencyCode;
|
|
10
11
|
customerId: string;
|
|
11
12
|
dropinRef: MutableRefObject<Dropin | null>;
|
|
12
13
|
environment: 'test' | 'live' | 'live-us' | 'live-au' | 'live-apse' | 'live-in';
|
|
@@ -10,6 +10,7 @@ import { Select } from '../../../../forms/select/select.js';
|
|
|
10
10
|
import { TextField } from '../../../../forms/text-field/text-field.js';
|
|
11
11
|
import { InfoIconTooltip } from '../../../../info-icon-tooltip/info-icon-tooltip.js';
|
|
12
12
|
import { FormattedMessage } from '../../../../intl/formatted-message.js';
|
|
13
|
+
import { isCountryCode } from '../../../../intl/types.js';
|
|
13
14
|
import { useFormattedMessage } from '../../../../intl/use-formatted-message.js';
|
|
14
15
|
import { logger } from '../../../../logging/logger.js';
|
|
15
16
|
import { useInvalidateCurrentCart } from '../../../../shared/api/storefront/hooks/cart/use-invalidate-current-cart.js';
|
|
@@ -18,7 +19,7 @@ import { usePlaceOrder } from '../../../../shared/api/storefront/hooks/cart/use-
|
|
|
18
19
|
import { useInvalidateAdyen } from '../../../../shared/api/storefront/hooks/payment/use-invalidate-adyen.js';
|
|
19
20
|
import { validateVATNumber } from '../../../../shared/api/storefront/services/finance-service.js';
|
|
20
21
|
import { useDataLayer } from '../../../../shared/ga/use-data-layer.js';
|
|
21
|
-
import {
|
|
22
|
+
import { getCurrencyCodeBySymbol } from '../../../../shared/model/currency.js';
|
|
22
23
|
import { environment } from '../../../../shared/utils/environment.js';
|
|
23
24
|
import { BillingAndInvoiceInformation } from '../../components/billing-and-invoice-information.js';
|
|
24
25
|
import { useHasReturnedFromAdyen } from '../hooks/use-has-returned-from-adyen.js';
|
|
@@ -42,8 +43,10 @@ function Payment({ atp, cart: _cart, form, isProcessing, onError: _onError, onPa
|
|
|
42
43
|
const [asSoonAsPossible, setAsSoonAsPossible] = useState(!hasAtp);
|
|
43
44
|
const [deliveryDate, setDeliveryDate] = useState(cart.requestedDeliveryDateDisplay?.toString() || '');
|
|
44
45
|
const [selectedPaymentMethod, setSelectedPaymentMethod] = useState(cart.paymentOptions?.paymentMethods?.[0]?.name || 'ADY');
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
if (!isCountryCode(_cart.billTo?.country?.abbreviation))
|
|
47
|
+
throw new Error(`Country code not found for cart with country abbreviation: ${_cart.billTo?.country?.abbreviation}`);
|
|
48
|
+
const countryCode = _cart.billTo.country.abbreviation;
|
|
49
|
+
const currencyCode = getCurrencyCodeBySymbol(cart.currencySymbol);
|
|
47
50
|
const lastVATNumber = useRef(cart.customerVatNumber);
|
|
48
51
|
if (!currencyCode)
|
|
49
52
|
throw new Error(`Currency code not found for cart with currency symbol: ${cart.currencySymbol}`);
|
|
@@ -152,7 +155,7 @@ function Payment({ atp, cart: _cart, form, isProcessing, onError: _onError, onPa
|
|
|
152
155
|
event: 'purchase',
|
|
153
156
|
},
|
|
154
157
|
}), {
|
|
155
|
-
currency:
|
|
158
|
+
currency: getCurrencyCodeBySymbol(cart.currencySymbol),
|
|
156
159
|
event: 'transactionComplete',
|
|
157
160
|
transactionAffiliation: cart.billTo?.companyName,
|
|
158
161
|
transactionId: cart.orderNumber,
|
|
@@ -172,10 +175,16 @@ function Payment({ atp, cart: _cart, form, isProcessing, onError: _onError, onPa
|
|
|
172
175
|
const formData = new FormData(e.currentTarget);
|
|
173
176
|
const cart = cartRef.current;
|
|
174
177
|
setValidationErrors(prev => prev); // NOTE: This makes sure the form is revalidated on submit
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
cart.customerVatNumber = formData.get('customerVatNumber')?.toString();
|
|
179
|
+
cart.poNumber = formData.get('poNumber')?.toString();
|
|
180
|
+
cart.properties = {
|
|
181
|
+
...cart.properties,
|
|
182
|
+
industry: formData.get('industry')?.toString() || '',
|
|
183
|
+
};
|
|
184
|
+
cart.requestedDeliveryDate = formData.get('deliveryDate')?.toString();
|
|
185
|
+
if (cart.customerVatNumber &&
|
|
186
|
+
lastVATNumber.current !== cart.customerVatNumber &&
|
|
187
|
+
!(await validateVAT(cart.customerVatNumber)))
|
|
179
188
|
return;
|
|
180
189
|
if (Object.keys(validationErrors).length > 0)
|
|
181
190
|
return;
|
|
@@ -192,16 +201,7 @@ function Payment({ atp, cart: _cart, form, isProcessing, onError: _onError, onPa
|
|
|
192
201
|
try {
|
|
193
202
|
try {
|
|
194
203
|
cartRef.current = await patchCart({
|
|
195
|
-
cart
|
|
196
|
-
...cart,
|
|
197
|
-
customerVatNumber: formData.get('customerVatNumber')?.toString(),
|
|
198
|
-
poNumber: formData.get('poNumber')?.toString(),
|
|
199
|
-
properties: {
|
|
200
|
-
...cart.properties,
|
|
201
|
-
industry: formData.get('industry')?.toString() || '',
|
|
202
|
-
},
|
|
203
|
-
requestedDeliveryDate: formData.get('deliveryDate')?.toString(),
|
|
204
|
-
},
|
|
204
|
+
cart,
|
|
205
205
|
forceRecalculation: false,
|
|
206
206
|
});
|
|
207
207
|
if (cartRef.current.properties.customerVatNumberStatus === 'invalid') {
|
|
@@ -236,12 +236,12 @@ function Payment({ atp, cart: _cart, form, isProcessing, onError: _onError, onPa
|
|
|
236
236
|
const cart = cartRef.current;
|
|
237
237
|
try {
|
|
238
238
|
onProcessing(true);
|
|
239
|
-
await placeOrder({ cart });
|
|
239
|
+
cartRef.current = await placeOrder({ cart });
|
|
240
240
|
onPlaceOrderCompleted({
|
|
241
|
-
cart,
|
|
242
|
-
payment_type:
|
|
241
|
+
cart: cartRef.current,
|
|
242
|
+
payment_type: cartRef.current.paymentMethod?.name || '',
|
|
243
243
|
});
|
|
244
|
-
return onPaymentComplete({ cartId:
|
|
244
|
+
return onPaymentComplete({ cartId: cartRef.current.trackId });
|
|
245
245
|
}
|
|
246
246
|
catch (error) {
|
|
247
247
|
logger.error(error);
|
|
@@ -6,6 +6,7 @@ import { CartTotalsSummary } from '../../../cart-totals/cart-totals-summary.js';
|
|
|
6
6
|
import { FormattedMessage } from '../../../intl/formatted-message.js';
|
|
7
7
|
import { useFormattedMessage } from '../../../intl/use-formatted-message.js';
|
|
8
8
|
import { OrderLineList } from '../../../lists/orderline-list/orderline-list.js';
|
|
9
|
+
import { getCurrencyCodeBySymbol } from '../../../shared/model/currency.js';
|
|
9
10
|
import { Page } from '../../components/page/page.js';
|
|
10
11
|
import { PATHS } from '../../paths.js';
|
|
11
12
|
import { CheckoutPageLayout } from '../layouts/checkout-page-layout/checkout-page-layout.js';
|
|
@@ -15,6 +16,9 @@ import { Payment } from './components/payment.js';
|
|
|
15
16
|
|
|
16
17
|
function PaymentPageContent({ atp, cart, formId, hasAtp, isProcessing, isValidatingVAT, onPaymentComplete, setIsProcessing, setIsValidatingVAT, }) {
|
|
17
18
|
const t = useFormattedMessage();
|
|
19
|
+
const currencyCode = getCurrencyCodeBySymbol(cart.currencySymbol);
|
|
20
|
+
if (!currencyCode)
|
|
21
|
+
throw new Error(`Currency code not found for symbol ${cart.currencySymbol}`);
|
|
18
22
|
return (jsx(Page, { breadcrumb: [
|
|
19
23
|
{ href: PATHS.HOME, label: t('Home') },
|
|
20
24
|
{
|
|
@@ -23,8 +27,8 @@ function PaymentPageContent({ atp, cart, formId, hasAtp, isProcessing, isValidat
|
|
|
23
27
|
},
|
|
24
28
|
], title: t('Review and payment'), children: jsxs(CheckoutPageLayout, { actions: {
|
|
25
29
|
primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutReviewAndSubmit_placeOrder", form: formId, isDisabled: isProcessing, isLoading: isProcessing ? (jsx(FormattedMessage, { id: "Processing" })) : isValidatingVAT ? (jsx(FormattedMessage, { id: "Validating" })) : (false), type: "submit", children: jsx(FormattedMessage, { id: "Pay" }) })),
|
|
26
|
-
}, mobileSummary: jsx(CartTotalsSummary, { totalAmount: cart.
|
|
27
|
-
cart.paymentMethod?.name === 'PBI', shippingCost: cart.
|
|
30
|
+
}, mobileSummary: jsx(CartTotalsSummary, { currencyCode: currencyCode, totalAmount: cart.orderGrandTotal }), overview: jsx(CartTotals, { currencyCode: currencyCode, deliveryDate: hasAtp ? undefined : cart.requestedDeliveryDate, fulfillmentMethod: cart.fulfillmentMethod, isPayByInvoice: (cart.paymentOptions?.paymentMethods?.length || 1) <= 1 &&
|
|
31
|
+
cart.paymentMethod?.name === 'PBI', shippingCost: cart.shippingAndHandling, subtotal: cart.orderSubTotal, tax: cart.totalTax, total: cart.orderGrandTotal, 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: formId, isProcessing: isProcessing, onPaymentComplete: onPaymentComplete, onProcessing: setIsProcessing, onValidatingVAT: setIsValidatingVAT }) }) }), 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: {
|
|
28
32
|
fit: 'contain',
|
|
29
33
|
image: {
|
|
30
34
|
'1': cartLine.smallImagePath,
|
|
@@ -34,6 +38,7 @@ function PaymentPageContent({ atp, cart, formId, hasAtp, isProcessing, isValidat
|
|
|
34
38
|
},
|
|
35
39
|
title: cartLine.altText,
|
|
36
40
|
}, isReadonly: true, price: {
|
|
41
|
+
currencyCode,
|
|
37
42
|
originalTotalPrice: cartLine.pricing?.extendedUnitNetPrice || 0,
|
|
38
43
|
pricePerUnit: cartLine.pricing?.unitNetPrice || 0,
|
|
39
44
|
totalPrice: cartLine.pricing?.extendedUnitNetPrice || 0,
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import { PaymentAmountExtended } from '@adyen/adyen-web/dist/types/types';
|
|
2
|
-
|
|
2
|
+
import { CountryCode } from '../../../../intl/types';
|
|
3
|
+
export declare function parseAmount(amount: string | number, countryCode: CountryCode): PaymentAmountExtended;
|
|
@@ -5,6 +5,7 @@ import { CartTotalsSummary } from '../../../cart-totals/cart-totals-summary.js';
|
|
|
5
5
|
import { Select } from '../../../forms/select/select.js';
|
|
6
6
|
import { FormattedMessage } from '../../../intl/formatted-message.js';
|
|
7
7
|
import { useFormattedMessage } from '../../../intl/use-formatted-message.js';
|
|
8
|
+
import { getCurrencyCodeBySymbol } from '../../../shared/model/currency.js';
|
|
8
9
|
import { Page } from '../../components/page/page.js';
|
|
9
10
|
import { PATHS } from '../../paths.js';
|
|
10
11
|
import { CheckoutPageLayout } from '../layouts/checkout-page-layout/checkout-page-layout.js';
|
|
@@ -20,6 +21,9 @@ function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulf
|
|
|
20
21
|
[method]: t(`fulfillmentMethod.${method}`),
|
|
21
22
|
}), {});
|
|
22
23
|
const hasBillToAddress = Boolean(cart.billTo?.address1);
|
|
24
|
+
const currencyCode = getCurrencyCodeBySymbol(cart.currencySymbol);
|
|
25
|
+
if (!currencyCode)
|
|
26
|
+
throw new Error(`Currency code not found for symbol ${cart.currencySymbol}`);
|
|
23
27
|
return (jsx(Page, { breadcrumb: [
|
|
24
28
|
{ href: PATHS.HOME, label: t('Home') },
|
|
25
29
|
{
|
|
@@ -28,9 +32,9 @@ function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulf
|
|
|
28
32
|
},
|
|
29
33
|
], title: t('Shipping details'), children: jsxs(CheckoutPageLayout, { actions: {
|
|
30
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" }) })),
|
|
31
|
-
}, mobileSummary: jsx(CartTotalsSummary, { totalAmount: cart.
|
|
35
|
+
}, mobileSummary: jsx(CartTotalsSummary, { currencyCode: currencyCode, totalAmount: cart.orderGrandTotal }), overview: jsx(CartTotals, { currencyCode: currencyCode, fulfillmentMethod: fulfillmentMethods && fulfillmentMethods.length === 1
|
|
32
36
|
? cart.fulfillmentMethod
|
|
33
|
-
: undefined, shippingCost: cart.
|
|
37
|
+
: undefined, shippingCost: cart.shippingAndHandling, subtotal: cart.orderSubTotal, tax: cart.totalTax, total: cart.orderGrandTotal, 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 && !isGuest ? readOnlyAddress : editAddress] }), Boolean(errorPatchBillingAddress) && (jsx("div", { className: styles['error-message'], children: jsx(FormattedMessage, { id: "An unexpected error occured" }) }))] }) }));
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
export { ShippingPageContent };
|
|
@@ -4,7 +4,7 @@ import { ConnectedFavoriteButton } from '../../../../../buttons/favorite/connect
|
|
|
4
4
|
import { Accordion } from '../../../../../collapsables/accordion/accordion.js';
|
|
5
5
|
import { AccordionItem } from '../../../../../collapsables/accordion/accordion-item.js';
|
|
6
6
|
import { ShowAll } from '../../../../../collapsables/show-all/show-all.js';
|
|
7
|
-
import {
|
|
7
|
+
import { Price } from '../../../../../display/price/price.js';
|
|
8
8
|
import { ProductSku } from '../../../../../display/product-sku/product-sku.js';
|
|
9
9
|
import { FormattedMessage } from '../../../../../intl/formatted-message.js';
|
|
10
10
|
import { DownloadDocumentList } from '../../../../../lists/download-document-list/download-document-list.js';
|
|
@@ -15,7 +15,7 @@ import styles from './product-details-panel.module.css.js';
|
|
|
15
15
|
|
|
16
16
|
function ProductDetailsPanel({ priceComponent, product, }) {
|
|
17
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", tag: "h1", children: product.productTitle }), jsx(ProductSku, { sku: product.productNumber })] }), jsxs("div", { className: styles['price-action-container'], children: [priceComponent || (jsx(
|
|
18
|
+
return (jsxs("div", { className: styles['product-details-panel'], children: [jsxs("div", { className: styles.heading, children: [jsx(Heading, { italic: true, size: "xs", tag: "h1", children: product.productTitle }), jsx(ProductSku, { sku: product.productNumber })] }), jsxs("div", { className: styles['price-action-container'], children: [priceComponent || (jsx(Price, { className: styles.price, currencyCode: product.currencyCode, "data-test": "productPrice_unitNetPrice", isVatIncluded: product.isVatIncluded, originalPrice: product.originalPrice, price: product.price, variant: "sonic" })), jsxs("div", { className: styles['action-container'], children: [product.canAddToCart && (jsx(ConnectedAddToCartButton, { onAddToCart: ({ cartLine }) => {
|
|
19
19
|
sendAddToCartFromProductDetailsPageEvent({
|
|
20
20
|
cartLine,
|
|
21
21
|
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var styles = {"product-details-panel":"product-details-panel-module-MXfPm","heading":"product-details-panel-module-rtZYR","price-action-container":"product-details-panel-module-wHZCr","action-container":"product-details-panel-module-QLafW","description":"product-details-panel-module-9L-Nm","feature-list":"product-details-panel-module-NC2nx"};
|
|
1
|
+
var styles = {"product-details-panel":"product-details-panel-module-MXfPm","heading":"product-details-panel-module-rtZYR","price-action-container":"product-details-panel-module-wHZCr","price":"product-details-panel-module-dI2JL","action-container":"product-details-panel-module-QLafW","description":"product-details-panel-module-9L-Nm","feature-list":"product-details-panel-module-NC2nx"};
|
|
2
2
|
|
|
3
3
|
export { styles as default };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CurrencyCode } from '../../../../intl/types';
|
|
1
2
|
export interface PageModel {
|
|
2
3
|
alternateLanguageUrls: {
|
|
3
4
|
[key: string]: string;
|
|
@@ -64,6 +65,7 @@ interface ResponsiveImage {
|
|
|
64
65
|
sm: DPRSrcSet;
|
|
65
66
|
}
|
|
66
67
|
interface ProductPrice {
|
|
68
|
+
currencyCode: CurrencyCode;
|
|
67
69
|
isVatIncluded: boolean;
|
|
68
70
|
originalPrice: number;
|
|
69
71
|
price: number;
|
|
@@ -105,6 +107,7 @@ export interface ProductDetails {
|
|
|
105
107
|
openGraphUrl: string;
|
|
106
108
|
pageTitle: string;
|
|
107
109
|
};
|
|
110
|
+
currencyCode: CurrencyCode;
|
|
108
111
|
documents: Array<{
|
|
109
112
|
description: string;
|
|
110
113
|
documentType: string;
|
|
@@ -4,7 +4,7 @@ export declare const usePlaceOrder: () => {
|
|
|
4
4
|
isLoading: boolean;
|
|
5
5
|
isSuccess: boolean;
|
|
6
6
|
mutate: (args_0: {
|
|
7
|
-
cart: import("../../model/storefront.model").
|
|
7
|
+
cart: import("../../model/storefront.model").PatchCartModel;
|
|
8
8
|
isPending?: boolean;
|
|
9
9
|
}) => Promise<import("../../model/storefront.model").CartModel>;
|
|
10
10
|
};
|
|
@@ -29,7 +29,7 @@ export declare function addProductToCurrentCart(productOrderData: AddProductToCu
|
|
|
29
29
|
export declare function fetchCurrentCartProductAtp(): Promise<ProductAtp[]>;
|
|
30
30
|
export declare function fetchCurrentCheckoutAtp(): Promise<CheckoutAtpEntry[]>;
|
|
31
31
|
export declare function placeOrder({ cart, isPending, }: {
|
|
32
|
-
cart:
|
|
32
|
+
cart: PatchCartModel;
|
|
33
33
|
isPending?: boolean;
|
|
34
34
|
}): Promise<CartModel>;
|
|
35
35
|
export declare function saveCartForLater({ cart }: {
|
|
@@ -111,7 +111,7 @@ async function placeOrder({ cart, isPending, }) {
|
|
|
111
111
|
'Content-Type': 'application/json',
|
|
112
112
|
},
|
|
113
113
|
method: 'PATCH',
|
|
114
|
-
url: `${config.BFF_API_URL}/api/v1/carts/current`,
|
|
114
|
+
url: `${config.BFF_API_URL}/api/v1/carts/current?forceRecalculation=false`,
|
|
115
115
|
});
|
|
116
116
|
return body;
|
|
117
117
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { getCurrencyCodeBySymbol } from '../model/currency.js';
|
|
3
3
|
import { dataLayer } from './data-layer.js';
|
|
4
4
|
import { useGoogleAnalyticsProvider } from './google-analytics-provider.js';
|
|
5
5
|
import { isGAEvent } from './types.js';
|
|
@@ -13,7 +13,7 @@ function useDataLayer(eventOrArgs) {
|
|
|
13
13
|
ecommerce: {
|
|
14
14
|
...event.ecommerce,
|
|
15
15
|
currency: event.ecommerce?.currency ??
|
|
16
|
-
|
|
16
|
+
getCurrencyCodeBySymbol(cart.currencySymbol),
|
|
17
17
|
customer: event.ecommerce?.customer ?? customerNumber,
|
|
18
18
|
items: cart.cartLines?.map(cartLine => ({
|
|
19
19
|
item_id: cartLine.erpNumber,
|
|
@@ -35,7 +35,7 @@ function useDataLayer(eventOrArgs) {
|
|
|
35
35
|
ecommerce: {
|
|
36
36
|
...event.ecommerce,
|
|
37
37
|
currency: event.ecommerce?.currency ??
|
|
38
|
-
|
|
38
|
+
getCurrencyCodeBySymbol(product.unitListPriceDisplay[0] || ''),
|
|
39
39
|
customer: event.ecommerce?.customer ?? customerNumber,
|
|
40
40
|
items: [
|
|
41
41
|
{
|
|
@@ -54,7 +54,7 @@ function useDataLayer(eventOrArgs) {
|
|
|
54
54
|
ecommerce: {
|
|
55
55
|
...event.ecommerce,
|
|
56
56
|
currency: event.ecommerce?.currency ??
|
|
57
|
-
|
|
57
|
+
getCurrencyCodeBySymbol(cartLine.pricing?.actualPriceDisplay[0] || ''),
|
|
58
58
|
customer: event.ecommerce?.customer ?? customerNumber,
|
|
59
59
|
items: [
|
|
60
60
|
{
|
|
@@ -1 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import { CurrencyCode } from '../../intl/types';
|
|
2
|
+
export type Currency = {
|
|
3
|
+
code: CurrencyCode;
|
|
4
|
+
name: string;
|
|
5
|
+
symbol: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const currencies: Currency[];
|
|
8
|
+
export declare function getCurrencyCodeBySymbol(symbol: string): CurrencyCode | undefined;
|
|
@@ -1,31 +1,29 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
'₽': 'RUB', // Russian Ruble
|
|
29
|
-
};
|
|
1
|
+
const currencies = [
|
|
2
|
+
{
|
|
3
|
+
code: 'EUR',
|
|
4
|
+
name: 'Euro',
|
|
5
|
+
symbol: '€',
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
code: 'USD',
|
|
9
|
+
name: 'US dollar',
|
|
10
|
+
symbol: '$',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
code: 'GBP',
|
|
14
|
+
name: 'Pound sterling',
|
|
15
|
+
symbol: '£',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
code: 'CHF',
|
|
19
|
+
name: 'Swiss franc',
|
|
20
|
+
symbol: 'CHF',
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
// This is a helper object to quickly find a currency code by its symbol.
|
|
24
|
+
const currencyCodeBySymbol = Object.fromEntries(currencies.map(currency => [currency.symbol, currency.code]));
|
|
25
|
+
function getCurrencyCodeBySymbol(symbol) {
|
|
26
|
+
return currencyCodeBySymbol[symbol];
|
|
27
|
+
}
|
|
30
28
|
|
|
31
|
-
export {
|
|
29
|
+
export { currencies, getCurrencyCodeBySymbol };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AlgoliaProductHit, AlgoliaPromoHit } from '../../algolia/algolia-hit-type';
|
|
2
|
+
import { CurrencyCode } from '../../intl/types';
|
|
2
3
|
import { ImageType } from './image';
|
|
3
4
|
export declare function transformAlgoliaPromoHitToPromoHit(algoliaPromoHit: AlgoliaPromoHit): PromoHit;
|
|
4
5
|
export declare function transformAlgoliaProductHitToProductHit(algoliaProductHit: AlgoliaProductHit): ProductHit;
|
|
@@ -11,6 +12,7 @@ export interface PromoHit {
|
|
|
11
12
|
type: 'promo';
|
|
12
13
|
}
|
|
13
14
|
export interface ProductHit {
|
|
15
|
+
currencyCode: CurrencyCode;
|
|
14
16
|
hit: AlgoliaProductHit;
|
|
15
17
|
id: string;
|
|
16
18
|
image: ImageType;
|
package/dist/shared/model/hit.js
CHANGED
|
@@ -10,6 +10,7 @@ function transformAlgoliaPromoHitToPromoHit(algoliaPromoHit) {
|
|
|
10
10
|
}
|
|
11
11
|
function transformAlgoliaProductHitToProductHit(algoliaProductHit) {
|
|
12
12
|
return {
|
|
13
|
+
currencyCode: algoliaProductHit.currencyCode,
|
|
13
14
|
hit: algoliaProductHit,
|
|
14
15
|
id: algoliaProductHit.id,
|
|
15
16
|
image: {
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { CurrencyCode } from '../../intl/types';
|
|
1
2
|
export interface ProductPriceType {
|
|
3
|
+
currencyCode: CurrencyCode;
|
|
2
4
|
isVatIncluded: boolean;
|
|
3
|
-
originalPrice
|
|
5
|
+
originalPrice?: number;
|
|
4
6
|
price: number;
|
|
5
7
|
}
|
|
6
8
|
export interface ProductTotalPriceType {
|
|
7
|
-
|
|
9
|
+
currencyCode: CurrencyCode;
|
|
10
|
+
originalTotalPrice?: number;
|
|
8
11
|
pricePerUnit?: number;
|
|
9
12
|
totalPrice: number;
|
|
10
13
|
}
|