@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.
Files changed (71) hide show
  1. package/dist/address-info-display/address-info-display.js +1 -2
  2. package/dist/algolia/algolia-hit-type.d.ts +2 -0
  3. package/dist/algolia/use-algolia-insights.js +3 -3
  4. package/dist/cards/orderline-card/orderline-card.js +2 -2
  5. package/dist/cards/orderline-card/orderline-card.module.css.js +1 -1
  6. package/dist/cards/product-card/product-card.js +3 -2
  7. package/dist/cards/product-card/product-card.module.css.js +1 -1
  8. package/dist/cart-totals/cart-totals-summary.d.ts +4 -2
  9. package/dist/cart-totals/cart-totals-summary.js +3 -2
  10. package/dist/cart-totals/cart-totals.d.ts +7 -5
  11. package/dist/cart-totals/cart-totals.js +3 -2
  12. package/dist/delivery-time/delivery-time.js +2 -2
  13. package/dist/display/price/price.d.ts +18 -0
  14. package/dist/display/price/price.js +30 -0
  15. package/dist/display/price/price.module.css.js +3 -0
  16. package/dist/display/product-sku/product-sku.d.ts +2 -1
  17. package/dist/display/product-sku/product-sku.js +3 -2
  18. package/dist/exports.d.ts +4 -2
  19. package/dist/global-search/search-result-panel/sections/with-results.js +1 -0
  20. package/dist/index.js +8 -6
  21. package/dist/intl/intl-context.d.ts +10 -4
  22. package/dist/intl/intl-context.js +4 -0
  23. package/dist/intl/intl-provider.d.ts +4 -2
  24. package/dist/intl/intl-provider.js +18 -4
  25. package/dist/intl/missing-translation-provider.js +3 -2
  26. package/dist/intl/translation-id.d.ts +1 -1
  27. package/dist/intl/types.d.ts +2 -0
  28. package/dist/intl/types.js +6 -1
  29. package/dist/intl/use-country-code.d.ts +3 -0
  30. package/dist/intl/use-country-code.js +15 -0
  31. package/dist/intl/use-culture-code.d.ts +2 -1
  32. package/dist/intl/use-culture-code.js +5 -4
  33. package/dist/intl/use-currency-code.d.ts +4 -0
  34. package/dist/intl/use-currency-code.js +15 -0
  35. package/dist/intl/use-formatted-message.js +2 -3
  36. package/dist/intl/use-intl.d.ts +1 -0
  37. package/dist/intl/use-intl.js +9 -0
  38. package/dist/intl/use-language-code.js +2 -3
  39. package/dist/pages/checkout/cart-page/cart-page.js +6 -1
  40. package/dist/pages/checkout/order-confirmation-page/order-confirmation-page-content.js +6 -1
  41. package/dist/pages/checkout/payment-page/components/adyen-payment.d.ts +3 -2
  42. package/dist/pages/checkout/payment-page/components/payment.js +22 -22
  43. package/dist/pages/checkout/payment-page/payment-page-content.js +7 -2
  44. package/dist/pages/checkout/payment-page/utils/parse-amount.d.ts +2 -1
  45. package/dist/pages/checkout/shipping-page/shipping-page-content.js +6 -2
  46. package/dist/pages/product/product-details-page/components/product-details-panel/product-details-panel.js +2 -2
  47. package/dist/pages/product/product-details-page/components/product-details-panel/product-details-panel.module.css.js +1 -1
  48. package/dist/pages/product/product-listing-page/product-listing-product-overview/product-listing-product-overview.js +1 -0
  49. package/dist/pages/product/search-result-page/search-result-product-overview/search-result-product-overview.js +1 -0
  50. package/dist/shared/api/bff/model/bff.model.d.ts +3 -0
  51. package/dist/shared/api/storefront/hooks/cart/use-place-order.d.ts +1 -1
  52. package/dist/shared/api/storefront/services/cart-service.d.ts +1 -1
  53. package/dist/shared/api/storefront/services/cart-service.js +1 -1
  54. package/dist/shared/ga/use-data-layer.js +4 -4
  55. package/dist/shared/model/currency.d.ts +8 -1
  56. package/dist/shared/model/currency.js +28 -30
  57. package/dist/shared/model/hit.d.ts +2 -0
  58. package/dist/shared/model/hit.js +1 -0
  59. package/dist/shared/model/price.d.ts +5 -2
  60. package/dist/shared/utils/price.d.ts +19 -5
  61. package/dist/shared/utils/price.js +36 -7
  62. package/dist/shared/utils/string.d.ts +0 -1
  63. package/dist/shared/utils/string.js +1 -4
  64. package/dist/styles.css +467 -278
  65. package/package.json +1 -1
  66. package/dist/display/product-price/product-price.d.ts +0 -7
  67. package/dist/display/product-price/product-price.js +0 -19
  68. package/dist/display/product-price/product-price.module.css.js +0 -3
  69. package/dist/display/product-price/product-total-price.d.ts +0 -7
  70. package/dist/display/product-price/product-total-price.js +0 -16
  71. package/dist/display/product-price/product-total-price.module.css.js +0 -3
@@ -0,0 +1,4 @@
1
+ import { UpdateCurrencyCode } from './intl-context';
2
+ import { CurrencyCode } from './types';
3
+ export declare function useCurrencyCode(): CurrencyCode;
4
+ export declare function useUpdateCurrencyCode(): UpdateCurrencyCode;
@@ -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 { useContext } from 'react';
3
- import { IntlContext } from './intl-context.js';
2
+ import { useIntl } from './use-intl.js';
4
3
 
5
4
  function useFormattedMessage() {
6
- const { formattedMessage } = useContext(IntlContext);
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;
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import { useContext } from 'react';
3
+ import { IntlContext } from './intl-context.js';
4
+
5
+ function useIntl() {
6
+ return useContext(IntlContext);
7
+ }
8
+
9
+ export { useIntl };
@@ -1,10 +1,9 @@
1
1
  "use client";
2
- import { useContext } from 'react';
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 } = useContext(IntlContext);
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.orderGrandTotalDisplay }), overview: jsx(CartTotals, { shippingCost: currentCart.shippingAndHandlingDisplay, subtotal: currentCart.orderSubTotalDisplay, tax: currentCart.totalTaxDisplay, total: currentCart.orderGrandTotalDisplay, 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: {
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.shippingAndHandlingDisplay, subtotal: cart.orderSubTotalDisplay, tax: cart.totalTaxDisplay, total: cart.orderGrandTotalDisplay, 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: {
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: string;
9
- currencyCode: string;
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 { currencySymbolToISO } from '../../../../shared/model/currency.js';
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
- const countryCode = _cart.billTo?.country?.abbreviation;
46
- const currencyCode = currencySymbolToISO[cart.currencySymbol];
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: currencySymbolToISO[cart.currencySymbol],
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
- const customerVatNumber = formData.get('customerVatNumber')?.toString();
176
- if (customerVatNumber &&
177
- lastVATNumber.current !== customerVatNumber &&
178
- !(await validateVAT(customerVatNumber)))
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: cart.paymentMethod?.name || '',
241
+ cart: cartRef.current,
242
+ payment_type: cartRef.current.paymentMethod?.name || '',
243
243
  });
244
- return onPaymentComplete({ cartId: cart.trackId });
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.orderGrandTotalDisplay }), overview: jsx(CartTotals, { deliveryDate: hasAtp ? undefined : cart.requestedDeliveryDate, fulfillmentMethod: cart.fulfillmentMethod, isPayByInvoice: (cart.paymentOptions?.paymentMethods?.length || 1) <= 1 &&
27
- 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: 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: {
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
- export declare function parseAmount(amount: string | number, countryCode: string): PaymentAmountExtended;
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.orderGrandTotalDisplay }), overview: jsx(CartTotals, { fulfillmentMethod: fulfillmentMethods && fulfillmentMethods.length === 1
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.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 && !isGuest ? readOnlyAddress : editAddress] }), Boolean(errorPatchBillingAddress) && (jsx("div", { className: styles['error-message'], children: jsx(FormattedMessage, { id: "An unexpected error occured" }) }))] }) }));
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 { ProductPrice } from '../../../../../display/product-price/product-price.js';
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(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 }) => {
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 };
@@ -19,6 +19,7 @@ function ProductHitCard({ hit }) {
19
19
  objectId: hit.objectId,
20
20
  position: hit.position,
21
21
  }), price: {
22
+ currencyCode: hit.currencyCode,
22
23
  isVatIncluded: hit.isVatIncluded,
23
24
  originalPrice: hit.originalPrice,
24
25
  price: hit.price,
@@ -21,6 +21,7 @@ function ProductHitCard({ hit }) {
21
21
  objectId: hit.objectId,
22
22
  position: hit.position,
23
23
  }), price: {
24
+ currencyCode: hit.currencyCode,
24
25
  isVatIncluded: hit.isVatIncluded,
25
26
  originalPrice: hit.originalPrice,
26
27
  price: hit.price,
@@ -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").CartModel;
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: CartModel;
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 { currencySymbolToISO } from '../model/currency.js';
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
- currencySymbolToISO[cart.currencySymbol],
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
- currencySymbolToISO[product.unitListPriceDisplay[0] || ''],
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
- currencySymbolToISO[cartLine.pricing?.actualPriceDisplay[0] || ''],
57
+ getCurrencyCodeBySymbol(cartLine.pricing?.actualPriceDisplay[0] || ''),
58
58
  customer: event.ecommerce?.customer ?? customerNumber,
59
59
  items: [
60
60
  {
@@ -1 +1,8 @@
1
- export declare const currencySymbolToISO: Record<string, string>;
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 currencySymbolToISO = {
2
- '': 'EUR', // Euro
3
- $: 'USD', // US Dollar
4
- 'Bs.': 'VES', // Venezuelan Bolívar Soberano
5
- CHF: 'CHF', // Swiss Franc
6
- Ft: 'HUF', // Hungarian Forint
7
- Kč: 'CZK', // Czech Koruna
8
- R: 'ZAR', // South African Rand
9
- kr: 'SEK', // Swedish Krona (and others like DKK, NOK depending on context)
10
- lei: 'RON', // Romanian Leu
11
- zł: 'PLN', // Polish Zloty
12
- '£': 'GBP', // British Pound
13
- '¥': 'JPY', // Japanese Yen
14
- '฿': 'THB', // Thai Baht
15
- '₡': 'CRC', // Costa Rican Colón
16
- '₦': 'NGN', // Nigerian Naira
17
- '₩': 'KRW', // South Korean Won
18
- '₪': 'ILS', // Israeli Shekel
19
- '₫': 'VND', // Vietnamese Dong
20
- '€': 'EUR', // Euro
21
- '₮': 'MNT', // Mongolian Tögrög
22
- '₱': 'PHP', // Philippine Peso
23
- '₲': 'PYG', // Paraguayan Guarani
24
- '₴': 'UAH', // Ukrainian Hryvnia
25
- '₵': 'GHS', // Ghanaian Cedi
26
- '₹': 'INR', // Indian Rupee
27
- '₺': 'TRY', // Turkish Lira
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 { currencySymbolToISO };
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;
@@ -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: number;
5
+ originalPrice?: number;
4
6
  price: number;
5
7
  }
6
8
  export interface ProductTotalPriceType {
7
- originalTotalPrice: number;
9
+ currencyCode: CurrencyCode;
10
+ originalTotalPrice?: number;
8
11
  pricePerUnit?: number;
9
12
  totalPrice: number;
10
13
  }