@sonic-equipment/ui 135.0.0 → 136.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 (35) hide show
  1. package/dist/algolia/algolia-initialization.js +2 -1
  2. package/dist/algolia/algolia-insights-provider.js +3 -3
  3. package/dist/algolia/algolia-searchclient-offline.js +3 -2
  4. package/dist/algolia/use-algolia-insights.js +24 -23
  5. package/dist/buttons/link/link.d.ts +2 -1
  6. package/dist/buttons/link/link.js +4 -2
  7. package/dist/collapsables/accordion/accordion-item.d.ts +2 -1
  8. package/dist/collapsables/accordion/accordion-item.js +13 -4
  9. package/dist/exports.d.ts +4 -0
  10. package/dist/footer/footer.d.ts +9 -0
  11. package/dist/footer/footer.js +14 -0
  12. package/dist/footer/footer.model.d.ts +18 -0
  13. package/dist/footer/footer.module.css.js +3 -0
  14. package/dist/index.js +4 -0
  15. package/dist/intl/utils.js +2 -1
  16. package/dist/logging/logger.d.ts +11 -0
  17. package/dist/logging/logger.js +22 -0
  18. package/dist/logging/use-log-error.d.ts +1 -0
  19. package/dist/logging/use-log-error.js +12 -0
  20. package/dist/notifications/announcements/announcement-provider.js +3 -6
  21. package/dist/pages/checkout/payment-page/components/adyen-payment.js +34 -24
  22. package/dist/pages/checkout/payment-page/components/payment.js +29 -17
  23. package/dist/pages/checkout/shipping-page/components/edit-address.d.ts +3 -2
  24. package/dist/pages/checkout/shipping-page/components/edit-address.js +5 -5
  25. package/dist/pages/checkout/shipping-page/shipping-page-content.d.ts +2 -1
  26. package/dist/pages/checkout/shipping-page/shipping-page-content.js +2 -2
  27. package/dist/pages/checkout/shipping-page/shipping-page.js +3 -2
  28. package/dist/pages/product/search-result-page/search-results-page.js +1 -1
  29. package/dist/shared/ga/data-layer.js +3 -2
  30. package/dist/shared/providers/global-state-provider.js +3 -5
  31. package/dist/shared/utils/debug.d.ts +2 -0
  32. package/dist/shared/utils/debug.js +21 -0
  33. package/dist/shared/utils/environment.js +4 -2
  34. package/dist/styles.css +104 -11
  35. package/package.json +1 -1
@@ -2,6 +2,7 @@
2
2
  import { config } from '../config.js';
3
3
  import Cookies from 'js-cookie';
4
4
  import aa from 'search-insights';
5
+ import { logger } from '../logging/logger.js';
5
6
  import { request } from '../shared/fetch/request.js';
6
7
  import { createUUID } from '../shared/utils/uuid.js';
7
8
 
@@ -14,7 +15,7 @@ aa('init', {
14
15
  });
15
16
  aa('getUserToken', {}, (err, value) => {
16
17
  if (err)
17
- return console.error(err);
18
+ return logger.error(err);
18
19
  userToken = value === undefined ? generateUserToken() : String(value);
19
20
  });
20
21
  aa('onUserTokenChange', value => {
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx } from 'react/jsx-runtime';
3
- import { createContext, useContext } from 'react';
3
+ import { createContext, useContext, useMemo } from 'react';
4
4
  import { useCultureCode } from '../intl/use-culture-code.js';
5
5
  import { getLanguageCodeFromCultureCode } from '../intl/utils.js';
6
6
  import { environment } from '../shared/utils/environment.js';
@@ -13,12 +13,12 @@ function AlgoliaInsightsProvider({ children, value, }) {
13
13
  const algoliaIndex = getAlgoliaIndex(environment, getLanguageCodeFromCultureCode(cultureCode));
14
14
  const [globalState] = useAlgoliaInsightsGlobalState();
15
15
  const context = useContext(AlgoliaInsightsProviderContext);
16
- const combinedValue = {
16
+ const combinedValue = useMemo(() => ({
17
17
  index: algoliaIndex.default,
18
18
  ...globalState,
19
19
  ...context,
20
20
  ...value,
21
- };
21
+ }), [algoliaIndex.default, context, globalState, value]);
22
22
  return (jsx(AlgoliaInsightsProviderContext.Provider, { value: combinedValue, children: children }));
23
23
  }
24
24
 
@@ -1,11 +1,12 @@
1
1
  "use client";
2
+ import { logger } from '../logging/logger.js';
3
+
2
4
  const searchClientLogger = (searchClient) => {
3
5
  return {
4
6
  ...searchClient,
5
7
  search: (async (queries, requestOptions) => {
6
8
  const response = await searchClient.search(queries, requestOptions);
7
- // eslint-disable-next-line no-console
8
- console.log('Algolia::SearchClient::search', {
9
+ logger.info('Algolia::SearchClient::search', {
9
10
  args: { queries, requestOptions },
10
11
  response,
11
12
  });
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { useContext, useMemo } from 'react';
3
3
  import aa from 'search-insights';
4
+ import { logger } from '../logging/logger.js';
4
5
  import { currencySymbolToISO } from '../shared/model/currency.js';
5
6
  import { ensureArray } from '../shared/utils/array.js';
6
7
  import { userToken } from './algolia-initialization.js';
@@ -18,7 +19,7 @@ function useAlgoliaInsights() {
18
19
  context,
19
20
  sendAddToCartFromProductDetailsPageEvent({ cartLine }) {
20
21
  if (!context.index)
21
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
22
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
22
23
  if (context.queryId) {
23
24
  aa('addedToCartObjectIDsAfterSearch', {
24
25
  currency: getCurrencyFromPriceString(cartLine.pricing?.actualPriceDisplay),
@@ -55,9 +56,9 @@ function useAlgoliaInsights() {
55
56
  },
56
57
  sendAddToCartFromProductListPageEvent({ cartLine }) {
57
58
  if (!context.index)
58
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
59
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
59
60
  if (!context.queryId)
60
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no queryId', context);
61
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no queryId', context);
61
62
  aa('addedToCartObjectIDsAfterSearch', {
62
63
  currency: getCurrencyFromPriceString(cartLine.pricing?.actualPriceDisplay),
63
64
  eventName: 'PLP: AddToCart ClickedAfterSearch',
@@ -76,7 +77,7 @@ function useAlgoliaInsights() {
76
77
  },
77
78
  sendAddToCartFromSearchEvent({ cartLine, queryId }) {
78
79
  if (!context.index)
79
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
80
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
80
81
  aa('addedToCartObjectIDsAfterSearch', {
81
82
  currency: getCurrencyFromPriceString(cartLine.pricing?.actualPriceDisplay),
82
83
  eventName: 'SRP: AddToCart ClickedAfterSearch',
@@ -95,9 +96,9 @@ function useAlgoliaInsights() {
95
96
  },
96
97
  sendAddToCartFromSearchResultPageEvent({ cartLine }) {
97
98
  if (!context.index)
98
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
99
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
99
100
  if (!context.queryId)
100
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no queryId', context);
101
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no queryId', context);
101
102
  aa('addedToCartObjectIDsAfterSearch', {
102
103
  currency: getCurrencyFromPriceString(cartLine.pricing?.actualPriceDisplay),
103
104
  eventName: 'SRP: AddToCart ClickedAfterSearch',
@@ -116,10 +117,10 @@ function useAlgoliaInsights() {
116
117
  },
117
118
  sendAddToWishListFromProductDetailsPageEvent({ objectId, position }) {
118
119
  if (!context.index)
119
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
120
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
120
121
  if (context.queryId) {
121
122
  if (!position)
122
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no position', context, objectId);
123
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no position', context, objectId);
123
124
  aa('clickedObjectIDsAfterSearch', {
124
125
  eventName: 'PDP: Product Added to Wishlist',
125
126
  index: context.index,
@@ -140,9 +141,9 @@ function useAlgoliaInsights() {
140
141
  },
141
142
  sendAddToWishListFromProductListPageEvent({ objectId, position }) {
142
143
  if (!context.index)
143
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
144
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
144
145
  if (!context.queryId)
145
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no queryId', context);
146
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no queryId', context);
146
147
  aa('clickedObjectIDsAfterSearch', {
147
148
  eventName: 'PLP: Product Added to Wishlist',
148
149
  index: context.index,
@@ -154,7 +155,7 @@ function useAlgoliaInsights() {
154
155
  },
155
156
  sendAddToWishListFromSearchEvent({ objectId, position, queryId }) {
156
157
  if (!context.index)
157
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
158
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
158
159
  aa('clickedObjectIDsAfterSearch', {
159
160
  eventName: 'SRP: Product Added to Wishlist',
160
161
  index: context.index,
@@ -166,9 +167,9 @@ function useAlgoliaInsights() {
166
167
  },
167
168
  sendAddToWishListFromSearchResultPageEvent({ objectId, position, }) {
168
169
  if (!context.index)
169
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
170
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
170
171
  if (!context.queryId)
171
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no queryId', context);
172
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no queryId', context);
172
173
  aa('clickedObjectIDsAfterSearch', {
173
174
  eventName: 'SRP: Product Added to Wishlist',
174
175
  index: context.index,
@@ -180,11 +181,11 @@ function useAlgoliaInsights() {
180
181
  },
181
182
  sendProductClickFromProductListPageEvent({ objectId, position }) {
182
183
  if (!objectId)
183
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
184
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
184
185
  if (!context.index)
185
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
186
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
186
187
  if (!context.queryId)
187
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no queryId', context);
188
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no queryId', context);
188
189
  aa('clickedObjectIDsAfterSearch', {
189
190
  eventName: 'PLP: Product Clicked',
190
191
  index: context.index,
@@ -200,9 +201,9 @@ function useAlgoliaInsights() {
200
201
  },
201
202
  sendProductClickFromSearchEvent({ objectId, position, queryId }) {
202
203
  if (!objectId)
203
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
204
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
204
205
  if (!context.index)
205
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
206
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
206
207
  aa('clickedObjectIDsAfterSearch', {
207
208
  eventName: 'SRP: Product Clicked',
208
209
  index: context.index,
@@ -218,11 +219,11 @@ function useAlgoliaInsights() {
218
219
  },
219
220
  sendProductClickFromSearchResultPageEvent({ objectId, position }) {
220
221
  if (!objectId)
221
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
222
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
222
223
  if (!context.index)
223
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
224
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
224
225
  if (!context.queryId)
225
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no queryId', context);
226
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no queryId', context);
226
227
  aa('clickedObjectIDsAfterSearch', {
227
228
  eventName: 'SRP: Product Clicked',
228
229
  index: context.index,
@@ -238,9 +239,9 @@ function useAlgoliaInsights() {
238
239
  },
239
240
  sendPurchaseEventFromPaymentPage({ cart }) {
240
241
  if (!context.index)
241
- return console.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
242
+ return logger.warn('Unable to send clickedObjectIDsAfterSearch event, no index', context);
242
243
  if (!cart.cartLines || cart.cartLines.length === 0)
243
- return console.warn('Unable to send purchasedObjectIDs event, no cartLines', cart);
244
+ return logger.warn('Unable to send purchasedObjectIDs event, no cartLines', cart);
244
245
  aa('purchasedObjectIDs', {
245
246
  currency: currencySymbolToISO[cart.currencySymbol],
246
247
  eventName: 'Purchase Successful',
@@ -2,8 +2,9 @@ import { AnchorHTMLAttributes } from 'react';
2
2
  export interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
3
3
  areaSelected?: boolean;
4
4
  color?: 'primary' | 'secondary';
5
+ currentColor?: boolean;
5
6
  hasUnderline?: boolean;
6
7
  isDisabled?: boolean;
7
8
  role?: 'option';
8
9
  }
9
- export declare function Link({ children, className, color, hasUnderline, isDisabled, onClick, onKeyUp, ...props }: LinkProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function Link({ children, className, color, currentColor, hasUnderline, isDisabled, onClick, onKeyUp, ...props }: LinkProps): import("react/jsx-runtime").JSX.Element;
@@ -3,11 +3,13 @@ import { jsx } from 'react/jsx-runtime';
3
3
  import clsx from 'clsx';
4
4
  import styles from './link.module.css.js';
5
5
 
6
- function Link({ children, className, color = 'primary', hasUnderline, isDisabled, onClick, onKeyUp, ...props }) {
6
+ function Link({ children, className, color = 'primary', currentColor, hasUnderline, isDisabled, onClick, onKeyUp, ...props }) {
7
7
  return (jsx("a", { className: clsx({
8
8
  [styles.hover]: Boolean(props.href),
9
9
  [styles['has-underline']]: hasUnderline && props.href,
10
- }, styles['link'], styles[color], className), "data-disabled": isDisabled ? true : undefined, onClick: onClick, onKeyUp: onKeyUp, role: "link", tabIndex: isDisabled ? -1 : 0, ...props, children: children }));
10
+ [styles[color]]: !currentColor,
11
+ [styles['current-color']]: currentColor,
12
+ }, styles['link'], className), "data-disabled": isDisabled ? true : undefined, onClick: onClick, onKeyUp: onKeyUp, role: "link", tabIndex: isDisabled ? -1 : 0, ...props, children: children }));
11
13
  }
12
14
 
13
15
  export { Link };
@@ -2,6 +2,7 @@ import { ReactNode } from 'react';
2
2
  export type BorderType = 'top' | 'middle' | 'middle-accentuated' | 'bottom';
3
3
  export interface AccordionItemProps {
4
4
  _pseudo?: 'none' | 'focus' | 'hover' | 'active';
5
+ allowCollapse?: boolean;
5
6
  allowToggle?: boolean;
6
7
  borderType?: BorderType | BorderType[];
7
8
  children: ReactNode;
@@ -12,4 +13,4 @@ export interface AccordionItemProps {
12
13
  size?: 'md' | 'lg';
13
14
  title: ReactNode;
14
15
  }
15
- export declare function AccordionItem({ _pseudo, allowToggle, borderType, children, className, id, initialIsOpen, isDisabled, size, title, }: AccordionItemProps): import("react/jsx-runtime").JSX.Element;
16
+ export declare function AccordionItem({ _pseudo, allowCollapse, allowToggle, borderType, children, className, id, initialIsOpen, isDisabled, size, title, }: AccordionItemProps): import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { useEffect } from 'react';
3
4
  import clsx from 'clsx';
4
5
  import { GlyphsChevronsBoldDownIcon } from '../../icons/glyph/glyphs-chevrons-bold-down-icon.js';
5
6
  import { GlyphsChevronsSlimDownIcon } from '../../icons/glyph/glyphs-chevrons-slim-down-icon.js';
@@ -7,16 +8,24 @@ import { useDisclosure } from '../../shared/hooks/use-disclosure.js';
7
8
  import { ensureArray } from '../../shared/utils/array.js';
8
9
  import styles from './accordion.module.css.js';
9
10
 
10
- function AccordionItem({ _pseudo = 'none', allowToggle = true, borderType = 'bottom', children, className, id, initialIsOpen = false, isDisabled = false, size, title, }) {
11
- const { isOpen, toggle } = useDisclosure(initialIsOpen);
11
+ function AccordionItem({ _pseudo = 'none', allowCollapse = true, allowToggle = true, borderType = 'bottom', children, className, id, initialIsOpen = false, isDisabled = false, size, title, }) {
12
+ const { close, isOpen, open, toggle } = useDisclosure(initialIsOpen);
13
+ useEffect(() => {
14
+ if (initialIsOpen) {
15
+ open();
16
+ }
17
+ else {
18
+ close();
19
+ }
20
+ }, [close, initialIsOpen, open]);
12
21
  const panelId = `panel-${id}`;
13
22
  return (jsxs("div", { className: clsx(className, ...ensureArray(borderType).map(type => styles[`border-type-${type}`]), styles['accordion-item'], {
14
23
  [styles['is-open']]: isOpen,
15
24
  [styles['allow-toggle']]: allowToggle,
16
- }), children: [jsx("h3", { children: jsxs("button", { "aria-controls": panelId, "aria-expanded": isOpen, className: clsx(styles.button, styles[_pseudo]), disabled: isDisabled, id: id, onClick: () => {
25
+ }), children: [jsx("h3", { children: allowCollapse ? (jsxs("button", { "aria-controls": panelId, "aria-expanded": isOpen, className: clsx(styles.button, styles[_pseudo]), disabled: isDisabled, id: id, onClick: () => {
17
26
  if (allowToggle)
18
27
  toggle();
19
- }, type: "button", children: [title, jsx("span", { className: styles.icon, children: size === 'lg' ? (jsx(GlyphsChevronsBoldDownIcon, {})) : (jsx(GlyphsChevronsSlimDownIcon, {})) })] }) }), jsx("div", { "aria-labelledby": id, className: styles.panel, id: panelId, role: "region", children: jsx("div", { className: styles.content, children: children }) })] }));
28
+ }, type: "button", children: [title, jsx("span", { className: styles.icon, children: size === 'lg' ? (jsx(GlyphsChevronsBoldDownIcon, {})) : (jsx(GlyphsChevronsSlimDownIcon, {})) })] })) : (jsx("span", { className: styles.button, children: title })) }), jsx("div", { "aria-labelledby": id, className: styles.panel, id: panelId, role: "region", children: jsx("div", { className: styles.content, children: children }) })] }));
20
29
  }
21
30
 
22
31
  export { AccordionItem };
package/dist/exports.d.ts CHANGED
@@ -73,6 +73,7 @@ export * from './display/product-sku/product-sku';
73
73
  export * from './filters/active-filters/active-filters';
74
74
  export * from './filters/multi-select/multi-select';
75
75
  export * from './filters/pagination/pagination';
76
+ export * from './footer/footer';
76
77
  export * from './forms/checkbox/checkbox';
77
78
  export * from './forms/color-checkbox/color-checkbox';
78
79
  export * from './forms/field-error/field-error';
@@ -130,6 +131,8 @@ export * from './lists/ul/list';
130
131
  export * from './loading/blank-page-spacer';
131
132
  export * from './loading/loading-overlay';
132
133
  export * from './loading/progress-circle';
134
+ export * from './logging/logger';
135
+ export * from './logging/use-log-error';
133
136
  export * from './media/image-grid/images-grid';
134
137
  export * from './media/image-lightbox/image-lightbox';
135
138
  export * from './media/image/image';
@@ -290,6 +293,7 @@ export * from './shared/routing/with-routing';
290
293
  export * from './shared/utils/array';
291
294
  export * from './shared/utils/breakpoints';
292
295
  export * from './shared/utils/date';
296
+ export * from './shared/utils/debug';
293
297
  export * from './shared/utils/environment';
294
298
  export * from './shared/utils/event-emitter';
295
299
  export * from './shared/utils/merge';
@@ -0,0 +1,9 @@
1
+ import { ReactNode } from 'react';
2
+ import { FooterLink, LinkBlock } from './footer.model';
3
+ export interface FooterProps {
4
+ bottomLinks: FooterLink[];
5
+ copyright: string;
6
+ countrySelector: ReactNode;
7
+ linkBlocks: LinkBlock[];
8
+ }
9
+ export declare function Footer({ bottomLinks, copyright, countrySelector, linkBlocks, }: FooterProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { Accordion } from '../collapsables/accordion/accordion.js';
4
+ import { AccordionItem } from '../collapsables/accordion/accordion-item.js';
5
+ import { useIsBreakpoint } from '../shared/hooks/use-is-breakpoint.js';
6
+ import { RouteLink } from '../shared/routing/route-link.js';
7
+ import styles from './footer.module.css.js';
8
+
9
+ function Footer({ bottomLinks, copyright, countrySelector, linkBlocks, }) {
10
+ const isXl = useIsBreakpoint('xl');
11
+ return (jsxs("footer", { className: styles.footer, children: [jsx("div", { className: styles['main-links'], children: linkBlocks.map(linkBlock => (jsx("div", { className: styles['link-block'], children: jsx(Accordion, { color: "white", hasLineSeparator: false, size: "lg", children: jsx(AccordionItem, { allowCollapse: !isXl, id: `link-block-${linkBlock.key}`, initialIsOpen: isXl, title: linkBlock.header, children: jsx("ul", { className: styles['list'], children: linkBlock.links.map(link => (jsx("li", { children: jsx(RouteLink, { currentColor: true, href: link.externalLink || link.internalLink, target: link.openInNewTab ? '_blank' : undefined, children: link.title }) }, link.key))) }) }) }) }, linkBlock.key))) }), jsxs("div", { className: styles['bottom-section'], children: [jsx("p", { className: styles.copyright, children: copyright }), jsx("div", { className: styles['bottom-links'], children: bottomLinks.map(link => (jsx(RouteLink, { className: styles['bottom-link'], currentColor: true, href: link.externalLink || link.internalLink, target: link.openInNewTab ? '_blank' : undefined, children: link.title }, link.key))) }), countrySelector] })] }));
12
+ }
13
+
14
+ export { Footer };
@@ -0,0 +1,18 @@
1
+ export interface FooterLink {
2
+ externalLink?: string;
3
+ internalLink?: string;
4
+ isButton: boolean;
5
+ key: string;
6
+ openInNewTab: boolean;
7
+ title?: string;
8
+ }
9
+ export interface LinkBlock {
10
+ header: string;
11
+ key: string;
12
+ links: FooterLink[];
13
+ }
14
+ export interface FooterModel {
15
+ bottomLinks: FooterLink[];
16
+ copyright: string;
17
+ linkBlocks: LinkBlock[];
18
+ }
@@ -0,0 +1,3 @@
1
+ var styles = {"footer":"footer-module-YzJ68","main-links":"footer-module-rFBXC","link-block":"footer-module-P5FXP","link-block-heading":"footer-module-umuTh","list":"footer-module-FM4hU","bottom-section":"footer-module-TZq-4","copyright":"footer-module-qlHSS","bottom-links":"footer-module-5eyFH","bottom-link":"footer-module-0gJpF"};
2
+
3
+ export { styles as default };
package/dist/index.js CHANGED
@@ -78,6 +78,7 @@ export { ProductSku } from './display/product-sku/product-sku.js';
78
78
  export { ActiveFilters } from './filters/active-filters/active-filters.js';
79
79
  export { MultiSelect } from './filters/multi-select/multi-select.js';
80
80
  export { Pagination } from './filters/pagination/pagination.js';
81
+ export { Footer } from './footer/footer.js';
81
82
  export { Checkbox } from './forms/checkbox/checkbox.js';
82
83
  export { ColorCheckbox } from './forms/color-checkbox/color-checkbox.js';
83
84
  export { FieldError } from './forms/field-error/field-error.js';
@@ -133,6 +134,8 @@ export { List, ListItem } from './lists/ul/list.js';
133
134
  export { BlankPageSpacer } from './loading/blank-page-spacer.js';
134
135
  export { LoadingOverlay } from './loading/loading-overlay.js';
135
136
  export { ProgressCircle } from './loading/progress-circle.js';
137
+ export { consoleLogger, initLogger, logger } from './logging/logger.js';
138
+ export { useLogError } from './logging/use-log-error.js';
136
139
  export { ImagesGrid } from './media/image-grid/images-grid.js';
137
140
  export { ImageLightbox } from './media/image-lightbox/image-lightbox.js';
138
141
  export { Image } from './media/image/image.js';
@@ -290,6 +293,7 @@ export { withRouting } from './shared/routing/with-routing.js';
290
293
  export { ensureArray } from './shared/utils/array.js';
291
294
  export { breakpoints, getCurrentBreakpoints } from './shared/utils/breakpoints.js';
292
295
  export { convertDateUnitToPluralOrSingle, formatDateToLocaleString, getDateUnitObject } from './shared/utils/date.js';
296
+ export { trackPropertyChange } from './shared/utils/debug.js';
293
297
  export { environment, environments } from './shared/utils/environment.js';
294
298
  export { EventEmitter } from './shared/utils/event-emitter.js';
295
299
  export { clone, deepMerge, isPlainObject, default as main, merge } from './shared/utils/merge.js';
@@ -1,3 +1,4 @@
1
+ import { logger } from '../logging/logger.js';
1
2
  import { isLanguageCode } from './types.js';
2
3
 
3
4
  function getLanguageCodeFromCultureCode(cultureCode) {
@@ -21,7 +22,7 @@ function spireTranslateAdapter(translate) {
21
22
  }, [])
22
23
  : []));
23
24
  if (optional && message === undefined)
24
- console.warn(`Missing translation with id: ${id}`);
25
+ logger.warn(`Missing translation with id: ${id}`);
25
26
  return message || fallbackValue || id;
26
27
  };
27
28
  }
@@ -0,0 +1,11 @@
1
+ export interface Logger {
2
+ debug(message: unknown, ...args: unknown[]): void;
3
+ error(message: unknown, error: unknown): void;
4
+ error(message: unknown, error: unknown, ...args: unknown[]): void;
5
+ error(error: unknown): void;
6
+ info(message: unknown, ...args: unknown[]): void;
7
+ warn(message: unknown, ...args: unknown[]): void;
8
+ }
9
+ export declare const consoleLogger: Logger;
10
+ export declare let logger: Logger;
11
+ export declare function initLogger(replacementLogger: Logger): Logger;
@@ -0,0 +1,22 @@
1
+ const consoleLogger = {
2
+ debug(...args) {
3
+ // eslint-disable-next-line no-console
4
+ return console.debug('⚡️', ...args);
5
+ },
6
+ error(...args) {
7
+ return console.error('❌', ...args);
8
+ },
9
+ info(...args) {
10
+ // eslint-disable-next-line no-console
11
+ return console.log('✅', ...args);
12
+ },
13
+ warn(...args) {
14
+ return console.warn('⚠️', ...args);
15
+ },
16
+ };
17
+ let logger = consoleLogger;
18
+ function initLogger(replacementLogger) {
19
+ return (logger = replacementLogger);
20
+ }
21
+
22
+ export { consoleLogger, initLogger, logger };
@@ -0,0 +1 @@
1
+ export declare function useLogError(error?: unknown): void;
@@ -0,0 +1,12 @@
1
+ import { useEffect } from 'react';
2
+ import { logger } from './logger.js';
3
+
4
+ function useLogError(error) {
5
+ return useEffect(() => {
6
+ if (!error)
7
+ return;
8
+ logger.error(error);
9
+ }, [error]);
10
+ }
11
+
12
+ export { useLogError };
@@ -1,8 +1,9 @@
1
1
  "use client";
2
2
  import { jsx } from 'react/jsx-runtime';
3
- import { useRef, useEffect } from 'react';
3
+ import { useRef } from 'react';
4
4
  import { TransitionGroup, CSSTransition } from 'react-transition-group';
5
5
  import { useCultureCode } from '../../intl/use-culture-code.js';
6
+ import { useLogError } from '../../logging/use-log-error.js';
6
7
  import { useFetchAnnouncements } from '../../shared/api/bff/hooks/use-fetch-announcements.js';
7
8
  import { useLocalStorage } from '../../shared/hooks/use-local-storage.js';
8
9
  import { ConnectedAnnouncement } from './connected-announcement.js';
@@ -14,11 +15,7 @@ function AnnouncementProvider() {
14
15
  const { data: announcements, error } = useFetchAnnouncements({
15
16
  cultureCode,
16
17
  });
17
- useEffect(() => {
18
- if (!error)
19
- return;
20
- console.error(error);
21
- }, [error]);
18
+ useLogError(error);
22
19
  const [dismissedIds, setDismissedIds] = useLocalStorage('dismissedAnnouncementIds', []);
23
20
  const filteredAnnouncements = announcements?.filter(({ id }) => !dismissedIds.includes(id));
24
21
  return (jsx(TransitionGroup, { className: styles['announcement-provider'], children: filteredAnnouncements?.map(announcement => (jsx(CSSTransition, { classNames: {
@@ -42,34 +42,44 @@ function AdyenPayment({ amount, cartId, countryCode, currencyCode, customerId, d
42
42
  if (!state.details.redirectResult) {
43
43
  return onError(new Error('No redirectResult'), null);
44
44
  }
45
- const result = await getAdyenPaymentDetails({
46
- redirectResult: state.details.redirectResult,
47
- });
48
- if (amount.toFixed(2).replaceAll(/[,.]/gi, '') !== adyenAmount)
49
- return onError(new Error('Invalid amount'), result);
50
- if (customerId !== adyenCustomerId)
51
- return onError(new Error('Invalid customer'), result);
52
- return handlePaymentResponse(result, onComplete, onError);
45
+ try {
46
+ const result = await getAdyenPaymentDetails({
47
+ redirectResult: state.details.redirectResult,
48
+ });
49
+ if (amount.toFixed(2).replaceAll(/[,.]/gi, '') !== adyenAmount)
50
+ return onError(new Error('Invalid amount'), result);
51
+ if (customerId !== adyenCustomerId)
52
+ return onError(new Error('Invalid customer'), result);
53
+ return handlePaymentResponse(result, onComplete, onError);
54
+ }
55
+ catch (error) {
56
+ return onError(error, null);
57
+ }
53
58
  }),
54
59
  onSubmit: (async (state, _component) => {
55
- dropinDivRef.current?.classList.add(styles.loading);
56
- if (state.data.paymentMethod.type === 'paybybank') {
57
- state.data.countryCode = countryCode;
58
- }
59
- const result = await postAdyenPayment({
60
- currencyCode,
61
- data: state.data,
62
- orderAmount,
63
- returnUrl,
64
- webOrderNumber: adyenSession.webOrderNumber,
65
- });
66
- if (result.action) {
67
- if (result.action.type === 'redirect') {
68
- return handleRedirectPaymentAction(result);
60
+ try {
61
+ dropinDivRef.current?.classList.add(styles.loading);
62
+ if (state.data.paymentMethod.type === 'paybybank') {
63
+ state.data.countryCode = countryCode;
64
+ }
65
+ const result = await postAdyenPayment({
66
+ currencyCode,
67
+ data: state.data,
68
+ orderAmount,
69
+ returnUrl,
70
+ webOrderNumber: adyenSession.webOrderNumber,
71
+ });
72
+ if (result.action) {
73
+ if (result.action.type === 'redirect') {
74
+ return handleRedirectPaymentAction(result);
75
+ }
76
+ return onError(new Error('Invalid payment response'), result);
69
77
  }
70
- return onError(new Error('Invalid payment response'), result);
78
+ return handlePaymentResponse(result, onComplete, onError);
79
+ }
80
+ catch (error) {
81
+ return onError(error, null);
71
82
  }
72
- return handlePaymentResponse(result, onComplete, onError);
73
83
  }),
74
84
  session: {
75
85
  ...adyenSession,
@@ -12,7 +12,9 @@ import { TextField } from '../../../../forms/text-field/text-field.js';
12
12
  import { InfoIconTooltip } from '../../../../info-icon-tooltip/info-icon-tooltip.js';
13
13
  import { FormattedMessage } from '../../../../intl/formatted-message.js';
14
14
  import { useFormattedMessage } from '../../../../intl/use-formatted-message.js';
15
+ import { logger } from '../../../../logging/logger.js';
15
16
  import { usePatchSession } from '../../../../shared/api/storefront/hooks/authentication/use-patch-session.js';
17
+ import { useInvalidateCurrentCart } from '../../../../shared/api/storefront/hooks/cart/use-invalidate-current-cart.js';
16
18
  import { usePatchCart } from '../../../../shared/api/storefront/hooks/cart/use-patch-cart.js';
17
19
  import { usePlaceOrder } from '../../../../shared/api/storefront/hooks/cart/use-place-order.js';
18
20
  import { useInvalidateAdyen } from '../../../../shared/api/storefront/hooks/payment/use-invalidate-adyen.js';
@@ -27,10 +29,13 @@ import styles from './payment.module.css.js';
27
29
 
28
30
  function Payment({ atp, cart: _cart, form, onError: _onError, onPaymentComplete, onProcessing, onValidating, }) {
29
31
  const { createEcommerceEvent, dataLayer } = useDataLayer();
30
- const { isLoading: isPatchingCart, mutate: patchCart } = usePatchCart();
32
+ const { isLoading: isPatchingCart, mutate: patchCart } = usePatchCart({
33
+ skipInvalidation: true,
34
+ });
31
35
  const { isLoading: isPatchingSession } = usePatchSession();
32
36
  const { isLoading: isPlacingCart, mutate: placeOrder } = usePlaceOrder();
33
37
  const { sendPurchaseEventFromPaymentPage } = useAlgoliaInsights();
38
+ const invalidateCurrentCart = useInvalidateCurrentCart();
34
39
  const dropinRef = useRef(null);
35
40
  const [paymentError, setPaymentError] = useState();
36
41
  const [apiError, setAPIError] = useState();
@@ -151,7 +156,7 @@ function Payment({ atp, cart: _cart, form, onError: _onError, onPaymentComplete,
151
156
  if (isAdyenPayment) {
152
157
  /* Adyen Payment */
153
158
  if (!dropinRef.current) {
154
- console.warn('Adyen Dropin not ready');
159
+ logger.warn('Adyen Dropin not ready');
155
160
  return;
156
161
  }
157
162
  dropinRef.current.showValidation();
@@ -168,20 +173,26 @@ function Payment({ atp, cart: _cart, form, onError: _onError, onPaymentComplete,
168
173
  requestedDeliveryDate: formData.get('deliveryDate')?.toString(),
169
174
  };
170
175
  try {
171
- cartRef.current = await patchCart({
172
- cart: updatedCart,
173
- });
174
- }
175
- catch (error) {
176
- console.error(error);
177
- setAPIError(error);
178
- }
179
- try {
180
- dropinRef.current.submit();
176
+ try {
177
+ cartRef.current = await patchCart({
178
+ cart: updatedCart,
179
+ });
180
+ }
181
+ catch (error) {
182
+ setAPIError(error);
183
+ throw error;
184
+ }
185
+ try {
186
+ dropinRef.current.submit();
187
+ }
188
+ catch (error) {
189
+ setPaymentError(error);
190
+ throw error;
191
+ }
181
192
  }
182
193
  catch (error) {
183
- console.error(error);
184
- setPaymentError(error);
194
+ logger.error(error);
195
+ invalidateCurrentCart();
185
196
  }
186
197
  }
187
198
  else {
@@ -196,8 +207,9 @@ function Payment({ atp, cart: _cart, form, onError: _onError, onPaymentComplete,
196
207
  return onPaymentComplete({ cartId: cart.trackId });
197
208
  }
198
209
  catch (error) {
199
- console.error(error);
210
+ logger.error(error);
200
211
  setPaymentError(error);
212
+ invalidateCurrentCart();
201
213
  }
202
214
  }
203
215
  }
@@ -224,7 +236,7 @@ function Payment({ atp, cart: _cart, form, onError: _onError, onPaymentComplete,
224
236
  return onPaymentComplete({ cartId: cart.trackId });
225
237
  }
226
238
  catch (error) {
227
- console.error(error);
239
+ logger.error(error);
228
240
  setAPIError(error);
229
241
  }
230
242
  }, [onPaymentComplete, onPlaceOrderCompleted, placeOrder]);
@@ -232,7 +244,7 @@ function Payment({ atp, cart: _cart, form, onError: _onError, onPaymentComplete,
232
244
  invalidateAdyen();
233
245
  // invalidateCurrentCart()
234
246
  setPaymentError(error);
235
- console.error(error);
247
+ logger.error(error);
236
248
  _onError?.(error, result);
237
249
  }, [_onError, invalidateAdyen]);
238
250
  return (jsxs(Form, { className: styles['payment-form'], "data-test-selector": "paymentForm", id: form, onSubmit: e => {
@@ -1,4 +1,4 @@
1
- import { CountryModel } from '../../../../shared/api/storefront/model/storefront.model';
1
+ import { BillToModel, CountryModel } from '../../../../shared/api/storefront/model/storefront.model';
2
2
  export declare const EDIT_ADDRESS_FORM_ID = "billToForm";
3
3
  interface Address {
4
4
  address1: string;
@@ -13,7 +13,8 @@ interface Address {
13
13
  phone: string;
14
14
  postalCode: string;
15
15
  }
16
- export declare function EditAddresses({ countries, isLoading, isPickup, onSubmit, }: {
16
+ export declare function EditAddresses({ billTo, countries, isLoading, isPickup, onSubmit, }: {
17
+ billTo: BillToModel | undefined | null;
17
18
  countries: CountryModel[];
18
19
  isLoading: boolean;
19
20
  isPickup: boolean;
@@ -15,10 +15,10 @@ import { SonicAddress } from './sonic-address.js';
15
15
  import styles from './edit-address.module.css.js';
16
16
 
17
17
  const EDIT_ADDRESS_FORM_ID = 'billToForm';
18
- function EditAddresses({ countries, isLoading, isPickup, onSubmit, }) {
18
+ function EditAddresses({ billTo, countries, isLoading, isPickup, onSubmit, }) {
19
19
  const t = useFormattedMessage();
20
- const [companyName, setCompanyName] = useState('');
21
- const [lastName, setLastName] = useState('');
20
+ const [companyName, setCompanyName] = useState(billTo?.companyName || '');
21
+ const [lastName, setLastName] = useState(billTo?.lastName || '');
22
22
  const { data: cart } = useFetchCurrentCart();
23
23
  return (jsxs(Fragment, { children: [jsx(CheckoutPageSection, { title: jsx(FormattedMessage, { id: "Billing address" }), children: jsx(CheckoutPageSectionContent, { children: jsxs(Form, { className: styles.form, "data-test-selector": "billToAddressForm", id: EDIT_ADDRESS_FORM_ID, onSubmit: e => {
24
24
  e.preventDefault();
@@ -43,7 +43,7 @@ function EditAddresses({ countries, isLoading, isPickup, onSubmit, }) {
43
43
  },
44
44
  notes: formData.get('notes')?.toString() || '',
45
45
  });
46
- }, children: [jsx(TextField, { isDisabled: isLoading, label: t('First name'), name: "firstName", showLabel: true }), jsx(TextField, { isDisabled: isLoading, isRequired: !companyName, label: t('Last name'), minLength: 3, name: "lastName", onChange: setLastName, showLabel: true, value: lastName }, `lastname-${Boolean(companyName)}`), jsx(TextField, { isDisabled: isLoading, label: t('Company name'), name: "companyName", onChange: setCompanyName, showLabel: true, value: companyName }), jsx(TextField, { isDisabled: isLoading, label: t('Attention'), name: "attention", showLabel: true }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isRequired: true, isDisabled: isLoading, label: `${t('Address')} 1`, maxLength: 30, minLength: 3, name: "address1", showLabel: true }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isDisabled: isLoading, label: `${t('Address')} 2`, maxLength: 30, minLength: 3, name: "address2", showLabel: true }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isDisabled: isLoading, label: `${t('Address')} 3`, maxLength: 30, minLength: 3, name: "address3", showLabel: true }) }), jsx(TextField, { isRequired: true, isDisabled: isLoading, label: t('Postal Code'), maxLength: 10, minLength: 4, name: "postalCode", showLabel: true }), jsx(TextField, { isRequired: true, isDisabled: isLoading, label: t('City'), maxLength: 30, minLength: 3, name: "city", showLabel: true }), jsx("div", { className: styles['span-2'], children: jsx(CountrySelect, { isRequired: true, countries: countries, "data-test-selector": "countrySelect", isDisabled: isLoading, name: "countrySelect" }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isRequired: true, isDisabled: isLoading, label: t('Phone'), name: "phone", showLabel: true, validate: value => {
46
+ }, children: [jsx(TextField, { defaultValue: billTo?.firstName, isDisabled: isLoading, label: t('First name'), name: "firstName", showLabel: true }), jsx(TextField, { isDisabled: isLoading, isRequired: !companyName, label: t('Last name'), minLength: 3, name: "lastName", onChange: setLastName, showLabel: true, value: lastName }, `lastname-${Boolean(companyName)}`), jsx(TextField, { defaultValue: billTo?.companyName, isDisabled: isLoading, label: t('Company name'), name: "companyName", onChange: setCompanyName, showLabel: true, value: companyName }), jsx(TextField, { defaultValue: billTo?.attention, isDisabled: isLoading, label: t('Attention'), name: "attention", showLabel: true }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isRequired: true, defaultValue: billTo?.address1, isDisabled: isLoading, label: `${t('Address')} 1`, maxLength: 30, minLength: 3, name: "address1", showLabel: true }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { defaultValue: billTo?.address2, isDisabled: isLoading, label: `${t('Address')} 2`, maxLength: 30, minLength: 3, name: "address2", showLabel: true }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { defaultValue: billTo?.address3, isDisabled: isLoading, label: `${t('Address')} 3`, maxLength: 30, minLength: 3, name: "address3", showLabel: true }) }), jsx(TextField, { isRequired: true, defaultValue: billTo?.postalCode, isDisabled: isLoading, label: t('Postal Code'), maxLength: 10, minLength: 4, name: "postalCode", showLabel: true }), jsx(TextField, { isRequired: true, defaultValue: billTo?.city, isDisabled: isLoading, label: t('City'), maxLength: 30, minLength: 3, name: "city", showLabel: true }), jsx("div", { className: styles['span-2'], children: jsx(CountrySelect, { isRequired: true, countries: countries, "data-test-selector": "countrySelect", isDisabled: isLoading, name: "countrySelect", selectedCountry: countries.find(country => country.id === billTo?.country?.id) }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isRequired: true, defaultValue: billTo?.phone, isDisabled: isLoading, label: t('Phone'), name: "phone", showLabel: true, validate: value => {
47
47
  if (!value)
48
48
  return value;
49
49
  return (validatePhone(value) ||
@@ -53,7 +53,7 @@ function EditAddresses({ countries, isLoading, isPickup, onSubmit, }) {
53
53
  return value;
54
54
  return (validateEmail(value) ||
55
55
  t('Please enter a valid e-mail address'));
56
- } }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { isDisabled: isLoading, isMultiline: true, label: t('Add order notes'), name: "notes", rows: 3, showLabel: true }) })] }) }) }), jsx(CheckoutPageSection, { title: jsx(FormattedMessage, { id: isPickup ? 'Pickup address' : 'Shipping address' }), children: jsx(CheckoutPageSectionContent, { children: jsx(Fragment, { children: isPickup ? (jsx(SonicAddress, {})) : (jsxs("div", { className: styles['use-invoice-checkbox'], children: [jsx(Checkbox, { "data-test-selector": "checkboxUseBillingAddress", isDisabled: true, isSelected: true, children: jsx(FormattedMessage, { id: "Use billing address" }) }), jsx(InfoIconTooltip, { variant: "stroke", children: t('Changing your address is currently not possible. Please contact customer support to change your address.') })] })) }) }) })] }));
56
+ } }) }), jsx("div", { className: styles['span-2'], children: jsx(TextField, { defaultValue: cart?.notes, isDisabled: isLoading, isMultiline: true, label: t('Add order notes'), name: "notes", rows: 3, showLabel: true }) })] }) }) }), jsx(CheckoutPageSection, { title: jsx(FormattedMessage, { id: isPickup ? 'Pickup address' : 'Shipping address' }), children: jsx(CheckoutPageSectionContent, { children: jsx(Fragment, { children: isPickup ? (jsx(SonicAddress, {})) : (jsxs("div", { className: styles['use-invoice-checkbox'], children: [jsx(Checkbox, { "data-test-selector": "checkboxUseBillingAddress", isDisabled: true, isSelected: true, children: jsx(FormattedMessage, { id: "Use billing address" }) }), jsx(InfoIconTooltip, { variant: "stroke", children: t('Changing your address is currently not possible. Please contact customer support to change your address.') })] })) }) }) })] }));
57
57
  }
58
58
 
59
59
  export { EDIT_ADDRESS_FORM_ID, EditAddresses };
@@ -5,10 +5,11 @@ export interface ShippingPageContentProps {
5
5
  editAddress: ReactNode;
6
6
  errorPatchBillingAddress?: unknown;
7
7
  fulfillmentMethods: string[] | undefined;
8
+ isGuest: boolean;
8
9
  isLoadingFulfillmentMethods: boolean;
9
10
  isPatching: boolean;
10
11
  isPatchingSession: boolean;
11
12
  onChangeFulfillmentMethod: (value: string) => void;
12
13
  readOnlyAddress: ReactNode;
13
14
  }
14
- export declare function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulfillmentMethods, isLoadingFulfillmentMethods, isPatching, isPatchingSession, onChangeFulfillmentMethod, readOnlyAddress, }: ShippingPageContentProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulfillmentMethods, isGuest, isLoadingFulfillmentMethods, isPatching, isPatchingSession, onChangeFulfillmentMethod, readOnlyAddress, }: ShippingPageContentProps): import("react/jsx-runtime").JSX.Element;
@@ -14,7 +14,7 @@ import { CheckoutPageSectionContent } from '../layouts/checkout-page-layout/comp
14
14
  import { EDIT_ADDRESS_FORM_ID } from './components/edit-address.js';
15
15
  import styles from './shipping-page.module.css.js';
16
16
 
17
- function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulfillmentMethods, isLoadingFulfillmentMethods, isPatching, isPatchingSession, onChangeFulfillmentMethod, readOnlyAddress, }) {
17
+ function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulfillmentMethods, isGuest, isLoadingFulfillmentMethods, isPatching, isPatchingSession, onChangeFulfillmentMethod, readOnlyAddress, }) {
18
18
  const t = useFormattedMessage();
19
19
  const fulfillmentMethodOptions = fulfillmentMethods?.reduce((acc, method) => ({
20
20
  ...acc,
@@ -34,7 +34,7 @@ function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulf
34
34
  primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutShippingCartTotalContinueButton", form: EDIT_ADDRESS_FORM_ID, isDisabled: isPatching, isLoading: isPatching || isPatchingSession ? (jsx(FormattedMessage, { id: "Updating address" })) : undefined, type: "submit", children: jsx(FormattedMessage, { id: "Continue shopping" }) })),
35
35
  }, mobileSummary: jsx(CartTotalsSummary, { totalAmount: cart.orderGrandTotalDisplay }), overview: jsx(CartTotals, { fulfillmentMethod: fulfillmentMethods && fulfillmentMethods.length === 1
36
36
  ? cart.fulfillmentMethod
37
- : undefined, shippingCost: cart.shippingAndHandlingDisplay, subtotal: cart.orderSubTotalDisplay, tax: cart.totalTaxDisplay, total: cart.orderGrandTotalDisplay, vatPercentage: cart.cartLines?.[0]?.pricing?.vatRate }), children: [jsxs(Fragment, { children: [fulfillmentMethods && fulfillmentMethods.length > 1 && (jsx(CheckoutPageSection, { hasBorder: true, title: t('Fulfillment method'), children: jsx(CheckoutPageSectionContent, { children: jsx("div", { className: styles['fulfillment-select-wrapper'], children: jsx(Select, { isRequired: true, showLabel: true, "data-test-selector": "fulfillmentMethodSelect", defaultSelectedOption: cart.fulfillmentMethod, isLoading: isLoadingFulfillmentMethods, label: t('Fulfillment method'), name: "fulfillmentMethod", onChange: onChangeFulfillmentMethod, options: fulfillmentMethodOptions || {}, variant: "solid" }) }) }) })), hasBillToAddress ? readOnlyAddress : editAddress] }), Boolean(errorPatchBillingAddress) && (jsx("div", { className: styles['error-message'], children: jsx(FormattedMessage, { id: "An unexpected error occured" }) }))] }) }));
37
+ : undefined, shippingCost: cart.shippingAndHandlingDisplay, subtotal: cart.orderSubTotalDisplay, tax: cart.totalTaxDisplay, total: cart.orderGrandTotalDisplay, vatPercentage: cart.cartLines?.[0]?.pricing?.vatRate }), children: [jsxs(Fragment, { children: [fulfillmentMethods && fulfillmentMethods.length > 1 && (jsx(CheckoutPageSection, { hasBorder: true, title: t('Fulfillment method'), children: jsx(CheckoutPageSectionContent, { children: jsx("div", { className: styles['fulfillment-select-wrapper'], children: jsx(Select, { isRequired: true, showLabel: true, "data-test-selector": "fulfillmentMethodSelect", defaultSelectedOption: cart.fulfillmentMethod, isLoading: isLoadingFulfillmentMethods, label: t('Fulfillment method'), name: "fulfillmentMethod", onChange: onChangeFulfillmentMethod, options: fulfillmentMethodOptions || {}, variant: "solid" }) }) }) })), hasBillToAddress && !isGuest ? readOnlyAddress : editAddress] }), Boolean(errorPatchBillingAddress) && (jsx("div", { className: styles['error-message'], children: jsx(FormattedMessage, { id: "An unexpected error occured" }) }))] }) }));
38
38
  }
39
39
 
40
40
  export { ShippingPageContent };
@@ -75,13 +75,14 @@ function ShippingPage() {
75
75
  if (isLoading || isNavigating || isError || isSuccess)
76
76
  return jsx(LoadingPage, {});
77
77
  if (!isAuthenticated ||
78
+ hasNo(session) ||
78
79
  hasNo(cart) ||
79
80
  hasNo(cart.cartLines) ||
80
81
  cart.cartLines.length === 0 ||
81
82
  hasNo(cart.billTo) ||
82
83
  (hasNo(cart.billTo.address1) && hasNo(countries)))
83
84
  return null;
84
- return (jsx(ShippingPageContent, { cart: cart, editAddress: jsx(EditAddresses, { countries: countries || [], isLoading: isPatching, isPickup: isPickup, onSubmit: async ({ address, notes }) => {
85
+ return (jsx(ShippingPageContent, { cart: cart, editAddress: jsx(EditAddresses, { billTo: cart.billTo, countries: countries || [], isLoading: isPatching, isPickup: isPickup, onSubmit: async ({ address, notes }) => {
85
86
  if (!cart.billTo)
86
87
  return;
87
88
  await patchShippingDetails({
@@ -93,7 +94,7 @@ function ShippingPage() {
93
94
  cart,
94
95
  event: { event: 'add_shipping_info' },
95
96
  }));
96
- } }), errorPatchBillingAddress: errorPatchBillingAddress, fulfillmentMethods: fulfillmentMethods, isLoadingFulfillmentMethods: isLoadingFulfillmentMethods, isPatching: isPatching, isPatchingSession: isPatchingSession, onChangeFulfillmentMethod: async (value) => {
97
+ } }), errorPatchBillingAddress: errorPatchBillingAddress, fulfillmentMethods: fulfillmentMethods, isGuest: session.isGuest, isLoadingFulfillmentMethods: isLoadingFulfillmentMethods, isPatching: isPatching, isPatchingSession: isPatchingSession, onChangeFulfillmentMethod: async (value) => {
97
98
  await patchSession({
98
99
  session: {
99
100
  ...session,
@@ -37,7 +37,7 @@ function SearchResultsPageContent({ keyword }) {
37
37
  const { hits, isLoading } = useAlgoliaHits();
38
38
  const hasHits = hits.length > 0;
39
39
  const t = useFormattedMessage();
40
- return (jsxs(Fragment, { children: [isLoading !== false && !hasHits && jsx(LoadingPage, {}), isLoading === false && !hasHits && (jsx(NoResults, { content: jsxs("p", { children: [jsx(FormattedMessage, { id: "You could try checking the spelling of your search query" }), jsx("br", {}), jsx(FormattedMessage, { id: "Try another search" }), jsx("br", {}), jsx(FormattedMessage, { id: "Are you looking for information about our service? Please visit our customer support page" })] }), title: t("Unfortnately, We found no articles for your search '{0}'", {
40
+ return (jsxs(Fragment, { children: [isLoading !== false && !hasHits && jsx(LoadingPage, {}), isLoading === false && !hasHits && (jsx(NoResults, { content: jsxs(Fragment, { children: [jsx(FormattedMessage, { id: "You could try checking the spelling of your search query" }), jsx("br", {}), jsx(FormattedMessage, { id: "Try another search" }), jsx("br", {}), jsx(FormattedMessage, { id: "Are you looking for information about our service? Please visit our customer support page" })] }), title: t("Unfortnately, We found no articles for your search '{0}'", {
41
41
  replacementValues: { 0: keyword },
42
42
  }) })), jsxs("div", { style: {
43
43
  display: hasHits ? undefined : 'none',
@@ -1,8 +1,9 @@
1
+ import { logger } from '../../logging/logger.js';
2
+
1
3
  const _dataLayer = [];
2
4
  _dataLayer.push = (function (_push) {
3
5
  return (...items) => {
4
- // eslint-disable-next-line no-console
5
- console.log('dataLayer.push', items.length === 1 ? items[0] : items);
6
+ logger.info('dataLayer.push', items.length === 1 ? items[0] : items);
6
7
  return _push(...items);
7
8
  };
8
9
  })(_dataLayer.push.bind(_dataLayer));
@@ -73,11 +73,9 @@ function useGlobalState(key, initialState) {
73
73
  state.removeEventListener('stateChanged', updateState);
74
74
  };
75
75
  }, [state]);
76
- function updateGlobalState(valueOrFn) {
77
- state.value =
78
- valueOrFn instanceof Function ? valueOrFn(state.value) : valueOrFn;
79
- }
80
- return [rerenderState, useCallback(updateGlobalState, [updateGlobalState])];
76
+ const setGlobalState = useCallback((valueOrFn) => (state.value =
77
+ valueOrFn instanceof Function ? valueOrFn(state.value) : valueOrFn), [state]);
78
+ return [rerenderState, setGlobalState];
81
79
  }
82
80
 
83
81
  export { GlobalStateProvider, GlobalStateProviderContext, useGlobalState };
@@ -0,0 +1,2 @@
1
+ export declare function trackPropertyChange(name: string, value: unknown): void;
2
+ export declare function trackPropertyChange(obj: Record<string, unknown>): void;
@@ -0,0 +1,21 @@
1
+ import { logger } from '../../logging/logger.js';
2
+
3
+ const prevState = {};
4
+ function trackPropertyChange(name, value) {
5
+ if (typeof name === 'string') {
6
+ if (value === prevState[name]) {
7
+ logger.info(name, value === prevState[name]);
8
+ }
9
+ else {
10
+ logger.warn(name, value === prevState[name]);
11
+ }
12
+ prevState[name] = value;
13
+ }
14
+ else {
15
+ for (const [key, value] of Object.entries(name)) {
16
+ trackPropertyChange(key, value);
17
+ }
18
+ }
19
+ }
20
+
21
+ export { trackPropertyChange };
@@ -1,3 +1,5 @@
1
+ import { logger } from '../../logging/logger.js';
2
+
1
3
  const environments = [
2
4
  'marketingLocal',
3
5
  'sandbox',
@@ -26,7 +28,7 @@ function getEnvironment() {
26
28
  }
27
29
  else if (typeof window === 'undefined') {
28
30
  environmentUrl = 'production';
29
- console.error('Unable to detect environment url');
31
+ logger.error('Unable to detect environment url');
30
32
  }
31
33
  else {
32
34
  environmentUrl = `${window.location.hostname}:${window.location.port}`;
@@ -52,7 +54,7 @@ function getEnvironment() {
52
54
  }
53
55
  else {
54
56
  environment = 'production';
55
- console.error(`Environment not detected for url ${environmentUrl}. Defaulting to production.`);
57
+ logger.error(`Environment not detected for url ${environmentUrl}. Defaulting to production.`);
56
58
  }
57
59
  return environment;
58
60
  }
package/dist/styles.css CHANGED
@@ -265,6 +265,7 @@
265
265
  position: relative;
266
266
  display: inline-flex;
267
267
  align-items: center;
268
+ color: currentcolor;
268
269
  cursor: pointer;
269
270
  font: inherit;
270
271
  gap: var(--space-4);
@@ -318,6 +319,7 @@
318
319
  --accordion-item-border-color: var(--seperator-color);
319
320
  --accordion-item-border-accentuated-color: var(--color-brand-dark-gray);
320
321
  --accordion-item-border: 1px solid var(--accordion-item-border-color);
322
+ --accordion-item-hover-color: var(--color-brand-light-gray);
321
323
  }
322
324
 
323
325
  .accordion-module-9WvAH.accordion-module-6CcEH {
@@ -326,6 +328,7 @@
326
328
 
327
329
  .accordion-module-9WvAH.accordion-module-CaVdG {
328
330
  --color: var(--color-white);
331
+ --accordion-item-hover-color: transparent;
329
332
  }
330
333
 
331
334
  .accordion-module-9WvAH.accordion-module-CaVdG .accordion-module-lf9d- button[aria-expanded='true'] {
@@ -398,8 +401,7 @@
398
401
  .accordion-module-9WvAH .accordion-module-lf9d- .accordion-module-KZjMo {
399
402
  display: grid;
400
403
  grid-template-rows: 0fr;
401
- transition:
402
- grid-template-rows var(--transition-duration) linear,
404
+ transition: grid-template-rows var(--transition-duration) linear,
403
405
  padding-block var(--transition-duration) linear;
404
406
  }
405
407
 
@@ -438,7 +440,7 @@
438
440
 
439
441
  @media (hover: hover) {
440
442
  .accordion-module-9WvAH .accordion-module-lf9d-.accordion-module-QEO2d .accordion-module--Rwpb:hover {
441
- background-color: var(--color-brand-light-gray);
443
+ background-color: var(--accordion-item-hover-color);
442
444
  }
443
445
  }
444
446
 
@@ -4085,6 +4087,101 @@ button.swiper-pagination-bullet {
4085
4087
  line-height: 1.5;
4086
4088
  }
4087
4089
 
4090
+ .footer-module-YzJ68 {
4091
+ --padding-inline: var(--space-24);
4092
+
4093
+ display: block;
4094
+ background-color: var(--color-black);
4095
+ color: var(--color-white);
4096
+ padding-block-start: var(--space-32);
4097
+ }
4098
+
4099
+ .footer-module-YzJ68,
4100
+ .footer-module-YzJ68 * {
4101
+ box-sizing: border-box;
4102
+ }
4103
+
4104
+ .footer-module-YzJ68 ul {
4105
+ padding: 0;
4106
+ margin: 0;
4107
+ list-style: none;
4108
+ }
4109
+
4110
+ .footer-module-YzJ68 .footer-module-rFBXC {
4111
+ display: flex;
4112
+ flex-flow: column wrap;
4113
+ justify-content: center;
4114
+ margin-block-end: var(--space-32);
4115
+ padding-inline: var(--padding-inline);
4116
+ }
4117
+
4118
+ .footer-module-YzJ68 .footer-module-rFBXC .footer-module-P5FXP .footer-module-umuTh {
4119
+ margin-bottom: var(--space-12);
4120
+ color: inherit;
4121
+ }
4122
+
4123
+ .footer-module-YzJ68 .footer-module-rFBXC .footer-module-P5FXP .footer-module-FM4hU {
4124
+ display: grid;
4125
+ margin-bottom: var(--space-16);
4126
+ gap: var(--space-12);
4127
+ }
4128
+
4129
+ .footer-module-YzJ68 .footer-module-TZq-4 {
4130
+ display: flex;
4131
+ flex-direction: column-reverse;
4132
+ align-items: center;
4133
+ justify-content: center;
4134
+ border-top: 1px solid var(--color-brand-dark-gray);
4135
+ gap: var(--space-32);
4136
+ padding-block: var(--space-32);
4137
+ padding-inline: var(--padding-inline);
4138
+ }
4139
+
4140
+ .footer-module-YzJ68 .footer-module-TZq-4 .footer-module-qlHSS {
4141
+ margin: 0;
4142
+ }
4143
+
4144
+ .footer-module-YzJ68 .footer-module-TZq-4 .footer-module-5eyFH {
4145
+ display: flex;
4146
+ flex-direction: column;
4147
+ align-items: center;
4148
+ justify-content: center;
4149
+ gap: var(--space-32);
4150
+ }
4151
+
4152
+ @media (width >= 1024px) {.footer-module-YzJ68 {
4153
+ padding-top: var(--space-56)
4154
+ }
4155
+
4156
+ .footer-module-YzJ68 .footer-module-rFBXC {
4157
+ display: grid;
4158
+ gap: var(--space-32);
4159
+ grid-template-columns: repeat(auto-fit, 220px);
4160
+ margin-block-end: 104px;
4161
+ }
4162
+
4163
+ .footer-module-YzJ68 .footer-module-TZq-4 {
4164
+ flex-direction: row;
4165
+ justify-content: space-between;
4166
+ padding-block: var(--space-16);
4167
+ }
4168
+
4169
+ .footer-module-YzJ68 .footer-module-TZq-4 .footer-module-5eyFH {
4170
+ flex-direction: row;
4171
+ }
4172
+
4173
+ .footer-module-YzJ68 .footer-module-TZq-4 .footer-module-0gJpF {
4174
+ position: relative;
4175
+ }
4176
+
4177
+ .footer-module-YzJ68 .footer-module-TZq-4 .footer-module-0gJpF:not(:last-child)::after {
4178
+ position: absolute;
4179
+ right: -17px;
4180
+ color: currentcolor;
4181
+ content: '|';
4182
+ }
4183
+ }
4184
+
4088
4185
  .switch-module-ywpXc {
4089
4186
  --pin-color: var(--color-white);
4090
4187
  --box-color: var(--color-brand-light-gray);
@@ -4820,7 +4917,7 @@ button.swiper-pagination-bullet {
4820
4917
  align-items: center;
4821
4918
  background-color: var(--color-white);
4822
4919
  gap: var(--space-8);
4823
- grid-template-columns: 1fr auto 1fr;
4920
+ grid-template-columns: auto 1fr auto;
4824
4921
  padding-block: var(--space-4);
4825
4922
  padding-inline: var(--space-16);
4826
4923
  }
@@ -4832,6 +4929,7 @@ button.swiper-pagination-bullet {
4832
4929
 
4833
4930
  .header-layout-module-VlTuk .header-layout-module-oKPyL {
4834
4931
  width: var(--space-100);
4932
+ justify-self: center;
4835
4933
  }
4836
4934
 
4837
4935
  .header-layout-module-VlTuk .header-layout-module-aBOJL {
@@ -4840,12 +4938,11 @@ button.swiper-pagination-bullet {
4840
4938
 
4841
4939
  .header-layout-module-VlTuk .header-layout-module--ICLK {
4842
4940
  display: none;
4843
- place-items: center;
4941
+ justify-items: center;
4844
4942
  }
4845
4943
 
4846
4944
  .header-layout-module-VlTuk .header-layout-module-HjY-a {
4847
4945
  display: flex;
4848
- margin-left: auto;
4849
4946
  }
4850
4947
 
4851
4948
  .header-layout-module-VlTuk .header-layout-module-HjY-a .header-layout-module-fP3a6 {
@@ -4857,14 +4954,10 @@ button.swiper-pagination-bullet {
4857
4954
  }
4858
4955
 
4859
4956
  @media (width >= 1024px) {.header-layout-module-VlTuk {
4860
- padding-block: var(--space-24);
4957
+ padding-block: var(--space-12);
4861
4958
  padding-inline: var(--space-32)
4862
4959
  }
4863
4960
 
4864
- .header-layout-module-VlTuk .header-layout-module-oKPyL {
4865
- margin-bottom: var(--space-8);
4866
- }
4867
-
4868
4961
  .header-layout-module-VlTuk .header-layout-module-aBOJL {
4869
4962
  display: none;
4870
4963
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonic-equipment/ui",
3
- "version": "135.0.0",
3
+ "version": "136.0.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "engines": {