@sonic-equipment/ui 0.0.111 → 0.0.113

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 (42) hide show
  1. package/dist/index.d.ts +30 -8
  2. package/dist/index.js +132 -52
  3. package/dist/src/buttons/print-button/print-button.d.ts +1 -0
  4. package/dist/src/buttons/print-button/print-button.stories.d.ts +13 -0
  5. package/dist/src/cards/orderline-card/connected-orderline-card.d.ts +6 -0
  6. package/dist/src/cards/orderline-card/connected-remove-button.d.ts +5 -0
  7. package/dist/src/cards/orderline-card/orderline-card.d.ts +25 -0
  8. package/dist/src/cards/orderline-card/orderline-card.stories.d.ts +46 -0
  9. package/dist/src/cart-totals/cart-totals.d.ts +12 -0
  10. package/dist/src/cart-totals/cart-totals.stories.d.ts +16 -0
  11. package/dist/src/country-selector/country-selector-dialog/country-selector-dialog.d.ts +3 -1
  12. package/dist/src/delivery-time/delivery-time.d.ts +5 -0
  13. package/dist/src/delivery-time/delivery-time.stories.d.ts +13 -0
  14. package/dist/src/display/product-price/product-price.d.ts +2 -1
  15. package/dist/src/display/product-price/product-total-price.d.ts +7 -0
  16. package/dist/src/display/product-price/product-total-price.stories.d.ts +14 -0
  17. package/dist/src/icons/solid/solid-event-icon.d.ts +1 -0
  18. package/dist/src/icons/solid/solid-news-icon.d.ts +1 -0
  19. package/dist/src/icons/solid/solid-sale-icon.d.ts +1 -0
  20. package/dist/src/intl/translation-id.d.ts +1 -1
  21. package/dist/src/intl/use-format-message.d.ts +11 -5
  22. package/dist/src/lists/orderline-list/orderline-list.d.ts +7 -0
  23. package/dist/src/lists/orderline-list/orderline-list.stories.d.ts +15 -0
  24. package/dist/src/modals/confirmation/confirmation-dialog.d.ts +10 -0
  25. package/dist/src/modals/confirmation/confirmation-dialog.stories.d.ts +19 -0
  26. package/dist/src/modals/dialog/dialog.d.ts +10 -5
  27. package/dist/src/modals/modal/modal.d.ts +1 -1
  28. package/dist/src/notifications/announcements/announcement.d.ts +1 -1
  29. package/dist/src/notifications/announcements/announcement.stories.d.ts +10 -6
  30. package/dist/src/shared/api/bff/model/announcement.model.d.ts +1 -0
  31. package/dist/src/shared/api/bff/services/bff-service.d.ts +10 -0
  32. package/dist/src/shared/feature-flags/use-feature-flags.d.ts +0 -1
  33. package/dist/src/shared/model/announcement.d.ts +6 -3
  34. package/dist/src/shared/model/price.d.ts +5 -0
  35. package/dist/src/shared/utils/date.d.ts +11 -0
  36. package/dist/src/shared/utils/date.test.d.ts +1 -0
  37. package/dist/src/shared/utils/price.d.ts +1 -0
  38. package/dist/src/typography/heading/heading.d.ts +1 -1
  39. package/dist/src/typography/heading/heading.stories.d.ts +1 -1
  40. package/dist/styles.css +19 -5
  41. package/package.json +6 -3
  42. /package/dist/src/shared/{fetch/constants.d.ts → utils/time.d.ts} +0 -0
package/dist/index.d.ts CHANGED
@@ -129,7 +129,6 @@ declare const request: Request;
129
129
  declare const features: {
130
130
  readonly language: "language";
131
131
  readonly pdp: "pdpV2";
132
- readonly pdpv1: "pdpV1";
133
132
  readonly plpv1: "plpV1";
134
133
  readonly searchv1: "searchV1";
135
134
  };
@@ -3828,35 +3827,47 @@ type TranslationId$1 =
3828
3827
  | "Unfortnately, We found no articles for your search '{0}'"
3829
3828
  | ' to your account to manage your lists.'
3830
3829
  | 'Add to list'
3830
+ | 'Amount: {0}'
3831
3831
  | 'An unexpected error occured'
3832
3832
  | 'Are you looking for information about our service? Please visit our customer support page'
3833
+ | 'Are you sure you want to remove all items from your cart?'
3834
+ | 'Are you sure you want to remove this item from your cart?'
3833
3835
  | 'Cancel'
3834
3836
  | 'Chosen filters'
3835
3837
  | 'Clear filters'
3836
3838
  | 'Clear'
3839
+ | 'Continue'
3837
3840
  | 'Continue shopping'
3841
+ | 'Cost overview'
3838
3842
  | 'Country'
3839
3843
  | 'Create new list'
3840
3844
  | 'create account'
3845
+ | 'Delivery expected in {0} {1}'
3841
3846
  | 'Double check your spelling'
3842
3847
  | 'Downloads'
3843
3848
  | 'Excl. VAT'
3844
3849
  | 'Explore by categories'
3845
3850
  | 'Exploring our products by category'
3846
3851
  | 'Features'
3852
+ | 'Fulfillment method'
3847
3853
  | 'Hide filters'
3848
3854
  | 'Incl. VAT'
3849
3855
  | 'Includes'
3850
3856
  | 'Language'
3851
3857
  | 'List name already exists'
3852
3858
  | 'New list name'
3859
+ | 'Order number'
3860
+ | 'pc'
3853
3861
  | 'Please Sign In'
3854
3862
  | 'Popular searches'
3863
+ | 'Print'
3855
3864
  | 'Product Features'
3856
3865
  | 'Products'
3866
+ | 'Product'
3857
3867
  | 'Quick access'
3858
3868
  | 'Recent searches'
3859
3869
  | 'Recently viewed'
3870
+ | 'Remove all'
3860
3871
  | 'Searching again using more general terms'
3861
3872
  | 'See all results'
3862
3873
  | 'Select a list'
@@ -3865,6 +3876,7 @@ type TranslationId$1 =
3865
3876
  | 'Your favorites are available on multiple devices'
3866
3877
  | 'Save'
3867
3878
  | 'Share your favorite list with others'
3879
+ | 'Shipping and handling'
3868
3880
  | 'Show all'
3869
3881
  | 'Show filters'
3870
3882
  | 'Show less'
@@ -3874,6 +3886,7 @@ type TranslationId$1 =
3874
3886
  | 'Sort by'
3875
3887
  | 'Specifications'
3876
3888
  | 'Submit'
3889
+ | 'Subtotal'
3877
3890
  | 'Suggestions'
3878
3891
  | 'The product has been added to your cart.'
3879
3892
  | 'The product has been updated in your cart.'
@@ -3882,7 +3895,9 @@ type TranslationId$1 =
3882
3895
  | 'Unable to update the product in your cart.'
3883
3896
  | 'Unable to remove the product from your cart.'
3884
3897
  | 'Try another search'
3898
+ | 'Total'
3885
3899
  | 'Use fewer keywords'
3900
+ | 'VAT'
3886
3901
  | 'Welcome to Sonic Equipment. Please choose your country and language below.'
3887
3902
  | 'What are you searching for?'
3888
3903
  | 'You could try checking the spelling of your search query'
@@ -3972,7 +3987,7 @@ interface UpdateCartLineParams {
3972
3987
  }
3973
3988
  declare function useUpdateCartLineById(): _tanstack_react_query.UseMutationResult<void, Error, UpdateCartLineParams, unknown>;
3974
3989
 
3975
- type TranslationId = "'{0}' in all products" | "Try 'Search' and try to find the product you're looking for" | "Unfortnately, We found no articles for your search '{0}'" | ' to your account to manage your lists.' | 'Add to list' | 'An unexpected error occured' | 'Are you looking for information about our service? Please visit our customer support page' | 'Cancel' | 'Chosen filters' | 'Clear filters' | 'Clear' | 'Continue shopping' | 'Country' | 'Create new list' | 'create account' | 'Double check your spelling' | 'Downloads' | 'Excl. VAT' | 'Explore by categories' | 'Exploring our products by category' | 'Features' | 'Hide filters' | 'Incl. VAT' | 'Includes' | 'Language' | 'List name already exists' | 'New list name' | 'Please Sign In' | 'Popular searches' | 'Product Features' | 'Products' | 'Quick access' | 'Recent searches' | 'Recently viewed' | 'Searching again using more general terms' | 'See all results' | 'Select a list' | 'Shop more efficiently and quicker with a favorites list' | 'Easily add your favorite products' | 'Your favorites are available on multiple devices' | 'Save' | 'Share your favorite list with others' | 'Show all' | 'Show filters' | 'Show less' | 'Show' | 'Sorry, there are no products found' | 'Sorry, we could not find matches for' | 'Sort by' | 'Specifications' | 'Submit' | 'Suggestions' | 'The product has been added to your cart.' | 'The product has been updated in your cart.' | 'The product has been removed from your cart.' | 'Unable to add the product to your cart.' | 'Unable to update the product in your cart.' | 'Unable to remove the product from your cart.' | 'Try another search' | 'Use fewer keywords' | 'Welcome to Sonic Equipment. Please choose your country and language below.' | 'What are you searching for?' | 'You could try checking the spelling of your search query' | 'You could try exploring our products by category' | 'You could try' | 'You must ' | 'article' | 'articles' | 'facet.categories' | 'facet.height' | 'facet.weight' | 'of' | 'sign in' | 'sort.newest' | 'sort.price_asc' | 'sort.price_desc' | 'sort.relevance' | 'tag.limited' | 'tag.new';
3990
+ type TranslationId = "'{0}' in all products" | "Try 'Search' and try to find the product you're looking for" | "Unfortnately, We found no articles for your search '{0}'" | ' to your account to manage your lists.' | 'Add to list' | 'Amount: {0}' | 'An unexpected error occured' | 'Are you looking for information about our service? Please visit our customer support page' | 'Are you sure you want to remove all items from your cart?' | 'Are you sure you want to remove this item from your cart?' | 'Cancel' | 'Chosen filters' | 'Clear filters' | 'Clear' | 'Continue' | 'Continue shopping' | 'Cost overview' | 'Country' | 'Create new list' | 'create account' | 'Delivery expected in {0} {1}' | 'Double check your spelling' | 'Downloads' | 'Excl. VAT' | 'Explore by categories' | 'Exploring our products by category' | 'Features' | 'Fulfillment method' | 'Hide filters' | 'Incl. VAT' | 'Includes' | 'Language' | 'List name already exists' | 'New list name' | 'Order number' | 'pc' | 'Please Sign In' | 'Popular searches' | 'Print' | 'Product Features' | 'Products' | 'Product' | 'Quick access' | 'Recent searches' | 'Recently viewed' | 'Remove all' | 'Searching again using more general terms' | 'See all results' | 'Select a list' | 'Shop more efficiently and quicker with a favorites list' | 'Easily add your favorite products' | 'Your favorites are available on multiple devices' | 'Save' | 'Share your favorite list with others' | 'Shipping and handling' | 'Show all' | 'Show filters' | 'Show less' | 'Show' | 'Sorry, there are no products found' | 'Sorry, we could not find matches for' | 'Sort by' | 'Specifications' | 'Submit' | 'Subtotal' | 'Suggestions' | 'The product has been added to your cart.' | 'The product has been updated in your cart.' | 'The product has been removed from your cart.' | 'Unable to add the product to your cart.' | 'Unable to update the product in your cart.' | 'Unable to remove the product from your cart.' | 'Try another search' | 'Total' | 'Use fewer keywords' | 'VAT' | 'Welcome to Sonic Equipment. Please choose your country and language below.' | 'What are you searching for?' | 'You could try checking the spelling of your search query' | 'You could try exploring our products by category' | 'You could try' | 'You must ' | 'article' | 'articles' | 'facet.categories' | 'facet.height' | 'facet.weight' | 'of' | 'sign in' | 'sort.newest' | 'sort.price_asc' | 'sort.price_desc' | 'sort.relevance' | 'tag.limited' | 'tag.new';
3976
3991
 
3977
3992
  type Translations = Record<TranslationId, string>;
3978
3993
  type FormatMessageFunction = (id: string, ...replacementValues: readonly string[]) => string | undefined;
@@ -4472,9 +4487,10 @@ declare function CountrySelector({ defaultCountryCode, defaultLanguageCode, onCh
4472
4487
 
4473
4488
  interface ProductPriceProps {
4474
4489
  className?: string;
4475
- isVatIncluded: boolean;
4490
+ isVatIncluded: boolean | null;
4476
4491
  originalPrice: number;
4477
4492
  price: number;
4493
+ pricePerUnit?: number;
4478
4494
  }
4479
4495
  declare function ProductPrice({ className, isVatIncluded, originalPrice, price, }: ProductPriceProps): react_jsx_runtime.JSX.Element | undefined;
4480
4496
 
@@ -4617,11 +4633,17 @@ interface IntlProviderProps {
4617
4633
  }
4618
4634
  declare function IntlProvider({ children, formatMessage, languageCode: _languageCode, }: IntlProviderProps): react_jsx_runtime.JSX.Element;
4619
4635
 
4620
- type FormattedMessageFunction = (id: TranslationId, options?: {
4621
- fallbackValue?: string;
4622
- optional?: boolean;
4623
- replacementValues?: Record<string, string>;
4624
- }) => string;
4636
+ interface FormattedMessageFunction {
4637
+ (id: TranslationId, options?: {
4638
+ fallbackValue?: string;
4639
+ optional?: boolean;
4640
+ replacementValues?: Record<string, string>;
4641
+ }): string;
4642
+ pluralize: {
4643
+ (translationId: string, count: number): string;
4644
+ (translationIdPrefix: string, translationId: string, count: number): string;
4645
+ };
4646
+ }
4625
4647
  declare function useFormattedMessage(): FormattedMessageFunction;
4626
4648
 
4627
4649
  interface ProductOverviewGridProps {
package/dist/index.js CHANGED
@@ -214,7 +214,7 @@ const configPerEnvironment = {
214
214
  ALGOLIA_API_KEY: 'e0edf30798a6b2e4e44fd25f0f2f9646',
215
215
  ALGOLIA_APP_ID: 'testing9VXJ0U4GSV',
216
216
  ALGOLIA_HOST: 'sonicequipment.commerce.insitesandbox.com',
217
- BFF_API_URL: 'https://sonicequipment.commerce.insitesandbox.com/api/v1/bff',
217
+ BFF_API_URL: 'https://localhost:8000/api/v1/bff',
218
218
  COOKIE_DOMAIN: '.insitesandbox.com',
219
219
  SHOP_API_URL:
220
220
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -484,7 +484,6 @@ const request = (function createRequestFunction() {
484
484
  const features = {
485
485
  language: 'language',
486
486
  pdp: 'pdpV2',
487
- pdpv1: 'pdpV1',
488
487
  plpv1: 'plpV1',
489
488
  searchv1: 'searchV1',
490
489
  };
@@ -1348,9 +1347,9 @@ function Button({ _pseudo = 'none', children, className, color = 'primary', cond
1348
1347
  const onClick = (e) => {
1349
1348
  if (_onClick)
1350
1349
  _onClick(e);
1350
+ e.stopPropagation();
1351
1351
  if (type === 'submit')
1352
1352
  return;
1353
- e.stopPropagation();
1354
1353
  e.preventDefault();
1355
1354
  };
1356
1355
  return (jsxs("button", { className: clsx({ [buttonStyles.condensed]: condensed }, { [buttonStyles.icon]: icon }, buttonStyles.button, buttonStyles[variant], buttonStyles[size], buttonStyles[color], buttonStyles[_pseudo], className), "data-disabled": isDisabled ? true : undefined, disabled: isDisabled, onClick: onClick, type: type, children: [jsx(Fragment, { children: showIconOnLeft && jsx("span", { className: buttonStyles.icon, children: icon }) }), children, withArrow && (jsx(GlyphsArrowBoldCapsRightIcon, { className: buttonStyles['right-arrow-icon'] })), showIconOnRight && jsx("span", { className: buttonStyles.icon, children: icon })] }));
@@ -1672,7 +1671,7 @@ const IntlContext = createContext({
1672
1671
 
1673
1672
  function useFormattedMessage() {
1674
1673
  const { formatMessage } = useContext(IntlContext);
1675
- return (id, { fallbackValue, optional, replacementValues } = {}) => {
1674
+ const formatFunction = (id, { fallbackValue, optional, replacementValues } = {}) => {
1676
1675
  const message = formatMessage(id,
1677
1676
  /* The following code converts replacementValues from an object to an array.
1678
1677
  * This is to keep the external API compatible with react-intls version
@@ -1693,6 +1692,13 @@ function useFormattedMessage() {
1693
1692
  console.warn(`Missing translation with id: ${id}`);
1694
1693
  return message || fallbackValue || id;
1695
1694
  };
1695
+ function pluralize(translationIdOrPrefix, translationIdOrCount, count) {
1696
+ return formatFunction((typeof translationIdOrCount === 'number'
1697
+ ? `${translationIdOrPrefix}.${translationIdOrCount === 1 ? 'singular' : 'plural'}`
1698
+ : `${translationIdOrPrefix}.${translationIdOrCount}.${count === 1 ? 'singular' : 'plural'}`));
1699
+ }
1700
+ formatFunction.pluralize = pluralize;
1701
+ return formatFunction;
1696
1702
  }
1697
1703
 
1698
1704
  const FormattedMessage = ({ fallbackValue, id, optional, replacementValues, }) => useFormattedMessage()(id, { fallbackValue, optional, replacementValues });
@@ -1845,13 +1851,14 @@ function Tag({ children }) {
1845
1851
  return (jsxs("div", { className: styles$Z.tag, children: [jsx("div", { className: styles$Z.body, children: children }), jsx("svg", { className: styles$Z.shape, height: "16", viewBox: "0 0 9 16", width: "9", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M1.92461763,0 L0,0 L0,16 L1.92461763,16 L6.4117887,16 L8.87489381,7.57121588 C9.23711515,6.3325062 8.79482383,4.99454094 7.78060408,4.2560794 L1.92461763,0 Z", fill: "currentColor" }) })] }));
1846
1852
  }
1847
1853
 
1848
- var styles$Y = {"product-price":"product-price-module-oIU1K","original-price":"product-price-module-til0s","is-hidden":"product-price-module-V1NCf","current-price-wrapper":"product-price-module-FfVhl","current-price":"product-price-module-pvy2w","wholes":"product-price-module-GCw07","dot":"product-price-module-N56iV","decimals":"product-price-module-eWOOF","vat":"product-price-module-96DoG"};
1849
-
1850
1854
  const formatPrice = (price) => new Intl.NumberFormat('en-US', {
1851
1855
  maximumFractionDigits: 2,
1852
1856
  minimumFractionDigits: 2,
1853
1857
  }).format(price);
1854
- function ProductPrice({ className, isVatIncluded, originalPrice, price, }) {
1858
+
1859
+ var styles$Y = {"product-price":"product-price-module-oIU1K","original-price":"product-price-module-til0s","is-hidden":"product-price-module-V1NCf","current-price-wrapper":"product-price-module-FfVhl","current-price":"product-price-module-pvy2w","wholes":"product-price-module-GCw07","dot":"product-price-module-N56iV","decimals":"product-price-module-eWOOF","price-per-unit":"product-price-module-syhum","vat":"product-price-module-96DoG"};
1860
+
1861
+ function ProductPrice({ className, isVatIncluded = false, originalPrice, price, }) {
1855
1862
  if (isNaN(price))
1856
1863
  return;
1857
1864
  const originalPriceWithCurrency = formatPrice(!isNaN(originalPrice) ? originalPrice : price);
@@ -1860,7 +1867,7 @@ function ProductPrice({ className, isVatIncluded, originalPrice, price, }) {
1860
1867
  const showOriginalPrice = priceWithCurrency !== originalPriceWithCurrency;
1861
1868
  return (jsxs("div", { className: clsx(className, styles$Y['product-price']), children: [jsx("span", { className: clsx(styles$Y['original-price'], {
1862
1869
  [styles$Y['is-hidden']]: !showOriginalPrice,
1863
- }), children: originalPriceWithCurrency }), jsxs("div", { className: styles$Y['current-price-wrapper'], children: [jsxs("div", { className: styles$Y['current-price'], children: [jsx("span", { className: styles$Y.wholes, children: wholes }), jsx("span", { className: styles$Y.dot, children: "." }), jsx("span", { className: styles$Y.decimals, children: decimals })] }), jsx("span", { className: styles$Y.vat, children: isVatIncluded ? (jsx(FormattedMessage, { id: "Incl. VAT" })) : (jsx(FormattedMessage, { id: "Excl. VAT" })) })] })] }));
1870
+ }), children: originalPriceWithCurrency }), jsxs("div", { className: styles$Y['current-price-wrapper'], children: [jsxs("div", { className: styles$Y['current-price'], children: [jsx("span", { className: styles$Y.wholes, children: wholes }), jsx("span", { className: styles$Y.dot, children: "." }), jsx("span", { className: styles$Y.decimals, children: decimals })] }), isVatIncluded !== null && (jsx("span", { className: styles$Y.vat, children: isVatIncluded ? (jsx(FormattedMessage, { id: "Incl. VAT" })) : (jsx(FormattedMessage, { id: "Excl. VAT" })) }))] })] }));
1864
1871
  }
1865
1872
 
1866
1873
  var styles$X = {"product-sku":"product-sku-module-ITb8x"};
@@ -7874,10 +7881,10 @@ function Modal({ children, className, hasCloseButton, isDismissable, isFullScree
7874
7881
  });
7875
7882
  }, className: clsx(styles$O['modal-overlay'], className), isDismissable: isDismissable, isKeyboardDismissDisabled: isKeyboardDismissDisabled, isOpen: isOpen, onOpenChange: onOpenChange, shouldCloseOnInteractOutside: () => shouldCloseOnInteractOutside, children: jsxs(Modal$1, { className: clsx(styles$O.modal, {
7876
7883
  [styles$O['is-full-screen']]: isFullScreen,
7877
- }), children: [hasCloseButton && (jsx("div", { className: styles$O.close, children: jsx(IconButton, { color: "secondary", isDisabled: !isDismissable, onClick: () => onOpenChange(false), children: jsx(StrokeCloseboxIcon, {}) }) })), jsx("div", { className: styles$O.content, children: children })] }) }));
7884
+ }), children: [hasCloseButton && (jsx("div", { className: styles$O.close, children: jsx(IconButton, { color: "secondary", isDisabled: !isDismissable, onClick: () => onOpenChange?.(false), children: jsx(StrokeCloseboxIcon, {}) }) })), jsx("div", { className: styles$O.content, children: children })] }) }));
7878
7885
  }
7879
7886
 
7880
- var styles$N = {"heading":"heading-module-pMC65","uppercase":"heading-module-6spgX","italic":"heading-module-XXMDM","bold":"heading-module-xvrxo","xxl":"heading-module-Kn3ZN","xl":"heading-module--hZs-","l":"heading-module-WrJRY","m":"heading-module-hTexc","s":"heading-module-7W29m","xs":"heading-module-SgaLB","xxs":"heading-module-33en7"};
7887
+ var styles$N = {"heading":"heading-module-pMC65","uppercase":"heading-module-6spgX","italic":"heading-module-XXMDM","bold":"heading-module-xvrxo","xxl":"heading-module-Kn3ZN","xl":"heading-module--hZs-","l":"heading-module-WrJRY","m":"heading-module-hTexc","s":"heading-module-7W29m","xs":"heading-module-SgaLB","xxs":"heading-module-33en7","xxxs":"heading-module-qvrEk"};
7881
7888
 
7882
7889
  const sizeToTag = {
7883
7890
  l: 'h3',
@@ -7887,6 +7894,7 @@ const sizeToTag = {
7887
7894
  xs: 'h6',
7888
7895
  xxl: 'h1',
7889
7896
  xxs: 'h6',
7897
+ xxxs: 'h6',
7890
7898
  };
7891
7899
  function Heading({ bold = true, children, className, italic, size = 'xxl', tag, uppercase, }) {
7892
7900
  return createElement$1(tag || sizeToTag[size], {
@@ -7900,22 +7908,28 @@ function Heading({ bold = true, children, className, italic, size = 'xxl', tag,
7900
7908
 
7901
7909
  var styles$M = {"dialog":"dialog-module-qKzgy","header":"dialog-module-ZnsAe","close":"dialog-module-Y7Tqg","footer":"dialog-module-y7Axm"};
7902
7910
 
7903
- function Footer({ close }) {
7904
- return (jsxs(Fragment, { children: [jsx(Button, { withArrow: true, color: "primary", size: "md", type: "submit", children: "Submit" }), jsx(Button, { color: "secondary", onClick: close, size: "md", variant: "outline", children: "Close" })] }));
7911
+ function Footer({ cancelLabel, close, submitLabel }) {
7912
+ return (jsxs(Fragment, { children: [jsx(Button, { withArrow: true, color: "primary", size: "md", type: "submit", children: jsx(FormattedMessage, { id: submitLabel }) }), jsx(Button, { color: "secondary", onClick: close, size: "md", variant: "outline", children: jsx(FormattedMessage, { id: cancelLabel }) })] }));
7905
7913
  }
7906
- function Dialog({ allowClose = true, children, className, dialogClassName, footer = Footer, hasCloseButton = true, hideTitle, isDismissable, isFullScreen, isKeyboardDismissDisabled, isOpen, onOpenChange, onSubmit, shouldCloseOnInteractOutside, title, validationErrors, }) {
7907
- return (jsx(Modal, { className: clsx(styles$M['modal-overlay'], className), hasCloseButton: false, isDismissable: isDismissable, isFullScreen: isFullScreen, isKeyboardDismissDisabled: isKeyboardDismissDisabled, isOpen: isOpen, onOpenChange: onOpenChange, shouldCloseOnInteractOutside: shouldCloseOnInteractOutside, children: jsx(Dialog$1, { "aria-label": title, className: clsx(styles$M.dialog, dialogClassName), children: ({ close }) => (jsxs(Form, { className: styles$M.form, onSubmit: onSubmit || (e => e.preventDefault), validationErrors: validationErrors, children: [jsxs("header", { className: styles$M.header, children: [!hideTitle && (jsx(Heading, { className: styles$M.heading, size: "xs", children: title })), hasCloseButton && (jsx("div", { className: styles$M.close, children: jsx(IconButton, { color: "secondary", isDisabled: !allowClose, onClick: close, children: jsx(StrokeCloseboxIcon, {}) }) }))] }), jsx("div", { className: styles$M.content, children: children instanceof Function ? children({ close }) : children }), jsx("footer", { className: styles$M.footer, children: footer instanceof Function ? footer({ close }) : footer })] })) }) }));
7914
+ function Dialog({ allowClose = true, cancelLabel = 'Close', children, className, dialogClassName, footer = Footer, hasCloseButton = true, hideTitle, isDismissable, isFullScreen, isKeyboardDismissDisabled, isOpen, onOpenChange, onSubmit, shouldCloseOnInteractOutside, submitLabel = 'Submit', title, validationErrors, }) {
7915
+ return (jsx(Modal, { className: clsx(styles$M['modal-overlay'], className), hasCloseButton: false, isDismissable: isDismissable, isFullScreen: isFullScreen, isKeyboardDismissDisabled: isKeyboardDismissDisabled, isOpen: isOpen, onOpenChange: onOpenChange, shouldCloseOnInteractOutside: shouldCloseOnInteractOutside, children: jsx(Dialog$1, { "aria-label": title, className: clsx(styles$M.dialog, dialogClassName), children: ({ close }) => (jsxs(Form, { className: styles$M.form, onSubmit: e => {
7916
+ e.preventDefault();
7917
+ e.stopPropagation();
7918
+ onSubmit?.(e);
7919
+ }, validationErrors: validationErrors, children: [jsxs("header", { className: styles$M.header, children: [!hideTitle && (jsx(Heading, { className: styles$M.heading, size: "xs", children: title })), hasCloseButton && (jsx("div", { className: styles$M.close, children: jsx(IconButton, { color: "secondary", isDisabled: !allowClose, onClick: close, children: jsx(StrokeCloseboxIcon, {}) }) }))] }), jsx("div", { className: styles$M.content, children: children instanceof Function ? children({ close }) : children }), jsx("footer", { className: styles$M.footer, children: footer instanceof Function
7920
+ ? footer({ cancelLabel, close, submitLabel })
7921
+ : footer })] })) }) }));
7908
7922
  }
7909
7923
 
7910
7924
  var styles$L = {"country-selector-dialog":"country-selector-dialog-module-mMJS0","content":"country-selector-dialog-module-z-ZqY","logo":"country-selector-dialog-module-7VjsF","intro":"country-selector-dialog-module-IdVDt","selects":"country-selector-dialog-module-Nvikf"};
7911
7925
 
7912
- function CountrySelectorDialog({ countries, isOpen, onSubmit, selectedCountry, selectedLanguage, showCountry = true, }) {
7926
+ function CountrySelectorDialog({ countries, isDismissable, isOpen, onOpenChange, onSubmit, selectedCountry, selectedLanguage, showCountry = true, }) {
7913
7927
  const t = useFormattedMessage();
7914
7928
  const [currentCountry, setCurrentCountry] = useState(selectedCountry);
7915
7929
  const [currentLanguage, setCurrentLanguage] = useState(selectedLanguage);
7916
7930
  const countryOptions = useMemo(() => countries.reduce((acc, country) => ({
7917
7931
  ...acc,
7918
- [country.id]: t(`clSelector.${country.name}`),
7932
+ [country.id]: t(`clSelector.${country.abbreviation}`),
7919
7933
  }), {}),
7920
7934
  // eslint-disable-next-line react-hooks/exhaustive-deps
7921
7935
  [countries]);
@@ -7929,11 +7943,11 @@ function CountrySelectorDialog({ countries, isOpen, onSubmit, selectedCountry, s
7929
7943
  setCurrentLanguage(fallbackLanguage);
7930
7944
  // eslint-disable-next-line react-hooks/exhaustive-deps
7931
7945
  }, [currentCountry]);
7932
- return (jsx(Dialog, { hideTitle: true, allowClose: true, className: styles$L.modal, dialogClassName: styles$L['country-selector-dialog'], footer: jsx(Button, { withArrow: true, type: "submit", children: jsx(FormattedMessage, { id: "Save" }) }), hasCloseButton: false, isOpen: isOpen, onOpenChange: () => { }, onSubmit: e => {
7946
+ return (jsx(Dialog, { hideTitle: true, allowClose: isDismissable, className: styles$L.modal, dialogClassName: styles$L['country-selector-dialog'], footer: jsx(Button, { withArrow: true, type: "submit", children: jsx(FormattedMessage, { id: "Save" }) }), hasCloseButton: isDismissable, isDismissable: isDismissable, isOpen: isOpen, onOpenChange: onOpenChange, onSubmit: e => {
7933
7947
  onSubmit({ country: currentCountry, language: currentLanguage });
7934
7948
  e.preventDefault();
7935
7949
  e.stopPropagation();
7936
- }, title: "Country Selector", children: jsxs("div", { className: styles$L.content, children: [jsx("svg", { className: styles$L.logo, height: "32", viewBox: "0 0 134 32", width: "134", xmlns: "http://www.w3.org/2000/svg", children: jsxs("g", { fill: "none", fillRule: "evenodd", children: [jsx("path", { d: "M15.83 11.533c2.42 0 4.382 1.977 4.382 4.415 0 8.794-7.1 15.95-15.83 15.95C1.963 31.897 0 29.92 0 27.481c0-2.354 1.83-4.278 4.134-4.408l.249-.007c3.797 0 6.905-3.036 7.058-6.826l.006-.293c0-2.438 1.963-4.415 4.383-4.415zM15.83 0c2.42 0 4.383 1.977 4.383 4.415 0 2.355-1.83 4.279-4.134 4.409l-.249.007c-3.8 0-6.906 3.035-7.059 6.824l-.006.293c0 2.438-1.962 4.415-4.382 4.415S0 18.386 0 15.948C0 7.154 7.101 0 15.83 0zm8.208 16.022c0 8.794 7.101 15.95 15.83 15.95s15.83-7.156 15.83-15.95S48.597.074 39.868.074s-15.83 7.154-15.83 15.948zm8.765 0c0-3.924 3.169-7.118 7.065-7.118 3.895 0 7.065 3.194 7.065 7.118 0 3.926-3.17 7.119-7.065 7.119-3.896 0-7.065-3.193-7.065-7.12zm76.888-11.276c-6.173 6.217-6.173 16.335-.002 22.553 6.173 6.217 16.215 6.217 22.388 0a4.44 4.44 0 0 0 .001-6.244 4.359 4.359 0 0 0-6.003-.184l-.194.184a7.04 7.04 0 0 1-9.994 0c-2.753-2.775-2.753-7.29.002-10.065a7.036 7.036 0 0 1 9.751-.233l.24.231a4.36 4.36 0 0 0 6.198 0 4.44 4.44 0 0 0-.001-6.245c-6.173-6.217-16.215-6.216-22.386.003zm-17.162-.174v22.863c0 2.439 1.961 4.416 4.381 4.416 2.422 0 4.384-1.977 4.384-4.416V4.572c0-2.439-1.962-4.416-4.384-4.416-2.42 0-4.38 1.977-4.38 4.416zM64.1.1c-2.42 0-4.383 1.977-4.383 4.415v23.07c0 2.438 1.962 4.415 4.382 4.415s4.383-1.977 4.383-4.415V8.93h3.933c3.895 0 7.065 3.192 7.065 7.118v11.537c0 2.438 1.962 4.415 4.382 4.415s4.383-1.977 4.383-4.415V16.048C88.244 7.254 81.143.1 72.414.1h-8.316z", fill: "#000" }), jsx("path", { d: "M47.036 16.022c0 3.99-3.209 7.222-7.168 7.222-3.96 0-7.169-3.233-7.169-7.222 0-3.989 3.21-7.222 7.169-7.222 3.96 0 7.168 3.233 7.168 7.222", fill: "#E30613" })] }) }), jsx("p", { className: styles$L.intro, children: jsx(FormattedMessage, { id: "Welcome to Sonic Equipment. Please choose your country and language below." }) }), jsxs("div", { className: styles$L.selects, children: [showCountry && (jsx(Select, { label: t('Country'), onChange: value => setCurrentCountry(countries.find(country => country.id === value) ||
7950
+ }, shouldCloseOnInteractOutside: isDismissable, title: "Country Selector", children: jsxs("div", { className: styles$L.content, children: [jsx("svg", { className: styles$L.logo, height: "32", viewBox: "0 0 134 32", width: "134", xmlns: "http://www.w3.org/2000/svg", children: jsxs("g", { fill: "none", fillRule: "evenodd", children: [jsx("path", { d: "M15.83 11.533c2.42 0 4.382 1.977 4.382 4.415 0 8.794-7.1 15.95-15.83 15.95C1.963 31.897 0 29.92 0 27.481c0-2.354 1.83-4.278 4.134-4.408l.249-.007c3.797 0 6.905-3.036 7.058-6.826l.006-.293c0-2.438 1.963-4.415 4.383-4.415zM15.83 0c2.42 0 4.383 1.977 4.383 4.415 0 2.355-1.83 4.279-4.134 4.409l-.249.007c-3.8 0-6.906 3.035-7.059 6.824l-.006.293c0 2.438-1.962 4.415-4.382 4.415S0 18.386 0 15.948C0 7.154 7.101 0 15.83 0zm8.208 16.022c0 8.794 7.101 15.95 15.83 15.95s15.83-7.156 15.83-15.95S48.597.074 39.868.074s-15.83 7.154-15.83 15.948zm8.765 0c0-3.924 3.169-7.118 7.065-7.118 3.895 0 7.065 3.194 7.065 7.118 0 3.926-3.17 7.119-7.065 7.119-3.896 0-7.065-3.193-7.065-7.12zm76.888-11.276c-6.173 6.217-6.173 16.335-.002 22.553 6.173 6.217 16.215 6.217 22.388 0a4.44 4.44 0 0 0 .001-6.244 4.359 4.359 0 0 0-6.003-.184l-.194.184a7.04 7.04 0 0 1-9.994 0c-2.753-2.775-2.753-7.29.002-10.065a7.036 7.036 0 0 1 9.751-.233l.24.231a4.36 4.36 0 0 0 6.198 0 4.44 4.44 0 0 0-.001-6.245c-6.173-6.217-16.215-6.216-22.386.003zm-17.162-.174v22.863c0 2.439 1.961 4.416 4.381 4.416 2.422 0 4.384-1.977 4.384-4.416V4.572c0-2.439-1.962-4.416-4.384-4.416-2.42 0-4.38 1.977-4.38 4.416zM64.1.1c-2.42 0-4.383 1.977-4.383 4.415v23.07c0 2.438 1.962 4.415 4.382 4.415s4.383-1.977 4.383-4.415V8.93h3.933c3.895 0 7.065 3.192 7.065 7.118v11.537c0 2.438 1.962 4.415 4.382 4.415s4.383-1.977 4.383-4.415V16.048C88.244 7.254 81.143.1 72.414.1h-8.316z", fill: "#000" }), jsx("path", { d: "M47.036 16.022c0 3.99-3.209 7.222-7.168 7.222-3.96 0-7.169-3.233-7.169-7.222 0-3.989 3.21-7.222 7.169-7.222 3.96 0 7.168 3.233 7.168 7.222", fill: "#E30613" })] }) }), jsx("p", { className: styles$L.intro, children: jsx(FormattedMessage, { id: "Welcome to Sonic Equipment. Please choose your country and language below." }) }), jsxs("div", { className: styles$L.selects, children: [showCountry && (jsx(Select, { label: t('Country'), onChange: value => setCurrentCountry(countries.find(country => country.id === value) ||
7937
7951
  currentCountry), options: countryOptions, selectedOption: currentCountry.id, showPlaceholder: false, variant: "solid" })), jsx(Select, { label: t('Language'), onChange: value => setCurrentLanguage(currentCountry.languages.find(language => language.id === value) || currentLanguage), options: languageOptions, selectedOption: currentLanguage.id, showPlaceholder: false, variant: "solid" })] })] }) }));
7938
7952
  }
7939
7953
 
@@ -7945,7 +7959,7 @@ function CountrySelectorTrigger({ onClick, selectedCountry, selectedLanguage, sh
7945
7959
  return;
7946
7960
  const abbreviation = selectedCountry.abbreviation.toLowerCase();
7947
7961
  const flagSrc = `https://res.cloudinary.com/dkz9eknwh/image/upload/v1729678637/images/flags/${abbreviation}.svg`;
7948
- return (jsxs("button", { "aria-label": "Open country selector dialog", className: styles$K['country-selector-trigger'], onClick: onClick, type: "button", children: [jsx(Image, { className: styles$K.flag, height: 24, image: { 1: flagSrc, 2: flagSrc, 3: flagSrc, altText: abbreviation }, title: abbreviation, width: 24 }), jsxs("div", { className: styles$K.text, children: [showCountry && (jsxs(Fragment, { children: [jsx("span", { children: t(`clSelector.${selectedCountry.name}`) }), jsx("span", { className: styles$K.divider, children: "-" })] })), jsx("span", { children: selectedLanguage.description })] })] }));
7962
+ return (jsxs("button", { "aria-label": "Open country selector dialog", className: styles$K['country-selector-trigger'], onClick: onClick, type: "button", children: [jsx(Image, { className: styles$K.flag, height: 24, image: { 1: flagSrc, 2: flagSrc, 3: flagSrc, altText: abbreviation }, title: abbreviation, width: 24 }), jsxs("div", { className: styles$K.text, children: [showCountry && (jsxs(Fragment, { children: [jsx("span", { children: t(`clSelector.${selectedCountry.abbreviation}`) }), jsx("span", { className: styles$K.divider, children: "-" })] })), jsx("span", { children: selectedLanguage.description })] })] }));
7949
7963
  }
7950
7964
 
7951
7965
  async function fetchCountriesLanguages() {
@@ -8010,9 +8024,21 @@ function useFetchCountriesLanguages({ enabled = true, } = { enabled: true }) {
8010
8024
  });
8011
8025
  }
8012
8026
 
8027
+ function useUpdateLocale() {
8028
+ return useMutation({
8029
+ mutationFn: updateLocale,
8030
+ throwOnError: true,
8031
+ });
8032
+ }
8033
+
8013
8034
  function useCookie(name, options) {
8014
8035
  const cookieValue = Cookies.get()[name];
8015
8036
  const [stateValue, setStateValue] = useState(cookieValue);
8037
+ useEffect(() => {
8038
+ if (cookieValue === stateValue)
8039
+ return;
8040
+ setStateValue(cookieValue);
8041
+ }, [cookieValue, stateValue]);
8016
8042
  function setValue(valueOrFn) {
8017
8043
  setStateValue(oldValue => {
8018
8044
  const newValue = typeof valueOrFn === 'function' ? valueOrFn(oldValue) : valueOrFn;
@@ -8053,6 +8079,7 @@ const cookieOptions = {
8053
8079
  };
8054
8080
  function useCountriesLanguages({ defaultCountryCode, defaultLanguageCode, }) {
8055
8081
  const [sessionCountries, setSessionCountries] = useSessionStorage('countries-v1');
8082
+ const { mutate: updateLocale } = useUpdateLocale();
8056
8083
  const [currentCountryId] = useCookie('CurrentCountryId', cookieOptions);
8057
8084
  const [currentLanguageId] = useCookie('CurrentLanguageId', cookieOptions);
8058
8085
  const [contextLanguageCode] = useCookie('SetContextLanguageCode', cookieOptions);
@@ -8067,7 +8094,7 @@ function useCountriesLanguages({ defaultCountryCode, defaultLanguageCode, }) {
8067
8094
  // eslint-disable-next-line react-hooks/exhaustive-deps
8068
8095
  }, [apiCountries]);
8069
8096
  async function updateCountryLanguage({ country, language, }) {
8070
- await updateLocale({ countryId: country.id, languageId: language.id });
8097
+ updateLocale({ countryId: country.id, languageId: language.id });
8071
8098
  }
8072
8099
  if (error)
8073
8100
  throw error;
@@ -8113,16 +8140,25 @@ function CountrySelector({ defaultCountryCode, defaultLanguageCode, onChange, sh
8113
8140
  defaultCountryCode,
8114
8141
  defaultLanguageCode,
8115
8142
  });
8143
+ const isCountryLanguageSelected = useMemo(() => selectedCountry !== undefined && selectedLanguage !== undefined, [selectedCountry, selectedLanguage]);
8144
+ const isDismissable = isCountryLanguageSelected;
8116
8145
  useEffect(() => {
8117
- setIsOpen(selectedCountry === undefined || selectedLanguage === undefined);
8146
+ setIsOpen(!isCountryLanguageSelected);
8118
8147
  // eslint-disable-next-line react-hooks/exhaustive-deps
8119
- }, [selectedCountry, selectedLanguage]);
8148
+ }, [isCountryLanguageSelected]);
8120
8149
  if (isFetching)
8121
8150
  return null;
8122
- return (jsxs(Fragment, { children: [jsx(CountrySelectorTrigger, { onClick: open, selectedCountry: selectedCountry, selectedLanguage: selectedLanguage, showCountry: showCountry }), jsx(CountrySelectorDialog, { countries: countries, isOpen: isOpen, onSubmit: async (args) => {
8123
- await updateCountryLanguage(args);
8151
+ return (jsxs(Fragment, { children: [jsx(CountrySelectorTrigger, { onClick: open, selectedCountry: selectedCountry, selectedLanguage: selectedLanguage, showCountry: showCountry }), jsx(CountrySelectorDialog, { countries: countries, isDismissable: isDismissable, isOpen: isOpen, onOpenChange: open => {
8152
+ if (!isDismissable)
8153
+ return;
8154
+ setIsOpen(open);
8155
+ }, onSubmit: async ({ country, language }) => {
8156
+ if (selectedCountry?.id === country.id &&
8157
+ selectedLanguage?.id === language.id)
8158
+ return close();
8159
+ await updateCountryLanguage({ country, language });
8124
8160
  close();
8125
- onChange?.(args);
8161
+ onChange?.({ country, language });
8126
8162
  }, selectedCountry: selectedCountry || defaultCountry, selectedLanguage: selectedLanguage || defaultLanguage, showCountry: showCountry })] }));
8127
8163
  }
8128
8164
 
@@ -8251,39 +8287,57 @@ function useLanguageCode() {
8251
8287
  return languageCode;
8252
8288
  }
8253
8289
 
8254
- const announcementTypes = [
8255
- 'promo',
8290
+ async function fetchAnnouncements({ languageCode, }) {
8291
+ return await request({
8292
+ headers: { 'Current-Language-Id': languageCode },
8293
+ url: `${config.BFF_API_URL}/notification/announcement`,
8294
+ });
8295
+ }
8296
+
8297
+ const announcementTypes = ['promo', 'service'];
8298
+ const announcementSubTypes = [
8299
+ 'sales',
8300
+ 'news',
8301
+ 'critical',
8256
8302
  'informative',
8257
8303
  'notice',
8258
- 'critical',
8304
+ 'event',
8305
+ 'new_product_introduction',
8259
8306
  ];
8260
8307
  function isAnnouncementType(type) {
8261
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
8262
8308
  return announcementTypes.includes(type);
8263
8309
  }
8310
+ function isAnnouncementSubtype(subtype) {
8311
+ return announcementSubTypes.includes(subtype);
8312
+ }
8264
8313
 
8265
8314
  function useFetchAnnouncements({ languageCode, }) {
8266
8315
  return useQuery({
8267
8316
  gcTime: 1 * TIME.DAY,
8268
- queryFn: async () => await request({
8269
- headers: { 'Current-Language-Id': languageCode },
8270
- url: `${config.BFF_API_URL}/notification/announcement`,
8271
- }),
8317
+ queryFn: () => fetchAnnouncements({ languageCode }),
8272
8318
  queryKey: ['announcements', languageCode],
8273
8319
  refetchInterval: 5 * TIME.MINUTE,
8274
- select: ({ body }) => body.map(({ endDate, href, id, startDate, text, title, type }) => {
8275
- if (!isAnnouncementType(type))
8276
- throw new Error(`Invalid announcement type: ${type}`);
8277
- return {
8278
- endDate: endDate ? new Date(endDate) : undefined,
8279
- href,
8280
- id,
8281
- startDate: startDate ? new Date(startDate) : undefined,
8282
- text,
8283
- title,
8284
- type,
8285
- };
8286
- }),
8320
+ select: ({ body }) => {
8321
+ if (typeof body === 'string')
8322
+ return [];
8323
+ return body.map(({ endDate, href, id, startDate, subType, text, title, type }) => {
8324
+ if (!isAnnouncementType(type))
8325
+ throw new Error(`Invalid announcement type: ${type}`);
8326
+ if (!isAnnouncementSubtype(subType)) {
8327
+ throw new Error(`Invalid announcement subType: ${subType}`);
8328
+ }
8329
+ return {
8330
+ endDate: endDate ? new Date(endDate) : undefined,
8331
+ href,
8332
+ id,
8333
+ startDate: startDate ? new Date(startDate) : undefined,
8334
+ subType,
8335
+ text,
8336
+ title,
8337
+ type,
8338
+ };
8339
+ });
8340
+ },
8287
8341
  staleTime: 1 * TIME.DAY,
8288
8342
  });
8289
8343
  }
@@ -8308,16 +8362,35 @@ function GlyphsArrowSemiBoldRightIcon(props) {
8308
8362
  return (jsx("svg", { xmlns: "http://www.w3.org/2000/svg", ...props, fill: "currentColor", height: "11", viewBox: "0 0 11 11", width: "11", children: jsx("path", { d: "M4.27243829,10 C4.05910402,10.0007527 3.92860879,9.73966348 4.04161427,9.53832073 L6.25359309,5.59919963 C6.37846177,5.37673437 6.36029412,5.09278754 6.20830955,4.89272723 L4.38978231,2.4963789 C4.24091607,2.30024134 4.36625928,2 4.59701551,2 L6.06357848,2 C6.14343478,2 6.2192237,2.03915207 6.27074389,2.10704584 L7.47868905,3.69877757 C8.09849054,4.51523787 8.1726525,5.67297753 7.66341606,6.57973654 L5.82495864,9.85357414 C5.77553993,9.94153429 5.68904024,9.99509493 5.59582936,9.99539668 L4.27243829,10 Z", fillRule: "evenodd" }) }));
8309
8363
  }
8310
8364
 
8365
+ function SolidEventIcon(props) {
8366
+ return (jsx("svg", { height: "24", viewBox: "0 0 24 24", width: "24", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { d: "M5.151 21h13.708C20.956 21 22 19.983 22 17.969V6.031C22 4.017 20.956 3 18.859 3H5.151C3.054 3 2 4.007 2 6.031v11.938C2 19.993 3.054 21 5.151 21zm-.15-1.574c-.894 0-1.385-.46-1.385-1.369v-9.22c0-.9.491-1.369 1.385-1.369h13.988c.894 0 1.395.47 1.395 1.369v9.22c0 .91-.501 1.369-1.395 1.369H5.001zm5.047-8.448h.592c.351 0 .462-.098.462-.44v-.577c0-.342-.11-.45-.462-.45h-.592c-.351 0-.471.108-.471.45v.577c0 .342.12.44.471.44zm3.332 0h.592c.351 0 .472-.098.472-.44v-.577c0-.342-.12-.45-.472-.45h-.592c-.351 0-.472.108-.472.45v.577c0 .342.12.44.472.44zm3.331 0h.593c.35 0 .471-.098.471-.44v-.577c0-.342-.12-.45-.471-.45h-.593c-.35 0-.461.108-.461.45v.577c0 .342.11.44.461.44zm-9.994 3.197h.582c.36 0 .471-.097.471-.44v-.576c0-.343-.11-.44-.471-.44h-.582c-.362 0-.472.097-.472.44v.576c0 .343.11.44.472.44zm3.331 0h.592c.351 0 .462-.097.462-.44v-.576c0-.343-.11-.44-.462-.44h-.592c-.351 0-.471.097-.471.44v.576c0 .343.12.44.471.44zm3.332 0h.592c.351 0 .472-.097.472-.44v-.576c0-.343-.12-.44-.472-.44h-.592c-.351 0-.472.097-.472.44v.576c0 .343.12.44.472.44zm3.331 0h.593c.35 0 .471-.097.471-.44v-.576c0-.343-.12-.44-.471-.44h-.593c-.35 0-.461.097-.461.44v.576c0 .343.11.44.461.44zm-9.994 3.207h.582c.36 0 .471-.107.471-.45v-.576c0-.342-.11-.44-.471-.44h-.582c-.362 0-.472.098-.472.44v.577c0 .342.11.45.472.45zm3.331 0h.592c.351 0 .462-.107.462-.45v-.576c0-.342-.11-.44-.462-.44h-.592c-.351 0-.471.098-.471.44v.577c0 .342.12.45.471.45zm3.332 0h.592c.351 0 .472-.107.472-.45v-.576c0-.342-.12-.44-.472-.44h-.592c-.351 0-.472.098-.472.44v.577c0 .342.12.45.472.45z", fill: "currentColor", fillRule: "nonzero" }) }));
8367
+ }
8368
+
8369
+ function SolidNewsIcon(props) {
8370
+ return (jsx("svg", { height: "24", viewBox: "0 0 24 24", width: "24", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { d: "M17.992 3.784c1.64 0 2.453.813 2.453 2.422V18.12c0 1.61-.812 2.414-2.453 2.414H5.632c.61-.336.806-.804.806-1.64V6.206c0-1.61.82-2.422 2.453-2.422zm-5.984 9.132h-2a1 1 0 0 0-1 1v2.5a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1v-2.5a1 1 0 0 0-1-1zm5.271 2.908h-2.558a.72.72 0 1 0 0 1.442h2.558a.72.72 0 0 0 0-1.442zm0-2.941h-2.558a.72.72 0 0 0 0 1.441h2.558a.72.72 0 0 0 0-1.441zm0-2.942H9.721a.72.72 0 1 0 0 1.442h7.558a.72.72 0 0 0 0-1.442zm0-2.941H9.721a.72.72 0 0 0 0 1.441h7.558a.72.72 0 0 0 0-1.441zM2.992 11.402v6.976c0 .57.414.938.961.938.547-.008.961-.368.961-.938V9.933h-.383c-.953 0-1.539.539-1.539 1.469z", fill: "currentColor", fillRule: "nonzero" }) }));
8371
+ }
8372
+
8373
+ function SolidSaleIcon(props) {
8374
+ return (jsx("svg", { height: "24", viewBox: "0 0 24 24", width: "24", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { d: "M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2zm3.45 5.318c-.638 0-1.26.128-1.26.128l-6.582 9.426.04.008c.143.028.648.12 1.188.12a7.52 7.52 0 0 0 1.216-.12l.044-.008 6.582-9.426s-.622-.128-1.228-.128zm.093 5.465c-1.61 0-2.36.754-2.536 1.86l-.08.465c-.19 1.122.351 1.876 1.962 1.876 1.61 0 2.36-.754 2.535-1.876l.08-.465c.175-1.106-.351-1.86-1.961-1.86zm-.24 1.54c.383 0 .51.095.463.32l-.08.465c-.032.224-.175.337-.558.337-.383 0-.494-.113-.462-.337l.08-.465c.047-.225.19-.32.557-.32zM9.646 7c-1.594 0-2.375.754-2.55 1.876l-.064.465c-.176 1.106.366 1.86 1.96 1.86 1.611 0 2.376-.754 2.552-1.86l.064-.465C11.783 7.754 11.257 7 9.646 7zm-.255 1.555c.383 0 .51.097.463.321l-.064.465c-.048.224-.191.337-.574.337-.383 0-.494-.113-.446-.337l.063-.465c.048-.224.192-.32.558-.32z", fill: "currentColor", fillRule: "nonzero" }) }));
8375
+ }
8376
+
8377
+ function SolidTagIcon(props) {
8378
+ return (jsx("svg", { xmlns: "http://www.w3.org/2000/svg", ...props, fill: "currentColor", height: "24", viewBox: "0 0 24 24", width: "24", children: jsx("path", { d: "M12.3939152,3.13425293 L21.8214774,12.5616776 C22.0595075,12.7995703 22.0595075,13.1851489 21.8214774,13.4230416 L13.4230416,21.8214774 C13.3042327,21.9404237 13.1482962,21.9999656 12.9923596,21.9999656 C12.836423,21.9999656 12.6804864,21.9404237 12.5616776,21.8214774 L3.13425293,12.3940527 C1.62191569,10.8815779 1.62191569,8.42069529 3.13425293,6.90835804 L6.90835804,3.13425293 C8.42069529,1.62191569 10.8815779,1.62191569 12.3939152,3.13425293 Z M8.83153453,7.43397705 C8.44568089,7.04812342 7.82028447,7.04812342 7.43443084,7.43397705 C7.04871471,7.81983069 7.04871471,8.44522711 7.43443084,8.83108074 C7.82028447,9.21679687 8.44568089,9.21679687 8.83153453,8.83108074 C9.21738817,8.44522711 9.21738817,7.81983069 8.83153453,7.43397705 Z", fillRule: "evenodd" }) }));
8379
+ }
8380
+
8311
8381
  var styles$C = {"announcement":"announcement-module-Xi0L5","wrapper":"announcement-module-4XVjD","icon":"announcement-module-lxmA2","content":"announcement-module-1Jn7y","title":"announcement-module-8k2rK","text":"announcement-module-yXGsN","close":"announcement-module-gZ9ae","informative":"announcement-module-0LTWL","notice":"announcement-module-Ga3lN","critical":"announcement-module-S3nSW","promo":"announcement-module-E6DqW"};
8312
8382
 
8313
8383
  const iconMap = {
8314
8384
  critical: jsx(SolidAttentionIcon, {}),
8385
+ event: jsx(SolidEventIcon, {}),
8315
8386
  informative: jsx(SolidInformationIcon, {}),
8387
+ new_product_introduction: jsx(SolidTagIcon, {}),
8388
+ news: jsx(SolidNewsIcon, {}),
8316
8389
  notice: jsx(SolidNoticeIcon, {}),
8317
- promo: jsx(SolidInformationIcon, {}),
8390
+ sales: jsx(SolidSaleIcon, {}),
8318
8391
  };
8319
- function Announcement({ announcement: { href, id, text, title, type }, onDismiss, }) {
8320
- return (jsxs(RouteLink, { className: clsx(styles$C.announcement, styles$C[type]), href: href, children: [jsxs("div", { className: styles$C.wrapper, children: [jsx("div", { className: styles$C.icon, children: iconMap[type] }), jsxs("div", { className: styles$C.content, children: [jsx("h2", { className: styles$C.title, children: title }), jsxs("p", { className: styles$C.text, children: [text, jsx(GlyphsArrowSemiBoldRightIcon, {})] })] })] }), jsx("div", { className: styles$C.close, children: jsx(IconButton, { color: "current-color", onClick: () => onDismiss?.(id), children: jsx(StrokeCloseboxIcon, {}) }) })] }));
8392
+ function Announcement({ announcement: { href, id, subType, text, title, type }, onDismiss, }) {
8393
+ return (jsxs(RouteLink, { className: clsx(styles$C.announcement, styles$C[type], styles$C[subType]), href: href, children: [jsxs("div", { className: styles$C.wrapper, children: [jsx("div", { className: styles$C.icon, children: iconMap[subType] }), jsxs("div", { className: styles$C.content, children: [jsx("h2", { className: styles$C.title, children: title }), jsxs("p", { className: styles$C.text, children: [text, jsx(GlyphsArrowSemiBoldRightIcon, {})] })] })] }), jsx("div", { className: styles$C.close, children: jsx(IconButton, { color: "current-color", onClick: () => onDismiss?.(id), children: jsx(StrokeCloseboxIcon, {}) }) })] }));
8321
8394
  }
8322
8395
 
8323
8396
  const now = () => new Date();
@@ -8345,9 +8418,14 @@ var styles$B = {"announcement-provider":"announcement-provider-module-sVIKY","an
8345
8418
  function AnnouncementProvider() {
8346
8419
  const languageCode = useLanguageCode();
8347
8420
  const nodeRef = useRef(null);
8348
- const { data: announcements } = useFetchAnnouncements({
8421
+ const { data: announcements, error } = useFetchAnnouncements({
8349
8422
  languageCode,
8350
8423
  });
8424
+ useEffect(() => {
8425
+ if (!error)
8426
+ return;
8427
+ console.error(error);
8428
+ }, [error]);
8351
8429
  const [dismissedIds, setDismissedIds] = useLocalStorage('dismissedAnnouncementIds', []);
8352
8430
  const filteredAnnouncements = announcements?.filter(({ id }) => !dismissedIds.includes(id));
8353
8431
  return (jsx(TransitionGroup, { className: styles$B['announcement-provider'], children: filteredAnnouncements?.map(announcement => (jsx(CSSTransition, { classNames: {
@@ -10388,7 +10466,9 @@ function ConnectedSearchInput() {
10388
10466
  const t = useFormattedMessage();
10389
10467
  const navigate = useNavigate();
10390
10468
  return (jsx(SearchInput, { autocomplete: autocomplete, formRef: formRef, inputRef: inputRef, onCancel: close, onSubmit: () => {
10391
- navigate(`/search?keyword=${inputRef.current?.value}`);
10469
+ if (!inputRef.current?.value)
10470
+ return;
10471
+ navigate(`/search?keyword=${encodeURIComponent(inputRef.current.value)}`);
10392
10472
  return close();
10393
10473
  }, placeholder: t('What are you searching for?') }));
10394
10474
  }
@@ -10499,7 +10579,7 @@ function StrokeRecentIcon(props) {
10499
10579
  function WithResults() {
10500
10580
  const { state } = useAlgoliaSearch();
10501
10581
  const { close } = useGlobalSearchDisclosure();
10502
- return (jsx("div", { children: jsx(SectionContainer, { buttons: jsxs(RouteButton, { className: clsx(styles$3['show-all-button'], buttonStyles.button, buttonStyles.secondary, buttonStyles.outline, buttonStyles.md), href: `/search?keyword=${state.query}`, onClick: close, children: [jsx(FormattedMessage, { id: "See all results" }), jsx(GlyphsArrowBoldCapsRightIcon, { className: buttonStyles['right-arrow-icon'] })] }), leftContent: jsx(SuggestionsSection, {}), rightContent: jsx(ProductResultsSection, {}) }) }));
10582
+ return (jsx("div", { children: jsx(SectionContainer, { buttons: jsxs(RouteButton, { className: clsx(styles$3['show-all-button'], buttonStyles.button, buttonStyles.secondary, buttonStyles.outline, buttonStyles.md), href: `/search?keyword=${encodeURIComponent(state.query)}`, onClick: close, children: [jsx(FormattedMessage, { id: "See all results" }), jsx(GlyphsArrowBoldCapsRightIcon, { className: buttonStyles['right-arrow-icon'] })] }), leftContent: jsx(SuggestionsSection, {}), rightContent: jsx(ProductResultsSection, {}) }) }));
10503
10583
  }
10504
10584
  function SuggestionsSection() {
10505
10585
  const { autocomplete, categories, querySuggestions, recentSearches } = useAlgoliaSearch();
@@ -0,0 +1 @@
1
+ export declare function PrintButton(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import type { StoryObj } from '@storybook/react';
2
+ import { PrintButton } from './print-button';
3
+ declare const meta: {
4
+ component: typeof PrintButton;
5
+ parameters: {
6
+ layout: string;
7
+ };
8
+ tags: string[];
9
+ title: string;
10
+ };
11
+ export default meta;
12
+ type Story = StoryObj<typeof meta>;
13
+ export declare const Default: Story;
@@ -0,0 +1,6 @@
1
+ import { OrderLineCardProps } from './orderline-card';
2
+ export interface ConnectedOrderLineProps extends Omit<OrderLineCardProps, 'addToCartButton' | 'favoriteButton'> {
3
+ onAddToCart?: VoidFunction;
4
+ onRemove?: (productId: string) => void;
5
+ }
6
+ export declare function ConnectedOrderLineCard({ id, onRemove, ...props }: ConnectedOrderLineProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ export interface ConnectedRemoveButtonProps {
2
+ onRemove: (productId: string) => void;
3
+ productId: string;
4
+ }
5
+ export declare function ConnectedRemoveButton({ onRemove: _onRemove, productId, }: ConnectedRemoveButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,25 @@
1
+ import { ReactElement } from 'react';
2
+ import { ImageSource } from 'shared/model/image';
3
+ import type { ProductTotalPrice as ProductTotalPriceType } from 'shared/model/price';
4
+ export interface BaseOrderLineCardProps {
5
+ deliveryDate?: Date;
6
+ href: string;
7
+ id: string;
8
+ image: ImageSource;
9
+ price: ProductTotalPriceType;
10
+ readonly: boolean;
11
+ sku: string;
12
+ tags?: string[];
13
+ title: string;
14
+ }
15
+ export interface InteractiveOrderLineCardProps extends BaseOrderLineCardProps {
16
+ addToCartButton: ReactElement;
17
+ readonly: false;
18
+ removeButton: ReactElement;
19
+ }
20
+ export interface ReadonlyOrderLineCardProps extends BaseOrderLineCardProps {
21
+ quantity: number;
22
+ readonly: true;
23
+ }
24
+ export type OrderLineCardProps = InteractiveOrderLineCardProps | ReadonlyOrderLineCardProps;
25
+ export declare function OrderLineCard(props: OrderLineCardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,46 @@
1
+ import type { StoryObj } from '@storybook/react';
2
+ import { OrderLineCard } from './orderline-card';
3
+ declare const meta: {
4
+ component: typeof OrderLineCard;
5
+ decorators: ((Story: import("@storybook/csf").PartialStoryFn<import("@storybook/react").ReactRenderer, {
6
+ addToCartButton: React.ReactElement;
7
+ readonly: false;
8
+ removeButton: React.ReactElement;
9
+ deliveryDate?: Date | undefined;
10
+ href: string;
11
+ id: string;
12
+ image: import("../../shared/model/image").ImageSource;
13
+ price: import("../../shared/model/price").ProductTotalPrice;
14
+ sku: string;
15
+ tags?: string[] | undefined;
16
+ title: string;
17
+ } | {
18
+ quantity: number;
19
+ readonly: true;
20
+ deliveryDate?: Date | undefined;
21
+ href: string;
22
+ id: string;
23
+ image: import("../../shared/model/image").ImageSource;
24
+ price: import("../../shared/model/price").ProductTotalPrice;
25
+ sku: string;
26
+ tags?: string[] | undefined;
27
+ title: string;
28
+ }>) => import("react/jsx-runtime").JSX.Element)[];
29
+ parameters: {
30
+ layout: string;
31
+ };
32
+ tags: string[];
33
+ title: string;
34
+ };
35
+ export default meta;
36
+ type Story = StoryObj<typeof OrderLineCard>;
37
+ export declare const Default: Story;
38
+ export declare const Small: Story;
39
+ export declare const Medium: Story;
40
+ export declare const Large: Story;
41
+ export declare const LongTitle: Story;
42
+ export declare const BigPrice: Story;
43
+ export declare const WithoutTags: Story;
44
+ export declare const ReadOnly: Story;
45
+ export declare const ReadOnlyNoTag: Story;
46
+ export declare const Connected: Story;
@@ -0,0 +1,12 @@
1
+ import { ReactElement } from 'react';
2
+ export interface CartTotalsProps {
3
+ buttons?: ReactElement;
4
+ fulfillmentMethod?: string;
5
+ orderNumber?: string;
6
+ shippingCost: string;
7
+ subtotal: string;
8
+ tax: string;
9
+ total: string;
10
+ vatPercentage: number;
11
+ }
12
+ export declare function CartTotals({ buttons, fulfillmentMethod, orderNumber, shippingCost, subtotal, tax, total, vatPercentage, }: CartTotalsProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,16 @@
1
+ import type { StoryObj } from '@storybook/react';
2
+ import { CartTotals } from './cart-totals';
3
+ declare const meta: {
4
+ component: typeof CartTotals;
5
+ parameters: {
6
+ layout: string;
7
+ };
8
+ tags: string[];
9
+ title: string;
10
+ };
11
+ export default meta;
12
+ type Story = StoryObj<typeof meta>;
13
+ export declare const Cart: Story;
14
+ export declare const Shipping: Story;
15
+ export declare const ReviewAndPayment: Story;
16
+ export declare const OrderConfirmation: Story;
@@ -1,7 +1,9 @@
1
1
  import { Country, Language } from 'shared/model/countries-languages';
2
2
  export interface CountrySelectorDialogProps {
3
3
  countries: Country[];
4
+ isDismissable?: boolean;
4
5
  isOpen: boolean;
6
+ onOpenChange?: (isOpen: boolean) => void;
5
7
  onSubmit: ({ country, language, }: {
6
8
  country: Country;
7
9
  language: Language;
@@ -10,4 +12,4 @@ export interface CountrySelectorDialogProps {
10
12
  selectedLanguage: Language;
11
13
  showCountry?: boolean;
12
14
  }
13
- export declare function CountrySelectorDialog({ countries, isOpen, onSubmit, selectedCountry, selectedLanguage, showCountry, }: CountrySelectorDialogProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function CountrySelectorDialog({ countries, isDismissable, isOpen, onOpenChange, onSubmit, selectedCountry, selectedLanguage, showCountry, }: CountrySelectorDialogProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ export interface DeliveryTimeProps {
2
+ className?: string;
3
+ deliveryDate: Date;
4
+ }
5
+ export declare function DeliveryTime({ className, deliveryDate }: DeliveryTimeProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import type { StoryObj } from '@storybook/react';
2
+ import { DeliveryTime } from './delivery-time';
3
+ declare const meta: {
4
+ component: typeof DeliveryTime;
5
+ parameters: {
6
+ layout: string;
7
+ };
8
+ tags: string[];
9
+ title: string;
10
+ };
11
+ export default meta;
12
+ type Story = StoryObj<typeof meta>;
13
+ export declare const Default: Story;
@@ -1,7 +1,8 @@
1
1
  export interface ProductPriceProps {
2
2
  className?: string;
3
- isVatIncluded: boolean;
3
+ isVatIncluded: boolean | null;
4
4
  originalPrice: number;
5
5
  price: number;
6
+ pricePerUnit?: number;
6
7
  }
7
8
  export declare function ProductPrice({ className, isVatIncluded, originalPrice, price, }: ProductPriceProps): import("react/jsx-runtime").JSX.Element | undefined;
@@ -0,0 +1,7 @@
1
+ export interface ProductTotalPriceProps {
2
+ className?: string;
3
+ originalTotalPrice: number;
4
+ pricePerUnit?: number;
5
+ totalPrice: number;
6
+ }
7
+ export declare function ProductTotalPrice({ className, originalTotalPrice: originalPrice, pricePerUnit, totalPrice, }: ProductTotalPriceProps): import("react/jsx-runtime").JSX.Element | undefined;
@@ -0,0 +1,14 @@
1
+ import type { StoryObj } from '@storybook/react';
2
+ import { ProductTotalPrice } from './product-total-price';
3
+ declare const meta: {
4
+ component: typeof ProductTotalPrice;
5
+ parameters: {
6
+ layout: string;
7
+ };
8
+ tags: string[];
9
+ title: string;
10
+ };
11
+ export default meta;
12
+ type Story = StoryObj<typeof meta>;
13
+ export declare const WithoutOriginalTotalPrice: Story;
14
+ export declare const WithOriginalTotalPrice: Story;
@@ -0,0 +1 @@
1
+ export declare function SolidEventIcon(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function SolidNewsIcon(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function SolidSaleIcon(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- export type TranslationId = "'{0}' in all products" | "Try 'Search' and try to find the product you're looking for" | "Unfortnately, We found no articles for your search '{0}'" | ' to your account to manage your lists.' | 'Add to list' | 'An unexpected error occured' | 'Are you looking for information about our service? Please visit our customer support page' | 'Cancel' | 'Chosen filters' | 'Clear filters' | 'Clear' | 'Continue shopping' | 'Country' | 'Create new list' | 'create account' | 'Double check your spelling' | 'Downloads' | 'Excl. VAT' | 'Explore by categories' | 'Exploring our products by category' | 'Features' | 'Hide filters' | 'Incl. VAT' | 'Includes' | 'Language' | 'List name already exists' | 'New list name' | 'Please Sign In' | 'Popular searches' | 'Product Features' | 'Products' | 'Quick access' | 'Recent searches' | 'Recently viewed' | 'Searching again using more general terms' | 'See all results' | 'Select a list' | 'Shop more efficiently and quicker with a favorites list' | 'Easily add your favorite products' | 'Your favorites are available on multiple devices' | 'Save' | 'Share your favorite list with others' | 'Show all' | 'Show filters' | 'Show less' | 'Show' | 'Sorry, there are no products found' | 'Sorry, we could not find matches for' | 'Sort by' | 'Specifications' | 'Submit' | 'Suggestions' | 'The product has been added to your cart.' | 'The product has been updated in your cart.' | 'The product has been removed from your cart.' | 'Unable to add the product to your cart.' | 'Unable to update the product in your cart.' | 'Unable to remove the product from your cart.' | 'Try another search' | 'Use fewer keywords' | 'Welcome to Sonic Equipment. Please choose your country and language below.' | 'What are you searching for?' | 'You could try checking the spelling of your search query' | 'You could try exploring our products by category' | 'You could try' | 'You must ' | 'article' | 'articles' | 'facet.categories' | 'facet.height' | 'facet.weight' | 'of' | 'sign in' | 'sort.newest' | 'sort.price_asc' | 'sort.price_desc' | 'sort.relevance' | 'tag.limited' | 'tag.new';
1
+ export type TranslationId = "'{0}' in all products" | "Try 'Search' and try to find the product you're looking for" | "Unfortnately, We found no articles for your search '{0}'" | ' to your account to manage your lists.' | 'Add to list' | 'Amount: {0}' | 'An unexpected error occured' | 'Are you looking for information about our service? Please visit our customer support page' | 'Are you sure you want to remove all items from your cart?' | 'Are you sure you want to remove this item from your cart?' | 'Cancel' | 'Chosen filters' | 'Clear filters' | 'Clear' | 'Continue' | 'Continue shopping' | 'Cost overview' | 'Country' | 'Create new list' | 'create account' | 'Delivery expected in {0} {1}' | 'Double check your spelling' | 'Downloads' | 'Excl. VAT' | 'Explore by categories' | 'Exploring our products by category' | 'Features' | 'Fulfillment method' | 'Hide filters' | 'Incl. VAT' | 'Includes' | 'Language' | 'List name already exists' | 'New list name' | 'Order number' | 'pc' | 'Please Sign In' | 'Popular searches' | 'Print' | 'Product Features' | 'Products' | 'Product' | 'Quick access' | 'Recent searches' | 'Recently viewed' | 'Remove all' | 'Searching again using more general terms' | 'See all results' | 'Select a list' | 'Shop more efficiently and quicker with a favorites list' | 'Easily add your favorite products' | 'Your favorites are available on multiple devices' | 'Save' | 'Share your favorite list with others' | 'Shipping and handling' | 'Show all' | 'Show filters' | 'Show less' | 'Show' | 'Sorry, there are no products found' | 'Sorry, we could not find matches for' | 'Sort by' | 'Specifications' | 'Submit' | 'Subtotal' | 'Suggestions' | 'The product has been added to your cart.' | 'The product has been updated in your cart.' | 'The product has been removed from your cart.' | 'Unable to add the product to your cart.' | 'Unable to update the product in your cart.' | 'Unable to remove the product from your cart.' | 'Try another search' | 'Total' | 'Use fewer keywords' | 'VAT' | 'Welcome to Sonic Equipment. Please choose your country and language below.' | 'What are you searching for?' | 'You could try checking the spelling of your search query' | 'You could try exploring our products by category' | 'You could try' | 'You must ' | 'article' | 'articles' | 'facet.categories' | 'facet.height' | 'facet.weight' | 'of' | 'sign in' | 'sort.newest' | 'sort.price_asc' | 'sort.price_desc' | 'sort.relevance' | 'tag.limited' | 'tag.new';
@@ -1,7 +1,13 @@
1
1
  import { TranslationId } from './translation-id';
2
- export type FormattedMessageFunction = (id: TranslationId, options?: {
3
- fallbackValue?: string;
4
- optional?: boolean;
5
- replacementValues?: Record<string, string>;
6
- }) => string;
2
+ export interface FormattedMessageFunction {
3
+ (id: TranslationId, options?: {
4
+ fallbackValue?: string;
5
+ optional?: boolean;
6
+ replacementValues?: Record<string, string>;
7
+ }): string;
8
+ pluralize: {
9
+ (translationId: string, count: number): string;
10
+ (translationIdPrefix: string, translationId: string, count: number): string;
11
+ };
12
+ }
7
13
  export declare function useFormattedMessage(): FormattedMessageFunction;
@@ -0,0 +1,7 @@
1
+ import { ReactNode } from 'react';
2
+ interface OrderLineListProps {
3
+ children?: ReactNode;
4
+ onRemoveAll?: () => void;
5
+ }
6
+ export declare function OrderLineList({ children, onRemoveAll }: OrderLineListProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,15 @@
1
+ import type { StoryObj } from '@storybook/react';
2
+ import { OrderLineList } from './orderline-list';
3
+ declare const meta: {
4
+ component: typeof OrderLineList;
5
+ parameters: {
6
+ layout: string;
7
+ };
8
+ title: string;
9
+ };
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+ export declare const Small: Story;
13
+ export declare const Medium: Story;
14
+ export declare const Large: Story;
15
+ export declare const Connected: Story;
@@ -0,0 +1,10 @@
1
+ interface ConfirmationDialogProps {
2
+ cancelLabel?: string;
3
+ isOpen: boolean;
4
+ onCancel: VoidFunction;
5
+ onConfirm: VoidFunction;
6
+ submitLabel?: string;
7
+ title: string;
8
+ }
9
+ export declare function ConfirmationDialog({ cancelLabel, isOpen, onCancel, onConfirm, submitLabel, title, }: ConfirmationDialogProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
@@ -0,0 +1,19 @@
1
+ import type { StoryObj } from '@storybook/react';
2
+ import { ConfirmationDialog } from './confirmation-dialog';
3
+ declare const meta: {
4
+ argTypes: {
5
+ isOpen: {
6
+ control: {
7
+ type: "boolean";
8
+ };
9
+ };
10
+ };
11
+ component: typeof ConfirmationDialog;
12
+ parameters: {
13
+ layout: string;
14
+ };
15
+ title: string;
16
+ };
17
+ export default meta;
18
+ type Story = StoryObj<typeof meta>;
19
+ export declare const Default: Story;
@@ -3,17 +3,22 @@ import { Form as AriaForm } from 'react-aria-components';
3
3
  import { ModalProps } from 'modals/modal/modal';
4
4
  interface DialogProps extends Omit<ModalProps, 'children'> {
5
5
  allowClose?: boolean;
6
- children: ReactNode | ((props: {
6
+ cancelLabel?: string;
7
+ children?: ReactNode | ((props: {
7
8
  close: VoidFunction;
8
9
  }) => ReactNode);
9
10
  dialogClassName?: string;
10
- footer?: ReactNode | ((props: {
11
- close: VoidFunction;
12
- }) => ReactNode);
11
+ footer?: ReactNode | ((props: DialogFooterProps) => ReactNode);
13
12
  hideTitle?: boolean;
14
13
  onSubmit?: (e: React.FormEvent<HTMLFormElement>) => void;
14
+ submitLabel?: string;
15
15
  title: string;
16
16
  validationErrors?: ComponentProps<typeof AriaForm>['validationErrors'];
17
17
  }
18
- export declare function Dialog({ allowClose, children, className, dialogClassName, footer, hasCloseButton, hideTitle, isDismissable, isFullScreen, isKeyboardDismissDisabled, isOpen, onOpenChange, onSubmit, shouldCloseOnInteractOutside, title, validationErrors, }: DialogProps): import("react/jsx-runtime").JSX.Element;
18
+ interface DialogFooterProps {
19
+ cancelLabel: string;
20
+ close: VoidFunction;
21
+ submitLabel: string;
22
+ }
23
+ export declare function Dialog({ allowClose, cancelLabel, children, className, dialogClassName, footer, hasCloseButton, hideTitle, isDismissable, isFullScreen, isKeyboardDismissDisabled, isOpen, onOpenChange, onSubmit, shouldCloseOnInteractOutside, submitLabel, title, validationErrors, }: DialogProps): import("react/jsx-runtime").JSX.Element;
19
24
  export {};
@@ -7,7 +7,7 @@ export interface ModalProps {
7
7
  isFullScreen?: boolean;
8
8
  isKeyboardDismissDisabled?: boolean;
9
9
  isOpen: boolean;
10
- onOpenChange: (isOpen: boolean) => void;
10
+ onOpenChange?: (isOpen: boolean) => void;
11
11
  shouldCloseOnInteractOutside?: boolean;
12
12
  }
13
13
  export declare function Modal({ children, className, hasCloseButton, isDismissable, isFullScreen, isKeyboardDismissDisabled, isOpen, onOpenChange, shouldCloseOnInteractOutside, }: ModalProps): import("react/jsx-runtime").JSX.Element;
@@ -3,4 +3,4 @@ export interface AnnouncementProps {
3
3
  announcement: AnnouncementType;
4
4
  onDismiss?: (id: string) => void;
5
5
  }
6
- export declare function Announcement({ announcement: { href, id, text, title, type }, onDismiss, }: AnnouncementProps): import("react/jsx-runtime").JSX.Element;
6
+ export declare function Announcement({ announcement: { href, id, subType, text, title, type }, onDismiss, }: AnnouncementProps): import("react/jsx-runtime").JSX.Element;
@@ -1,6 +1,5 @@
1
1
  import type { StoryObj } from '@storybook/react';
2
2
  import { Announcement } from './announcement';
3
- import { AnnouncementProvider } from './announcement-provider';
4
3
  declare const meta: {
5
4
  component: typeof Announcement;
6
5
  parameters: {
@@ -11,8 +10,13 @@ declare const meta: {
11
10
  };
12
11
  export default meta;
13
12
  type Story = StoryObj<typeof meta>;
14
- export declare const Promo: Story;
15
- export declare const Informative: Story;
16
- export declare const Notice: Story;
17
- export declare const Critical: Story;
18
- export declare const Connected: StoryObj<typeof AnnouncementProvider>;
13
+ export declare const PromoNewProductIntroduction: Story;
14
+ export declare const PromoEvent: Story;
15
+ export declare const PromoSale: Story;
16
+ export declare const PromoNews: Story;
17
+ export declare const ServiceInformative: Story;
18
+ export declare const ServiceNotice: Story;
19
+ export declare const ServiceCritical: Story;
20
+ export declare const Connected: StoryObj<{
21
+ languageCode: string;
22
+ }>;
@@ -3,6 +3,7 @@ interface Announcement {
3
3
  href: string;
4
4
  id: string;
5
5
  startDate?: string;
6
+ subType: string;
6
7
  text: string;
7
8
  title: string;
8
9
  type: string;
@@ -0,0 +1,10 @@
1
+ import { AnnouncementResponse } from 'shared/api/bff/model/announcement.model';
2
+ export interface FetchAnnouncementsArgs {
3
+ languageCode: string;
4
+ }
5
+ export declare function fetchAnnouncements({ languageCode, }: FetchAnnouncementsArgs): Promise<{
6
+ body: string | AnnouncementResponse;
7
+ headers: Headers;
8
+ status: number;
9
+ statusText: string;
10
+ }>;
@@ -1,7 +1,6 @@
1
1
  declare const features: {
2
2
  readonly language: "language";
3
3
  readonly pdp: "pdpV2";
4
- readonly pdpv1: "pdpV1";
5
4
  readonly plpv1: "plpV1";
6
5
  readonly searchv1: "searchV1";
7
6
  };
@@ -1,13 +1,16 @@
1
- export declare const announcementTypes: readonly ["promo", "informative", "notice", "critical"];
2
- type AnnouncementType = (typeof announcementTypes)[number];
1
+ export declare const announcementTypes: readonly ["promo", "service"];
2
+ export type AnnouncementType = (typeof announcementTypes)[number];
3
+ export declare const announcementSubTypes: readonly ["sales", "news", "critical", "informative", "notice", "event", "new_product_introduction"];
4
+ export type AnnouncementSubType = (typeof announcementSubTypes)[number];
3
5
  export interface Announcement {
4
6
  endDate?: Date;
5
7
  href: string;
6
8
  id: string;
7
9
  startDate?: Date;
10
+ subType: AnnouncementSubType;
8
11
  text: string;
9
12
  title: string;
10
13
  type: AnnouncementType;
11
14
  }
12
15
  export declare function isAnnouncementType(type: string): type is AnnouncementType;
13
- export {};
16
+ export declare function isAnnouncementSubtype(subtype: string): subtype is AnnouncementSubType;
@@ -3,3 +3,8 @@ export interface ProductPrice {
3
3
  originalPrice: number;
4
4
  price: number;
5
5
  }
6
+ export interface ProductTotalPrice {
7
+ originalTotalPrice: number;
8
+ pricePerUnit?: number;
9
+ totalPrice: number;
10
+ }
@@ -0,0 +1,11 @@
1
+ export type DateUnit = 'day' | 'week' | 'month';
2
+ export type DateUnitObject = {
3
+ number: number;
4
+ unit: DateUnit;
5
+ };
6
+ export type DateThreshold = {
7
+ dateUnitObject: DateUnitObject;
8
+ numberOfDays: number;
9
+ };
10
+ export declare function getDateUnitObject(date: Date): DateUnitObject;
11
+ export declare function convertDateUnitToPluralOrSingle(unit: DateUnit, number: number): 'day' | 'days' | 'week' | 'weeks' | 'month' | 'months';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export declare const formatPrice: (price: number) => string;
@@ -1,4 +1,4 @@
1
- export declare const SIZES: readonly ["xxl", "xl", "l", "m", "s", "xs", "xxs"];
1
+ export declare const SIZES: readonly ["xxl", "xl", "l", "m", "s", "xs", "xxs", "xxxs"];
2
2
  export declare const TAGS: readonly ["h1", "h2", "h3", "h4", "h5", "h6", "h7"];
3
3
  type Size = (typeof SIZES)[number];
4
4
  type Tag = (typeof TAGS)[number];
@@ -8,7 +8,7 @@ declare const meta: {
8
8
  };
9
9
  description: string;
10
10
  name: string;
11
- options: ("xl" | "xxl" | "s" | "l" | "m" | "xs" | "xxs")[];
11
+ options: ("xl" | "xxl" | "s" | "l" | "m" | "xs" | "xxs" | "xxxs")[];
12
12
  };
13
13
  tag: {
14
14
  control: {
package/dist/styles.css CHANGED
@@ -37,6 +37,7 @@
37
37
  --font-weight-base: var(--font-weight-normal);
38
38
 
39
39
  /* line heights */
40
+ --line-height-20: 1.25rem;
40
41
  --line-height-22: 1.375rem;
41
42
  --line-height-24: 1.5rem;
42
43
  --line-height-28: 1.75rem;
@@ -88,6 +89,10 @@
88
89
  --text-heading-xxs-size: var(--font-size-24);
89
90
  --text-heading-xxs-line-height: var(--line-height-22);
90
91
  --text-heading-xxs-line-height-uppercase: var(--line-height-24);
92
+
93
+ /* headings xxxs */
94
+ --text-heading-xxxs-size: var(--font-size-20);
95
+ --text-heading-xxxs-line-height: var(--line-height-20);
91
96
  }
92
97
  :root {
93
98
  /*********************************************************
@@ -143,6 +148,7 @@
143
148
  --color-red-950: #4d0206;
144
149
 
145
150
  /* Neutrals */
151
+ --color-gray-25: #00000019;
146
152
  --color-gray-50: #fbfbfb;
147
153
  --color-gray-75: #f6f6f6;
148
154
  --color-gray-100: #ededed;
@@ -230,8 +236,9 @@
230
236
  --background-overlay-layer: 90;
231
237
  --sidebar-layer: 100;
232
238
  --search-layer: 200;
233
- --modal-layer: 300;
234
- --zoom-image-layer: 400;
239
+ --sticky-bottom-price: 1300;
240
+ --modal-layer: 2000;
241
+ --zoom-image-layer: 2100;
235
242
  }
236
243
  :root {
237
244
  --header-height-desktop: 96px;
@@ -945,6 +952,7 @@
945
952
 
946
953
  .product-price-module-oIU1K {
947
954
  --current-price-color: var(--color-brand-black);
955
+ --original-price-font-size: var(--font-size-18);
948
956
  --current-price-font-style: normal;
949
957
  --font-size-wholes: var(--price-font-size-wholes, var(--font-size-36));
950
958
  --font-size-decimals: var(--price-font-size-decimals, var(--font-size-24));
@@ -957,7 +965,7 @@
957
965
  .product-price-module-oIU1K .product-price-module-til0s {
958
966
  padding-left: var(--space-4);
959
967
  color: var(--color-brand-dark-gray);
960
- font-size: var(--font-size-18);
968
+ font-size: var(--original-price-font-size);
961
969
  font-weight: var(--font-weight-bold);
962
970
  text-decoration: line-through;
963
971
  }
@@ -978,14 +986,14 @@
978
986
  position: relative;
979
987
  display: flex;
980
988
  color: var(--current-price-color);
981
- font-size: var(--font-size-36);
989
+ font-size: var(--font-size-wholes);
982
990
  font-style: var(--current-price-font-style);
983
991
  font-weight: var(--font-weight-black);
984
992
  }
985
993
 
986
994
  .product-price-module-oIU1K .product-price-module-pvy2w .product-price-module-GCw07,
987
995
  .product-price-module-oIU1K .product-price-module-pvy2w .product-price-module-N56iV {
988
- font-size: var(--font-size-wholes);
996
+ font-size: inherit;
989
997
  font-weight: inherit;
990
998
  }
991
999
 
@@ -997,6 +1005,7 @@
997
1005
  font-weight: inherit;
998
1006
  }
999
1007
 
1008
+ .product-price-module-oIU1K .product-price-module-syhum,
1000
1009
  .product-price-module-oIU1K .product-price-module-96DoG {
1001
1010
  color: var(--color-brand-dark-gray);
1002
1011
  font-size: var(--font-size-12);
@@ -2175,6 +2184,11 @@
2175
2184
  line-height: var(--text-heading-xxs-line-height-uppercase);
2176
2185
  }
2177
2186
 
2187
+ .heading-module-pMC65:where(.heading-module-qvrEk) {
2188
+ font-size: var(--text-heading-xxxs-size);
2189
+ line-height: var(--text-heading-xxxs-line-height);
2190
+ }
2191
+
2178
2192
  .dialog-module-qKzgy {
2179
2193
  position: relative;
2180
2194
  padding: var(--space-24);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonic-equipment/ui",
3
- "version": "0.0.111",
3
+ "version": "0.0.113",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -36,7 +36,8 @@
36
36
  "start": "http-server ./storybook-static",
37
37
  "stylelint": "stylelint --config .stylelintrc.cjs \"src/**/*.css\"",
38
38
  "stylelint:fix": "stylelint --config .stylelintrc.cjs \"src/**/*.css\" --formatter verbose --fix",
39
- "test:all": "npx concurrently -g --names \"TSC,ESLINT,STYLELINT\" -c auto --kill-others-on-fail \"npm run test:types\" \"npm run lint\" \"npm run stylelint\"",
39
+ "test:all": "npx concurrently -g --names \"TSC,VITEST,ESLINT,STYLELINT\" -c auto --kill-others-on-fail \"npm run test:types\" \"npm run test:unit\" \"npm run lint\" \"npm run stylelint\"",
40
+ "test:unit": "vitest run",
40
41
  "test:types": "tsc --noEmit --pretty false",
41
42
  "update-packages": "npx npm-check-updates -u"
42
43
  },
@@ -69,6 +70,7 @@
69
70
  "@storybook/test": "8.4.2",
70
71
  "@types/js-cookie": "3.0.6",
71
72
  "@types/node": "22.9.0",
73
+ "@types/postcss-import": "14.0.3",
72
74
  "@types/react": "18.3.12",
73
75
  "@types/react-dom": "18.3.1",
74
76
  "@typescript-eslint/eslint-plugin": "8.13.0",
@@ -113,7 +115,8 @@
113
115
  "stylelint-config-standard": "36.0.1",
114
116
  "typescript": "5.6.3",
115
117
  "vite": "5.4.10",
116
- "vite-tsconfig-paths": "5.1.0"
118
+ "vite-tsconfig-paths": "5.1.0",
119
+ "vitest": "2.1.5"
117
120
  },
118
121
  "dependencies": {
119
122
  "@algolia/autocomplete-core": "1.17.7",