@sonic-equipment/ui 202.0.0 → 203.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breadcrumbs/breadcrumb.js +7 -16
- package/dist/breadcrumbs/breadcrumb.module.css.js +1 -1
- package/dist/buttons/add-to-cart-button/add-to-cart-button.d.ts +1 -1
- package/dist/buttons/add-to-cart-button/add-to-cart-button.js +12 -13
- package/dist/collapsables/accordion/accordion-item.js +6 -5
- package/dist/collapsables/accordion/accordion.module.css.js +1 -1
- package/dist/cookies/client-cookie-context.d.ts +3 -0
- package/dist/cookies/client-cookie-context.js +30 -0
- package/dist/cookies/cookie-context.d.ts +2 -0
- package/dist/cookies/cookie-context.js +6 -0
- package/dist/cookies/cookie-provider.d.ts +6 -0
- package/dist/cookies/cookie-provider.js +10 -0
- package/dist/cookies/readonly-cookie-reader.d.ts +2 -0
- package/dist/cookies/readonly-cookie-reader.js +18 -0
- package/dist/cookies/types.d.ts +14 -0
- package/dist/cookies/types.js +7 -0
- package/dist/{shared/hooks → cookies}/use-cookie.d.ts +1 -2
- package/dist/cookies/use-cookie.js +30 -0
- package/dist/country-select/hooks/use-countries.js +1 -1
- package/dist/country-selector/connected-country-selector.js +1 -1
- package/dist/country-selector/use-countries-languages.js +3 -11
- package/dist/exports.d.ts +6 -1
- package/dist/header/buttons/account/connected-account-button.js +1 -8
- package/dist/index.js +7 -2
- package/dist/media/image-grid/images-grid.d.ts +2 -1
- package/dist/media/image-grid/images-grid.js +2 -2
- package/dist/media/image-lightbox/image-lightbox.d.ts +2 -1
- package/dist/media/image-lightbox/image-lightbox.js +2 -2
- package/dist/pages/account/components/create-account-form/create-account-form.js +1 -1
- package/dist/pages/account/create-account-page/create-account-page.js +5 -3
- package/dist/pages/account/layouts/sign-in-page-layout/sign-in-page-layout.d.ts +2 -1
- package/dist/pages/account/layouts/sign-in-page-layout/sign-in-page-layout.js +2 -4
- package/dist/pages/account/sign-in-page/sign-in-page.js +2 -2
- package/dist/pages/checkout/cart-page/cart-page.js +1 -1
- package/dist/pages/checkout/order-confirmation-page/order-confirmation-page-content.js +1 -1
- package/dist/pages/my-sonic/widgets/connected-bill-to-address-widget.js +2 -1
- package/dist/pages/my-sonic/widgets/connected-ship-to-address-widget.js +2 -1
- package/dist/pages/product/product-details-page/components/product-details-images/product-detail-images.js +1 -3
- package/dist/pages/product/product-details-page/components/product-details-images/product-detail-images.module.css.js +1 -1
- package/dist/pages/product/product-details-page/product-details.js +5 -1
- package/dist/pages/product/product-listing-page/no-results/no-results.js +3 -1
- package/dist/shared/api/storefront/hooks/cart/use-fetch-current-cart-with-atp.js +6 -4
- package/dist/shared/api/storefront/hooks/product/use-mark-product-as-viewed.d.ts +5 -3
- package/dist/shared/api/storefront/hooks/product/use-mark-product-as-viewed.js +4 -8
- package/dist/shared/api/storefront/services/website-service.js +9 -0
- package/dist/shared/hooks/use-debounced-callback.d.ts +5 -1
- package/dist/shared/hooks/use-debounced-callback.js +10 -10
- package/dist/shared/providers/react-query-container.d.ts +8 -3
- package/dist/shared/providers/react-query-container.js +4 -4
- package/dist/shared/routing/route-provider.d.ts +1 -0
- package/dist/shared/routing/types.d.ts +1 -0
- package/dist/shared/routing/use-location.js +2 -2
- package/dist/sidebar/sidebar-provider.js +0 -2
- package/dist/styles.css +31 -1
- package/package.json +1 -1
- package/dist/shared/hooks/use-cookie.js +0 -34
|
@@ -5,32 +5,23 @@ import clsx from 'clsx';
|
|
|
5
5
|
import { Link } from '../buttons/link/link.js';
|
|
6
6
|
import { GlyphsChevronsSlimLeftIcon } from '../icons/glyph/glyphs-chevrons-slim-left-icon.js';
|
|
7
7
|
import { SolidHomeIcon } from '../icons/solid/solid-home-icon.js';
|
|
8
|
-
import { useIsBreakpoint } from '../shared/hooks/use-is-breakpoint.js';
|
|
9
8
|
import styles from './breadcrumb.module.css.js';
|
|
10
9
|
|
|
11
|
-
function
|
|
10
|
+
function Breadcrumb({ links }) {
|
|
11
|
+
if (links.length <= 1)
|
|
12
|
+
return null;
|
|
13
|
+
const linksWithoutFirst = links.slice(1);
|
|
12
14
|
const homeLink = links[0];
|
|
13
15
|
const previousLink = links.at(-2);
|
|
14
16
|
const isHomeLink = previousLink === undefined || previousLink === homeLink;
|
|
15
17
|
const href = previousLink?.href || homeLink?.href;
|
|
16
18
|
const label = previousLink?.label || homeLink?.label;
|
|
17
|
-
return (jsx(Breadcrumbs, { className: styles.breadcrumbs, children: jsx(Breadcrumb$1, { className: styles.breadcrumb, children: jsxs(Link, { className: styles.link, href: href, isDisabled: false, title: label, children: [jsx(GlyphsChevronsSlimLeftIcon, { className: styles.icon }), isHomeLink ? (jsx(SolidHomeIcon, { className: styles.icon })) : (jsx("span", { children: previousLink.label }))] }) }) }));
|
|
18
|
-
}
|
|
19
|
-
function BreadcrumbLongItem({ index, isDisabled, link, }) {
|
|
20
|
-
return (jsx(Breadcrumb$1, { className: styles.breadcrumb, children: jsxs(Link, { className: styles.link, color: "secondary", href: link.href, isDisabled: isDisabled, title: link.label, children: [jsx(GlyphsChevronsSlimLeftIcon, { className: clsx(styles['previous-icon'], styles.icon) }), link.label] }) }, index));
|
|
21
|
-
}
|
|
22
|
-
function BreadcrumbLong({ links }) {
|
|
23
|
-
const linksWithoutFirst = links.slice(1);
|
|
24
|
-
const homeLink = links[0];
|
|
25
19
|
if (!homeLink)
|
|
26
20
|
return null;
|
|
27
|
-
return (jsxs(Breadcrumbs, { className: styles.breadcrumbs, children: [jsx(Breadcrumb$1, { className: styles.breadcrumb, children: jsx(Link, { className: styles.link, href: homeLink.href, title: homeLink.label, children: jsx(SolidHomeIcon, { className: clsx(styles['home-icon'], styles.icon) }) }) }), linksWithoutFirst.map((link, index) => (jsx(BreadcrumbLongItem, { index: index, isDisabled: linksWithoutFirst.length - 1 === index, link: link }, link.href + link.label || index)))] }));
|
|
21
|
+
return (jsxs(Breadcrumbs, { className: styles.breadcrumbs, children: [jsx(Breadcrumb$1, { className: clsx(styles.breadcrumb, styles.short), children: jsxs(Link, { className: styles.link, href: href, isDisabled: false, title: label, children: [jsx(GlyphsChevronsSlimLeftIcon, { className: styles.icon }), isHomeLink ? (jsx(SolidHomeIcon, { className: styles.icon })) : (jsx("span", { children: previousLink.label }))] }) }), jsx(Breadcrumb$1, { className: clsx(styles.breadcrumb, styles.long), children: jsx(Link, { className: styles.link, href: homeLink.href, title: homeLink.label, children: jsx(SolidHomeIcon, { className: clsx(styles['home-icon'], styles.icon) }) }) }), linksWithoutFirst.map((link, index) => (jsx(BreadcrumbLongItem, { index: index, isDisabled: linksWithoutFirst.length - 1 === index, link: link }, link.href + link.label || index)))] }));
|
|
28
22
|
}
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
if (links.length <= 1)
|
|
32
|
-
return null;
|
|
33
|
-
return isLg ? BreadcrumbLong({ links }) : BreadcrumbShort({ links });
|
|
23
|
+
function BreadcrumbLongItem({ index, isDisabled, link, }) {
|
|
24
|
+
return (jsx(Breadcrumb$1, { className: clsx(styles.breadcrumb, styles.long), children: jsxs(Link, { className: styles.link, color: "secondary", href: link.href, isDisabled: isDisabled, title: link.label, children: [jsx(GlyphsChevronsSlimLeftIcon, { className: clsx(styles['previous-icon'], styles.icon) }), link.label] }) }, index));
|
|
34
25
|
}
|
|
35
26
|
|
|
36
27
|
export { Breadcrumb };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var styles = {"breadcrumbs":"breadcrumb-module-CQGse","breadcrumb":"breadcrumb-module-hxhDY","link":"breadcrumb-module-fp2Q6","icon":"breadcrumb-module-uIn3w","previous-icon":"breadcrumb-module-K-wMJ"};
|
|
1
|
+
var styles = {"breadcrumbs":"breadcrumb-module-CQGse","breadcrumb":"breadcrumb-module-hxhDY","link":"breadcrumb-module-fp2Q6","icon":"breadcrumb-module-uIn3w","previous-icon":"breadcrumb-module-K-wMJ","short":"breadcrumb-module-ToeDB","long":"breadcrumb-module-np5GK"};
|
|
2
2
|
|
|
3
3
|
export { styles as default };
|
|
@@ -3,5 +3,5 @@ interface AddToCartButtonProps {
|
|
|
3
3
|
onChange: (quantity: number) => void;
|
|
4
4
|
quantity: number;
|
|
5
5
|
}
|
|
6
|
-
export declare function AddToCartButton({ isDisabled, onChange, quantity, }: AddToCartButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare function AddToCartButton({ isDisabled, onChange: _onChange, quantity: _quantity, }: AddToCartButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
7
7
|
export {};
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
3
|
import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
4
4
|
import clsx from 'clsx';
|
|
5
5
|
import { NumberField } from '../../forms/fields/number-field/number-field.js';
|
|
6
6
|
import { SolidCartIcon } from '../../icons/solid/solid-cart-icon.js';
|
|
7
7
|
import { useFormattedMessage } from '../../intl/use-formatted-message.js';
|
|
8
|
+
import { useDebouncedCallback } from '../../shared/hooks/use-debounced-callback.js';
|
|
8
9
|
import { ensureNumber } from '../../shared/utils/number.js';
|
|
9
10
|
import { Button } from '../button/button.js';
|
|
10
11
|
import styles from './add-to-cart-button.module.css.js';
|
|
11
12
|
|
|
12
|
-
function AddToCartButton({ isDisabled = false, onChange, quantity, }) {
|
|
13
|
-
return (jsx(InternalAddToCartButton, { isDisabled: isDisabled, onChange: onChange, quantity: quantity }));
|
|
14
|
-
}
|
|
15
|
-
function InternalAddToCartButton({ isDisabled = false, onChange: _onChange, quantity: _quantity, }) {
|
|
13
|
+
function AddToCartButton({ isDisabled = false, onChange: _onChange, quantity: _quantity, }) {
|
|
16
14
|
const [quantity, setQuantity] = useState(_quantity);
|
|
17
15
|
const [currentState, setState] = useState(quantity > 0 ? 'input' : 'initial');
|
|
18
16
|
const [hasFocus, setHasFocus] = useState(false);
|
|
@@ -60,7 +58,6 @@ function InitialState({ buttonRef, hasFocus, isDisabled, onAddToCart, onHasFocus
|
|
|
60
58
|
onAddToCart();
|
|
61
59
|
}, size: "md" }));
|
|
62
60
|
}
|
|
63
|
-
let debounced;
|
|
64
61
|
/* input state: spinner buttons and manual input */
|
|
65
62
|
function InputState({ hasFocus, inputRef, isDisabled, onChange: _onChange, onHasFocussed, quantity, }) {
|
|
66
63
|
const t = useFormattedMessage();
|
|
@@ -68,6 +65,7 @@ function InputState({ hasFocus, inputRef, isDisabled, onChange: _onChange, onHas
|
|
|
68
65
|
const [manualQuantity, setManualQuantity] = useState(null);
|
|
69
66
|
const isManualInput = useMemo(() => manualQuantity !== null, [manualQuantity]);
|
|
70
67
|
const isSpinnerInput = useMemo(() => manualQuantity === null, [manualQuantity]);
|
|
68
|
+
const onChangeDebounced = useDebouncedCallback((quantity) => _onChange(quantity), 1500);
|
|
71
69
|
useEffect(() => {
|
|
72
70
|
if (hasFocus) {
|
|
73
71
|
inputRef?.current?.focus();
|
|
@@ -78,28 +76,29 @@ function InputState({ hasFocus, inputRef, isDisabled, onChange: _onChange, onHas
|
|
|
78
76
|
useEffect(() => {
|
|
79
77
|
// clear debounced when switching to manual input or when quantity is 0 (returning to initial state)
|
|
80
78
|
if (isManualInput)
|
|
81
|
-
|
|
82
|
-
}, [isManualInput]);
|
|
79
|
+
onChangeDebounced.cancel();
|
|
80
|
+
}, [isManualInput, onChangeDebounced]);
|
|
83
81
|
const onKeyUp = (e) => {
|
|
84
82
|
if (isSpinnerInput)
|
|
85
83
|
return;
|
|
86
84
|
if (e.key === 'Enter')
|
|
87
85
|
confirmManualQuantity();
|
|
88
86
|
if (e.key === 'Escape') {
|
|
87
|
+
/* returns to spinner input and restarts a debounce timer for the internalQuantity on the field */
|
|
89
88
|
setManualQuantity(null);
|
|
90
|
-
|
|
89
|
+
onChangeDebounced(internalQuantity);
|
|
91
90
|
}
|
|
92
91
|
};
|
|
93
92
|
const onSpinnerChange = (quantity) => {
|
|
94
|
-
|
|
93
|
+
if (Number.isNaN(quantity))
|
|
94
|
+
return;
|
|
95
95
|
setInternalQuantity(quantity);
|
|
96
96
|
if (quantity === 0) {
|
|
97
|
+
onChangeDebounced.cancel();
|
|
97
98
|
_onChange(0);
|
|
98
99
|
}
|
|
99
100
|
else {
|
|
100
|
-
|
|
101
|
-
_onChange(quantity);
|
|
102
|
-
}, 1500);
|
|
101
|
+
onChangeDebounced(quantity);
|
|
103
102
|
}
|
|
104
103
|
};
|
|
105
104
|
const onManualInput = (e) => {
|
|
@@ -20,14 +20,15 @@ function AccordionItem({ _pseudo = 'none', allowCollapse = true, allowToggle = t
|
|
|
20
20
|
}
|
|
21
21
|
}, [close, initialIsOpen, open]);
|
|
22
22
|
const panelId = `panel-${id}`;
|
|
23
|
-
return (jsxs("div", { className: clsx(className, ...ensureArray(borderType).map(type => styles[`border-type-${type}`]), styles['accordion-item'], isDisabled && styles.disabled, {
|
|
23
|
+
return (jsxs("div", { suppressHydrationWarning: true, className: clsx(className, ...ensureArray(borderType).map(type => styles[`border-type-${type}`]), styles['accordion-item'], isDisabled && styles.disabled, {
|
|
24
24
|
[styles['is-open']]: isOpen,
|
|
25
|
-
[styles['allow-collapse']]: allowCollapse,
|
|
26
25
|
[styles['allow-toggle']]: allowCollapse && allowToggle,
|
|
27
|
-
}), "data-test-selector": dataTestSelector, children: [jsx(Heading, { className: styles.heading, tag: "h3", children:
|
|
28
|
-
|
|
26
|
+
}), "data-test-selector": dataTestSelector, children: [jsx(Heading, { className: styles.heading, tag: "h3", children: jsxs("button", { suppressHydrationWarning: true, "aria-controls": panelId, "aria-expanded": isOpen, className: clsx(styles.button, styles[_pseudo], {
|
|
27
|
+
[styles['disable-collapse']]: !allowCollapse,
|
|
28
|
+
}), disabled: isDisabled, id: id, onClick: () => {
|
|
29
|
+
if (allowToggle && allowCollapse)
|
|
29
30
|
toggle();
|
|
30
|
-
}, tabIndex: allowToggle ? 0 : -1, type: "button", children: [title, jsx("span", { className: styles.icon, children: size === 'lg' ? (jsx(GlyphsChevronsBoldDownIcon, {})) : (jsx(GlyphsChevronsSlimDownIcon, {})) })] })
|
|
31
|
+
}, tabIndex: allowToggle ? 0 : -1, 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 }) })] }));
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export { AccordionItem };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var styles = {"accordion":"accordion-module-9WvAH","indented":"accordion-module-6CcEH","white":"accordion-module-CaVdG","accordion-item":"accordion-module-lf9d-","lg":"accordion-module-0qnae","with-seperators":"accordion-module-yOLrW","heading":"accordion-module-d-B4T","button":"accordion-module--Rwpb","icon":"accordion-module-Y50uq","focus":"accordion-module-M4BZs","allow-toggle":"accordion-module-QEO2d","panel":"accordion-module-KZjMo","content":"accordion-module-ejMH3","border-type-bottom":"accordion-module-oTdZK","border-type-top":"accordion-module-0mrLq","border-type-middle":"accordion-module-aAr-R","is-open":"accordion-module-W0F1z","border-type-middle-accentuated":"accordion-module-OB98a","select":"accordion-module-SAbiG","disabled":"accordion-module-ogvYX"};
|
|
1
|
+
var styles = {"accordion":"accordion-module-9WvAH","indented":"accordion-module-6CcEH","white":"accordion-module-CaVdG","accordion-item":"accordion-module-lf9d-","lg":"accordion-module-0qnae","with-seperators":"accordion-module-yOLrW","heading":"accordion-module-d-B4T","button":"accordion-module--Rwpb","icon":"accordion-module-Y50uq","focus":"accordion-module-M4BZs","allow-toggle":"accordion-module-QEO2d","panel":"accordion-module-KZjMo","content":"accordion-module-ejMH3","border-type-bottom":"accordion-module-oTdZK","border-type-top":"accordion-module-0mrLq","border-type-middle":"accordion-module-aAr-R","is-open":"accordion-module-W0F1z","border-type-middle-accentuated":"accordion-module-OB98a","disable-collapse":"accordion-module-RnNRT","select":"accordion-module-SAbiG","disabled":"accordion-module-ogvYX"};
|
|
2
2
|
|
|
3
3
|
export { styles as default };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import Cookies from 'js-cookie';
|
|
2
|
+
import { config } from '../config.js';
|
|
3
|
+
import { TIME } from '../shared/utils/time.js';
|
|
4
|
+
|
|
5
|
+
const defaultCookieOptions = {
|
|
6
|
+
domain: config.COOKIE_DOMAIN,
|
|
7
|
+
expires: new Date(Date.now() + TIME.DAY * 356), // 365,
|
|
8
|
+
path: '/',
|
|
9
|
+
sameSite: 'none',
|
|
10
|
+
secure: true,
|
|
11
|
+
};
|
|
12
|
+
function get(name) {
|
|
13
|
+
if (name)
|
|
14
|
+
return Cookies.get(name);
|
|
15
|
+
return Cookies.get();
|
|
16
|
+
}
|
|
17
|
+
function set(name, value, options) {
|
|
18
|
+
if (value) {
|
|
19
|
+
Cookies.set(name, value, options);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
Cookies.remove(name);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const clientCookieContextValue = {
|
|
26
|
+
get,
|
|
27
|
+
set,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export { clientCookieContextValue, defaultCookieOptions };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { clientCookieContextValue } from './client-cookie-context.js';
|
|
4
|
+
import { CookieContext } from './cookie-context.js';
|
|
5
|
+
|
|
6
|
+
function CookieProvider({ children, value = clientCookieContextValue, }) {
|
|
7
|
+
return (jsx(CookieContext.Provider, { value: value, children: children }));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { CookieProvider };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { logger } from '../logging/logger.js';
|
|
2
|
+
|
|
3
|
+
function set(name, value, _options) {
|
|
4
|
+
logger.warn('Attempted to set a cookie on a readonly cookie reader', {
|
|
5
|
+
name,
|
|
6
|
+
value,
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
function createReadonlyCookieReader(cookies) {
|
|
10
|
+
function get(name) {
|
|
11
|
+
if (name)
|
|
12
|
+
return cookies[name];
|
|
13
|
+
return cookies;
|
|
14
|
+
}
|
|
15
|
+
return { get, set };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { createReadonlyCookieReader };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface CookieAttributes {
|
|
2
|
+
domain?: string | undefined;
|
|
3
|
+
expires?: Date | undefined;
|
|
4
|
+
path?: string | undefined;
|
|
5
|
+
sameSite?: 'lax' | 'strict' | 'none' | undefined;
|
|
6
|
+
secure?: boolean | undefined;
|
|
7
|
+
}
|
|
8
|
+
export interface CookieGetterSetter {
|
|
9
|
+
get(): Record<string, string> | undefined;
|
|
10
|
+
get(name: string): string | undefined;
|
|
11
|
+
set(name: string, value: string | undefined, options?: CookieAttributes): void;
|
|
12
|
+
}
|
|
13
|
+
export type CookieContextValue = CookieGetterSetter | Record<string, string>;
|
|
14
|
+
export declare function isCookieGetterSetter(value: CookieContextValue): value is CookieGetterSetter;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { CookieAttributes } from '
|
|
2
|
-
export declare const defaultCookieOptions: CookieAttributes;
|
|
1
|
+
import { CookieAttributes } from './types';
|
|
3
2
|
interface SetValueFn {
|
|
4
3
|
(value: string | undefined): void;
|
|
5
4
|
(fn: (value: string | undefined) => string | undefined): void;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useContext, useState } from 'react';
|
|
3
|
+
import { defaultCookieOptions, clientCookieContextValue } from './client-cookie-context.js';
|
|
4
|
+
import { CookieContext } from './cookie-context.js';
|
|
5
|
+
import { createReadonlyCookieReader } from './readonly-cookie-reader.js';
|
|
6
|
+
import { isCookieGetterSetter } from './types.js';
|
|
7
|
+
|
|
8
|
+
function useCookie(name, options = defaultCookieOptions) {
|
|
9
|
+
const context = useContext(CookieContext);
|
|
10
|
+
const Cookies = context
|
|
11
|
+
? isCookieGetterSetter(context)
|
|
12
|
+
? context
|
|
13
|
+
: createReadonlyCookieReader(context)
|
|
14
|
+
: clientCookieContextValue;
|
|
15
|
+
const cookieValue = Cookies.get()?.[name];
|
|
16
|
+
const [stateValue, setStateValue] = useState(cookieValue);
|
|
17
|
+
if (cookieValue !== stateValue) {
|
|
18
|
+
setStateValue(cookieValue);
|
|
19
|
+
}
|
|
20
|
+
function setValue(valueOrFn) {
|
|
21
|
+
setStateValue(oldValue => {
|
|
22
|
+
const newValue = typeof valueOrFn === 'function' ? valueOrFn(oldValue) : valueOrFn;
|
|
23
|
+
Cookies.set(name, newValue, options);
|
|
24
|
+
return newValue;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return [stateValue, setValue];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { useCookie };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
|
+
import { useCookie } from '../../cookies/use-cookie.js';
|
|
2
3
|
import { isCountryCode, isCultureCode, isLanguageCode } from '../../intl/types.js';
|
|
3
4
|
import { useFetchCountriesWithLanguages } from '../../shared/api/storefront/hooks/website/use-fetch-countries-with-languages.js';
|
|
4
|
-
import { useCookie } from '../../shared/hooks/use-cookie.js';
|
|
5
5
|
import { useSessionStorage } from '../../shared/hooks/use-session-storage.js';
|
|
6
6
|
|
|
7
7
|
function useCountries({ enabled = true, } = {}) {
|
|
@@ -38,7 +38,7 @@ function ConnectedCountrySelector({ defaultCountryCode, defaultLanguageCode, onC
|
|
|
38
38
|
logger.error('Error fetching countries and languages:', error);
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
|
-
return (jsxs(Fragment, { children: [jsx(CountrySelectorTrigger, { onClick: open, selectedCountry: selectedCountry, selectedLanguage: selectedLanguage, showCountry: showCountry }), jsx(CountrySelectorDialog, { countries: countries, isDismissable: isDismissable, isOpen: isOpen, onOpenChange: open => {
|
|
41
|
+
return (jsxs(Fragment, { children: [jsx(CountrySelectorTrigger, { onClick: open, selectedCountry: selectedCountry || defaultCountry, selectedLanguage: selectedLanguage || defaultLanguage, showCountry: showCountry }), jsx(CountrySelectorDialog, { countries: countries, isDismissable: isDismissable, isOpen: isOpen, onOpenChange: open => {
|
|
42
42
|
if (!isDismissable)
|
|
43
43
|
return;
|
|
44
44
|
setIsOpen(open);
|
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useEffect } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { useCookie } from '../cookies/use-cookie.js';
|
|
4
4
|
import { useFetchCountriesWithLanguages } from '../shared/api/storefront/hooks/website/use-fetch-countries-with-languages.js';
|
|
5
5
|
import { updateLocale } from '../shared/api/storefront/services/website-service.js';
|
|
6
|
-
import { useCookie } from '../shared/hooks/use-cookie.js';
|
|
7
6
|
import { useSessionStorage } from '../shared/hooks/use-session-storage.js';
|
|
8
7
|
import { isCountry } from '../shared/model/countries-languages.js';
|
|
9
8
|
|
|
10
|
-
const cookieOptions = {
|
|
11
|
-
domain: config.COOKIE_DOMAIN,
|
|
12
|
-
expires: 365,
|
|
13
|
-
path: '/',
|
|
14
|
-
sameSite: 'None',
|
|
15
|
-
secure: true,
|
|
16
|
-
};
|
|
17
9
|
function useCountriesLanguages({ defaultCountryCode, defaultLanguageCode, }) {
|
|
18
10
|
const [sessionCountries, setSessionCountries] = useSessionStorage('countries-v1');
|
|
19
|
-
const [currentCountryId] = useCookie('CurrentCountryId'
|
|
11
|
+
const [currentCountryId] = useCookie('CurrentCountryId');
|
|
20
12
|
// const [currentLanguageId] = ['be71b608-4876-420a-b1f5-adfe0093a72a'] // useCookie('CurrentLanguageId', cookieOptions)
|
|
21
|
-
const [currentLanguageId] = useCookie('CurrentLanguageId'
|
|
13
|
+
const [currentLanguageId] = useCookie('CurrentLanguageId');
|
|
22
14
|
const hasSessionCountries = Boolean(sessionCountries?.length);
|
|
23
15
|
const { data: apiCountries, error, isFetching, } = useFetchCountriesWithLanguages({
|
|
24
16
|
enabled: !hasSessionCountries,
|
package/dist/exports.d.ts
CHANGED
|
@@ -72,6 +72,12 @@ export * from './collapsables/show-all/show-all';
|
|
|
72
72
|
export * from './collapsables/unmounter/unmounter';
|
|
73
73
|
export * from './collapsables/unmounter/utils';
|
|
74
74
|
export * from './config';
|
|
75
|
+
export * from './cookies/client-cookie-context';
|
|
76
|
+
export * from './cookies/cookie-context';
|
|
77
|
+
export * from './cookies/cookie-provider';
|
|
78
|
+
export * from './cookies/readonly-cookie-reader';
|
|
79
|
+
export * from './cookies/types';
|
|
80
|
+
export * from './cookies/use-cookie';
|
|
75
81
|
export * from './country-select/country-select';
|
|
76
82
|
export * from './country-select/hooks/use-countries';
|
|
77
83
|
export * from './country-selector/connected-country-selector';
|
|
@@ -374,7 +380,6 @@ export * from './shared/ga/google-analytics-provider';
|
|
|
374
380
|
export * from './shared/ga/types';
|
|
375
381
|
export * from './shared/ga/use-data-layer';
|
|
376
382
|
export * from './shared/hooks/use-breakpoint';
|
|
377
|
-
export * from './shared/hooks/use-cookie';
|
|
378
383
|
export * from './shared/hooks/use-cookiebot';
|
|
379
384
|
export * from './shared/hooks/use-css-link';
|
|
380
385
|
export * from './shared/hooks/use-debounced-callback';
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
|
-
import { useMemo } from 'react';
|
|
4
3
|
import { IconButton } from '../../../buttons/icon-button/icon-button.js';
|
|
5
4
|
import { useFormattedMessage } from '../../../intl/use-formatted-message.js';
|
|
6
5
|
import { AccountIcon } from '../../../navigation/account-icon/account-icon.js';
|
|
@@ -12,13 +11,7 @@ function ConnectedAccountButton({ className, 'data-test-selector': dataTestSelec
|
|
|
12
11
|
const paths = usePaths();
|
|
13
12
|
const t = useFormattedMessage();
|
|
14
13
|
const isAuthenticated = useIsAuthenticated();
|
|
15
|
-
const
|
|
16
|
-
const href = useMemo(() =>
|
|
17
|
-
// TODO: Replace with relative URL when migrated away from Umbraco
|
|
18
|
-
typeof location === 'undefined' ? undefined : location.href,
|
|
19
|
-
// Using the location hook to detect url changes, but not using it directly
|
|
20
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
21
|
-
[_location]);
|
|
14
|
+
const { href } = useLocation();
|
|
22
15
|
return (jsx(IconButton, { className: className, "data-authenticated": isAuthenticated ? true : false, "data-test-selector": dataTestSelector, href: isAuthenticated
|
|
23
16
|
? paths.ACCOUNT
|
|
24
17
|
: `${paths.SIGN_IN}${href ? `?returnUrl=${encodeURIComponent(href)}` : ''}`, onClick: onClick, children: jsx(AccountIcon, { "aria-label": isAuthenticated ? t('My Sonic') : t('Sign in or create account'), isAuthenticated: isAuthenticated }) }));
|
package/dist/index.js
CHANGED
|
@@ -76,6 +76,12 @@ export { ShowAll } from './collapsables/show-all/show-all.js';
|
|
|
76
76
|
export { Unmounter, UnmounterContext, useUnmount } from './collapsables/unmounter/unmounter.js';
|
|
77
77
|
export { createAddEndListener } from './collapsables/unmounter/utils.js';
|
|
78
78
|
export { config, configPerEnvironment } from './config.js';
|
|
79
|
+
export { clientCookieContextValue, defaultCookieOptions } from './cookies/client-cookie-context.js';
|
|
80
|
+
export { CookieContext } from './cookies/cookie-context.js';
|
|
81
|
+
export { CookieProvider } from './cookies/cookie-provider.js';
|
|
82
|
+
export { createReadonlyCookieReader } from './cookies/readonly-cookie-reader.js';
|
|
83
|
+
export { isCookieGetterSetter } from './cookies/types.js';
|
|
84
|
+
export { useCookie } from './cookies/use-cookie.js';
|
|
79
85
|
export { CountrySelect } from './country-select/country-select.js';
|
|
80
86
|
export { useCountries } from './country-select/hooks/use-countries.js';
|
|
81
87
|
export { ConnectedCountrySelector } from './country-selector/connected-country-selector.js';
|
|
@@ -375,7 +381,6 @@ export { GoogleAnalyticsProvider, InitializeGoogleAnalyticsProvider, useGoogleAn
|
|
|
375
381
|
export { isGAEvent } from './shared/ga/types.js';
|
|
376
382
|
export { useDataLayer } from './shared/ga/use-data-layer.js';
|
|
377
383
|
export { useBreakpoint } from './shared/hooks/use-breakpoint.js';
|
|
378
|
-
export { defaultCookieOptions, useCookie } from './shared/hooks/use-cookie.js';
|
|
379
384
|
export { useCookiebot } from './shared/hooks/use-cookiebot.js';
|
|
380
385
|
export { useCSSLink } from './shared/hooks/use-css-link.js';
|
|
381
386
|
export { useDebouncedCallback } from './shared/hooks/use-debounced-callback.js';
|
|
@@ -403,7 +408,7 @@ export { isResponsiveImage } from './shared/model/image.js';
|
|
|
403
408
|
export { CartProvider, useCartEvents } from './shared/providers/cart-provider.js';
|
|
404
409
|
export { FavoriteProvider, useFavorite, useFavoriteProduct } from './shared/providers/favorite-provider.js';
|
|
405
410
|
export { GlobalStateProvider, GlobalStateProviderContext, useGlobalState } from './shared/providers/global-state-provider.js';
|
|
406
|
-
export { ReactQueryContainer } from './shared/providers/react-query-container.js';
|
|
411
|
+
export { ReactQueryContainer, globalQueryClient } from './shared/providers/react-query-container.js';
|
|
407
412
|
export { RouteContext } from './shared/routing/route-context.js';
|
|
408
413
|
export { RouteProvider } from './shared/routing/route-provider.js';
|
|
409
414
|
export { buildHref } from './shared/routing/route-utils.js';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ImageType } from '../../shared/model/image';
|
|
2
2
|
interface ImagesGridProps {
|
|
3
|
+
className?: string;
|
|
3
4
|
images: ImageType[];
|
|
4
5
|
onSelectImage?: (image: ImageType, index: number) => void;
|
|
5
6
|
}
|
|
6
|
-
export declare function ImagesGrid({ images, onSelectImage }: ImagesGridProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare function ImagesGrid({ className, images, onSelectImage, }: ImagesGridProps): import("react/jsx-runtime").JSX.Element;
|
|
7
8
|
export {};
|
|
@@ -11,7 +11,7 @@ const mainImagePosition = {
|
|
|
11
11
|
4: 0,
|
|
12
12
|
5: 2,
|
|
13
13
|
};
|
|
14
|
-
function ImagesGrid({ images, onSelectImage }) {
|
|
14
|
+
function ImagesGrid({ className, images, onSelectImage, }) {
|
|
15
15
|
const positionIndex = mainImagePosition[images.length] || 0;
|
|
16
16
|
const imageList = [
|
|
17
17
|
...images.slice(1, positionIndex + 1),
|
|
@@ -24,7 +24,7 @@ function ImagesGrid({ images, onSelectImage }) {
|
|
|
24
24
|
onSelectImage?.(image, images.indexOf(image));
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
return (jsx("div", { className: styles['images-grid'], "data-count": images.length, children: imageList.map((image, index) => image && (jsx("div", { "aria-label": `Open image ${index}`, className: clsx(styles['grid-item'], {
|
|
27
|
+
return (jsx("div", { className: clsx(styles['images-grid'], className), "data-count": images.length, children: imageList.map((image, index) => image && (jsx("div", { "aria-label": `Open image ${index}`, className: clsx(styles['grid-item'], {
|
|
28
28
|
[styles.clickable]: Boolean(onSelectImage),
|
|
29
29
|
}), onClick: () => onSelectImage?.(image, index), onKeyDown: event => handleKeydown(event, image), role: "button", tabIndex: 0, children: jsx(Image, { className: styles.image, fit: "contain", image: image, title: image.altText }) }, index))) }));
|
|
30
30
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import 'swiper/css';
|
|
2
2
|
import { ImageType } from '../../shared/model/image';
|
|
3
3
|
export interface ImageLightboxProps {
|
|
4
|
+
className?: string;
|
|
4
5
|
images: ImageType[];
|
|
5
6
|
initialSelectedIndex?: number;
|
|
6
7
|
onZoom?: (args: {
|
|
@@ -9,4 +10,4 @@ export interface ImageLightboxProps {
|
|
|
9
10
|
}) => void;
|
|
10
11
|
variant?: 'sm' | 'lg';
|
|
11
12
|
}
|
|
12
|
-
export declare function ImageLightbox({ images, initialSelectedIndex, onZoom, variant, }: ImageLightboxProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function ImageLightbox({ className, images, initialSelectedIndex, onZoom, variant, }: ImageLightboxProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -10,7 +10,7 @@ import { CarouselPagination } from '../../carousel/pagination/pagination.js';
|
|
|
10
10
|
import { Image } from '../image/image.js';
|
|
11
11
|
import styles from './image-lightbox.module.css.js';
|
|
12
12
|
|
|
13
|
-
function ImageLightbox({ images, initialSelectedIndex = 0, onZoom, variant = 'sm', }) {
|
|
13
|
+
function ImageLightbox({ className, images, initialSelectedIndex = 0, onZoom, variant = 'sm', }) {
|
|
14
14
|
const [thumbsSwiper, setThumbsSwiper] = useState();
|
|
15
15
|
const [currentIndex, setCurrentIndex] = useState(initialSelectedIndex);
|
|
16
16
|
const nextEl = useRef(null);
|
|
@@ -26,7 +26,7 @@ function ImageLightbox({ images, initialSelectedIndex = 0, onZoom, variant = 'sm
|
|
|
26
26
|
const scrollPercentage = clientY / height;
|
|
27
27
|
onZoom?.({ index: currentIndex, scrollPercentage });
|
|
28
28
|
}
|
|
29
|
-
return (jsxs("div", { className: clsx(styles['image-lightbox'], styles[variant]), children: [jsx(Swiper, { watchSlidesProgress: true, className: styles['thumbs-swiper'], direction: variant === 'sm' ? 'horizontal' : 'vertical', modules: [Thumb], onSwiper: swiper => setThumbsSwiper(swiper), slidesPerView: "auto", spaceBetween: 8, children: images.map((image, index) => (
|
|
29
|
+
return (jsxs("div", { className: clsx(styles['image-lightbox'], styles[variant], className), children: [jsx(Swiper, { watchSlidesProgress: true, className: styles['thumbs-swiper'], direction: variant === 'sm' ? 'horizontal' : 'vertical', modules: [Thumb], onSwiper: swiper => setThumbsSwiper(swiper), slidesPerView: "auto", spaceBetween: 8, children: images.map((image, index) => (
|
|
30
30
|
// eslint-disable-next-line @eslint-react/no-array-index-key
|
|
31
31
|
jsx(SwiperSlide, { className: styles.slide, children: jsx("div", { className: styles.thumb, children: jsx(Image, { className: styles.image, fit: "contain", height: 80, image: {
|
|
32
32
|
1: image['1'],
|
|
@@ -62,7 +62,7 @@ function CreateAccountForm({ errorType, isDisabled: _isDisabled = false, isPendi
|
|
|
62
62
|
});
|
|
63
63
|
};
|
|
64
64
|
// form header
|
|
65
|
-
const header = (jsx(Heading, { "data-test-selector": "
|
|
65
|
+
const header = (jsx(Heading, { "data-test-selector": "pageTitle", italic: true, size: "m", tag: "h1", uppercase: true, children: title }));
|
|
66
66
|
// form footer
|
|
67
67
|
const footer = (jsx(FormSegment, { children: jsx(Button, { "data-test-selector": "createAccount_createButton", isDisabled: isDisabled, isLoading: isPendingCreateAccount && 'Creating account...', type: "submit", withArrow: true, children: t('create account') }) }));
|
|
68
68
|
return (jsxs(Form, { "aria-label": title, autoComplete: true, className: styles['create-account-form'], errorMessage: errorType && errorMessages[errorType], footer: footer, header: header, onSubmit: handleSubmit, title: title, children: [jsxs(FormSegmentGroup, { children: [jsx(FormSegment, { children: jsx(TextField, { autoComplete: "username", "data-test-selector": "createAccount_email", inputMode: "email", isDisabled: isDisabled, isRequired: true, label: t('Email'), name: "email", type: "email", validate: value => {
|
|
@@ -20,8 +20,10 @@ function CreateAccountPage({ returnUrl } = {}) {
|
|
|
20
20
|
const { error: errorCreateAccount, isPending: isPendingCreateAccount, isSuccess, mutate: createAccount, } = useCreateAccount();
|
|
21
21
|
const isExistingAccount = errorCreateAccount instanceof ExistingAccountError;
|
|
22
22
|
const isDisabled = isSuccess || isExistingAccount;
|
|
23
|
-
const continuePath = returnUrl && returnUrl !== paths.ACCOUNT_CREATE
|
|
24
|
-
|
|
23
|
+
const continuePath = returnUrl && decodeURIComponent(returnUrl) !== paths.ACCOUNT_CREATE
|
|
24
|
+
? decodeURIComponent(returnUrl)
|
|
25
|
+
: paths.ACCOUNT;
|
|
26
|
+
const isReturnToShipping = returnUrl && decodeURIComponent(returnUrl) === paths.CHECKOUT_SHIPPING;
|
|
25
27
|
const onSubmit = ({ data }) => {
|
|
26
28
|
createAccount(data, {
|
|
27
29
|
onSuccess() {
|
|
@@ -40,7 +42,7 @@ function CreateAccountPage({ returnUrl } = {}) {
|
|
|
40
42
|
navigate(continuePath, { reload: true });
|
|
41
43
|
return;
|
|
42
44
|
}
|
|
43
|
-
return (jsxs(Fragment, { children: [jsx(SignInPageLayout, { fullHeight: true, children: jsx(CreateAccountForm, { errorType: errorType, isDisabled: isDisabled, isPendingCreateAccount: isPendingCreateAccount, onSubmit: onSubmit }) }), jsx(Dialog, { footer: jsx(Button, { color: "primary", href: continuePath, route: { reload: true }, size: "md", withArrow: true, children: jsx(FormattedMessage, { id: "Continue" }) }), hasCloseButton: false, isDismissable: false, isKeyboardDismissDisabled: true, isOpen: isSuccess && !isReturnToShipping, title: "Account created", children: jsx("p", { children: jsx(FormattedMessage, { id: "Your new Sonic Equipment account was succesfully created. You should receive an email soon with further instructions on how to activate this account. If you do not receive this email, please contact Customer Support." }) }) }), jsx(Dialog, { footer: jsx(Button, { color: "primary", href: `${paths.SIGN_IN}${returnUrl ? `?returnUrl=${continuePath}` : ''}`, route: { reload: true }, size: "md", withArrow: true, children: jsx(FormattedMessage, { id: "Continue to sign in" }) }), hasCloseButton: false, isDismissable: false, isKeyboardDismissDisabled: true, isOpen: isExistingAccount, title: "Existing account", children: jsx("p", { children: jsx(FormattedMessage, { id: "The email address you entered is already associated with an existing account. Please sign in to this account or contact Customer Support." }) }) })] }));
|
|
45
|
+
return (jsxs(Fragment, { children: [jsx(SignInPageLayout, { fullHeight: true, "data-test-selector": "create-account-page", children: jsx(CreateAccountForm, { errorType: errorType, isDisabled: isDisabled, isPendingCreateAccount: isPendingCreateAccount, onSubmit: onSubmit }) }), jsx(Dialog, { footer: jsx(Button, { color: "primary", href: continuePath, route: { reload: true }, size: "md", withArrow: true, children: jsx(FormattedMessage, { id: "Continue" }) }), hasCloseButton: false, isDismissable: false, isKeyboardDismissDisabled: true, isOpen: isSuccess && !isReturnToShipping, title: "Account created", children: jsx("p", { children: jsx(FormattedMessage, { id: "Your new Sonic Equipment account was succesfully created. You should receive an email soon with further instructions on how to activate this account. If you do not receive this email, please contact Customer Support." }) }) }), jsx(Dialog, { footer: jsx(Button, { color: "primary", href: `${paths.SIGN_IN}${returnUrl ? `?returnUrl=${continuePath}` : ''}`, route: { reload: true }, size: "md", withArrow: true, children: jsx(FormattedMessage, { id: "Continue to sign in" }) }), hasCloseButton: false, isDismissable: false, isKeyboardDismissDisabled: true, isOpen: isExistingAccount, title: "Existing account", children: jsx("p", { children: jsx(FormattedMessage, { id: "The email address you entered is already associated with an existing account. Please sign in to this account or contact Customer Support." }) }) })] }));
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
export { CreateAccountPage };
|
|
@@ -2,7 +2,8 @@ import { ReactNode } from 'react';
|
|
|
2
2
|
import { ImageType } from '../../../../shared/model/image';
|
|
3
3
|
export interface SignInPageLayoutProps {
|
|
4
4
|
children?: ReactNode;
|
|
5
|
+
'data-test-selector': string;
|
|
5
6
|
fullHeight?: boolean;
|
|
6
7
|
image?: ImageType;
|
|
7
8
|
}
|
|
8
|
-
export declare function SignInPageLayout({ children, fullHeight, image, }: SignInPageLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare function SignInPageLayout({ children, 'data-test-selector': dataTestSelector, fullHeight, image, }: SignInPageLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
|
-
import { useIsBreakpoint } from '../../../../shared/hooks/use-is-breakpoint.js';
|
|
5
4
|
import { Image } from '../../../../media/image/image.js';
|
|
6
5
|
import { SIGN_IN_PAGE_BACKGROUND_IMAGE } from './sign-in-page-background-image.js';
|
|
7
6
|
import styles from './sign-in-page-layout.module.css.js';
|
|
8
7
|
|
|
9
|
-
function SignInPageLayout({ children, fullHeight, image = SIGN_IN_PAGE_BACKGROUND_IMAGE, }) {
|
|
10
|
-
|
|
11
|
-
return (jsxs("div", { className: clsx(styles['sign-in-page-layout'], fullHeight && styles['full-height']), children: [jsx("section", { className: styles.main, children: children }), isLg && (jsx("div", { className: styles.side, children: jsx("div", { className: styles.image, children: jsx(Image, { image: image, title: "" }) }) }))] }));
|
|
8
|
+
function SignInPageLayout({ children, 'data-test-selector': dataTestSelector, fullHeight, image = SIGN_IN_PAGE_BACKGROUND_IMAGE, }) {
|
|
9
|
+
return (jsxs("div", { className: clsx(styles['sign-in-page-layout'], fullHeight && styles['full-height']), "data-test-selector": dataTestSelector, children: [jsx("section", { className: styles.main, children: children }), jsx("div", { className: styles.side, children: jsx("div", { className: styles.image, children: jsx(Image, { image: image, title: "" }) }) })] }));
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
export { SignInPageLayout };
|
|
@@ -37,7 +37,7 @@ function SignInPage({ returnUrl } = {}) {
|
|
|
37
37
|
navigate(returnUrl || paths.HOME, { reload: true });
|
|
38
38
|
};
|
|
39
39
|
const allowGuestSignIn = returnUrl === paths.CHECKOUT_SHIPPING;
|
|
40
|
-
const createAccountPath = `${paths.ACCOUNT_CREATE}${returnUrl ? `?returnUrl=${returnUrl}` : ''}`;
|
|
40
|
+
const createAccountPath = `${paths.ACCOUNT_CREATE}${returnUrl ? `?returnUrl=${encodeURIComponent(returnUrl)}` : ''}`;
|
|
41
41
|
const onSubmit = ({ data }) => {
|
|
42
42
|
resetSignIn();
|
|
43
43
|
resetCreateGuest();
|
|
@@ -57,7 +57,7 @@ function SignInPage({ returnUrl } = {}) {
|
|
|
57
57
|
const onRecoverPasswordDialogOpen = () => {
|
|
58
58
|
setRecoverPasswordDialogOpen(true);
|
|
59
59
|
};
|
|
60
|
-
return (jsxs(Fragment, { children: [jsx(SignInPageLayout, { fullHeight: true, children: jsx(SignInForm, { allowGuestSignIn: allowGuestSignIn, createAccountPath: createAccountPath, errorType: errorType, initialEmail: session?.isGuest ? '' : session?.email, initialRememberMe: session?.rememberMe, isDisabled: !session || isSuccess, isLoading: isLoading, isPendingGuestSignIn: isPendingCreateGuest, isPendingUserSignIn: isPendingSignIn, onRecoverPasswordDialogOpen: onRecoverPasswordDialogOpen, onSubmit: onSubmit }) }), jsx(RecoverPasswordDialog, { isOpen: isRecoverPasswordDialogOpen, onOpenChange: isOpen => setRecoverPasswordDialogOpen(isOpen) })] }));
|
|
60
|
+
return (jsxs(Fragment, { children: [jsx(SignInPageLayout, { fullHeight: true, "data-test-selector": "signInPage", children: jsx(SignInForm, { allowGuestSignIn: allowGuestSignIn, createAccountPath: createAccountPath, errorType: errorType, initialEmail: session?.isGuest ? '' : session?.email, initialRememberMe: session?.rememberMe, isDisabled: !session || isSuccess, isLoading: isLoading, isPendingGuestSignIn: isPendingCreateGuest, isPendingUserSignIn: isPendingSignIn, onRecoverPasswordDialogOpen: onRecoverPasswordDialogOpen, onSubmit: onSubmit }) }), jsx(RecoverPasswordDialog, { isOpen: isRecoverPasswordDialogOpen, onOpenChange: isOpen => setRecoverPasswordDialogOpen(isOpen) })] }));
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export { SignInPage };
|
|
@@ -82,7 +82,7 @@ function CartContent({ cartLines }) {
|
|
|
82
82
|
if (!currencyCode)
|
|
83
83
|
throw new Error(`Currency code not found for symbol ${currentCart.currencySymbol}`);
|
|
84
84
|
return (jsx(CheckoutPageLayout, { actions: {
|
|
85
|
-
primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutShippingCartTotalContinueButton", href:
|
|
85
|
+
primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutShippingCartTotalContinueButton", href: paths.CHECKOUT_SHIPPING, children: jsx(FormattedMessage, { id: "Start checkout" }) })),
|
|
86
86
|
secondary: isAuthenticated ? (jsx(Button, { color: "secondary", "data-test-selector": "saveCartForLaterButton", onClick: () => {
|
|
87
87
|
saveCartForLater.mutate({ cart: currentCart });
|
|
88
88
|
}, variant: "outline", children: jsx(FormattedMessage, { id: "Save order" }) })) : (jsx(Button, { color: "secondary", "data-test-selector": "saveCartForLaterButton", href: paths.SIGN_IN, variant: "outline", children: jsx(FormattedMessage, { id: "Save order" }) })),
|
|
@@ -51,7 +51,7 @@ function OrderConfirmationPageContent({ cart, }) {
|
|
|
51
51
|
label: t('Order confirmation'),
|
|
52
52
|
},
|
|
53
53
|
], "data-test-selector": "orderConfirmationPage", title: t('Order confirmation'), children: jsx(CheckoutPageLayout, { actions: {
|
|
54
|
-
primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutReviewAndSubmit_continueShopping", href:
|
|
54
|
+
primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutReviewAndSubmit_continueShopping", href: paths.HOME, children: jsx(FormattedMessage, { id: "Continue shopping" }) })),
|
|
55
55
|
secondary: (jsxs(Fragment, { children: [cart.canSaveOrder && (jsx(Button, { color: "secondary", onClick: () => {
|
|
56
56
|
saveCartForLater.mutate({ cart });
|
|
57
57
|
}, variant: "outline", children: jsx(FormattedMessage, { id: "Save order" }) })), jsx(PrintButton, {})] })),
|
|
@@ -9,7 +9,8 @@ import { AddressDataCard } from './components/address-data-card.js';
|
|
|
9
9
|
|
|
10
10
|
function ConnectedBillToAddressWidget({ billToId = 'current', } = {}) {
|
|
11
11
|
const paths = usePaths();
|
|
12
|
-
const {
|
|
12
|
+
const { pathname, search } = useLocation();
|
|
13
|
+
const href = `${pathname}${search}`;
|
|
13
14
|
const editAddressUrl = `${paths.ACCOUNT_EDIT_BILL_TO_ADDRESS}/${billToId}?returnUrl=${encodeURIComponent(href)}`;
|
|
14
15
|
const { data: billToAddress, error, isLoading, } = useFetchBillToAddress({ billToId });
|
|
15
16
|
return (jsx(AddressDataCard, { actions: [
|
|
@@ -9,7 +9,8 @@ import { AddressDataCard } from './components/address-data-card.js';
|
|
|
9
9
|
|
|
10
10
|
function ConnectedShipToAddressWidget({ billToId = 'current', shipToId = 'current', } = {}) {
|
|
11
11
|
const paths = usePaths();
|
|
12
|
-
const {
|
|
12
|
+
const { pathname, search } = useLocation();
|
|
13
|
+
const href = `${pathname}${search}`;
|
|
13
14
|
const editAddressUrl = `${paths.ACCOUNT_EDIT_BILL_TO_ADDRESS}/${billToId}${paths.ACCOUNT_EDIT_SHIP_TO_ADDRESS}/${shipToId}?returnUrl=${encodeURIComponent(href)}`;
|
|
14
15
|
const createAddressUrl = `${paths.ACCOUNT_EDIT_BILL_TO_ADDRESS}/${billToId}${paths.ACCOUNT_EDIT_SHIP_TO_ADDRESS}/new?returnUrl=${encodeURIComponent(href)}`;
|
|
15
16
|
const { data: shipToAddress, error, isLoading, } = useFetchShipToAddress({
|
|
@@ -6,7 +6,6 @@ import { ImageLightbox } from '../../../../../media/image-lightbox/image-lightbo
|
|
|
6
6
|
import { ZoomImage } from '../../../../../media/zoom-image/zoom-image.js';
|
|
7
7
|
import { Modal } from '../../../../../modals/modal/modal.js';
|
|
8
8
|
import { useDisclosure } from '../../../../../shared/hooks/use-disclosure.js';
|
|
9
|
-
import { useIsBreakpoint } from '../../../../../shared/hooks/use-is-breakpoint.js';
|
|
10
9
|
import styles from './product-detail-images.module.css.js';
|
|
11
10
|
|
|
12
11
|
const MAX_IMAGES = 5;
|
|
@@ -16,7 +15,6 @@ function ProductDetailImages({ images }) {
|
|
|
16
15
|
const [scrollPercentage, setScrollPercentage] = useState(0);
|
|
17
16
|
const { isOpen: isOpenModal, open: openModal, toggle: toggleModal, } = useDisclosure();
|
|
18
17
|
const { close: closeZoom, isOpen: isOpenZoom, open: openZoom, } = useDisclosure();
|
|
19
|
-
const isXl = useIsBreakpoint('xl');
|
|
20
18
|
if (images.length > MAX_IMAGES) {
|
|
21
19
|
images = images.slice(0, MAX_IMAGES);
|
|
22
20
|
}
|
|
@@ -29,7 +27,7 @@ function ProductDetailImages({ images }) {
|
|
|
29
27
|
setScrollPercentage(scrollPercentage);
|
|
30
28
|
openZoom();
|
|
31
29
|
}
|
|
32
|
-
return (jsxs(Fragment, { children: [
|
|
30
|
+
return (jsxs(Fragment, { children: [jsx(ImagesGrid, { className: styles['images-grid'], images: images, onSelectImage: (image, _index) => handleOpenImage(image) }), isOpenModal && (jsx(Modal, { hasCloseButton: true, isDismissable: true, isFullScreen: true, isKeyboardDismissDisabled: false, isOpen: isOpenModal, onOpenChange: toggleModal, shouldCloseOnInteractOutside: false, children: jsx("div", { className: styles['image-lightbox-modal'], children: jsx(ImageLightbox, { images: images, initialSelectedIndex: selectedImageIndex, onZoom: onZoom, variant: "lg" }) }) })), jsx(ImageLightbox, { className: styles['image-lightbox'], images: images, onZoom: onZoom }), isOpenZoom && (jsx(ZoomImage, { currentImage: images[selectedZoomImageIndex], isZoomed: isOpenZoom, onClose: closeZoom, scrollFromTopPercentage: scrollPercentage }))] }));
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
export { ProductDetailImages };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var styles = {"image-lightbox-modal":"product-detail-images-module-ERzjA"};
|
|
1
|
+
var styles = {"image-lightbox-modal":"product-detail-images-module-ERzjA","images-grid":"product-detail-images-module-cdIHn","image-lightbox":"product-detail-images-module-0udrk"};
|
|
2
2
|
|
|
3
3
|
export { styles as default };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { useEffect } from 'react';
|
|
3
4
|
import { ConnectedProductCard } from '../../../cards/product-card/connected-product-card.js';
|
|
4
5
|
import { CardCarousel } from '../../../carousel/card-carousel/card-carousel.js';
|
|
5
6
|
import { ProductUSPCarousel } from '../../../carousel/usp-carousel/product-usp-carousel.js';
|
|
@@ -15,7 +16,10 @@ import { ProductDetailsRecentlyViewedSection } from './components/product-detail
|
|
|
15
16
|
|
|
16
17
|
function ProductDetails({ data, priceComponent, }) {
|
|
17
18
|
const { breadCrumb, included, page, product, usps } = data;
|
|
18
|
-
|
|
19
|
+
const { mutate } = useMarkProductAsRecentlyViewed();
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
mutate({ productId: product.id });
|
|
22
|
+
}, [mutate, product]);
|
|
19
23
|
useDataLayer({
|
|
20
24
|
event: {
|
|
21
25
|
event: 'view_item',
|
|
@@ -3,12 +3,14 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
3
3
|
import { Button } from '../../../../buttons/button/button.js';
|
|
4
4
|
import { FormattedMessage } from '../../../../intl/formatted-message.js';
|
|
5
5
|
import { useIsBreakpoint } from '../../../../shared/hooks/use-is-breakpoint.js';
|
|
6
|
+
import { usePaths } from '../../../../shared/routing/use-paths.js';
|
|
6
7
|
import { Heading } from '../../../../typography/heading/heading.js';
|
|
7
8
|
import styles from './no-results.module.css.js';
|
|
8
9
|
|
|
9
10
|
function NoResults({ content, title }) {
|
|
11
|
+
const paths = usePaths();
|
|
10
12
|
const isLg = useIsBreakpoint('lg');
|
|
11
|
-
return (jsxs("div", { className: styles['no-results'], children: [jsx(Heading, { bold: false, className: styles.title, size: isLg ? 's' : 'xs', tag: "h2", children: title }), jsx("p", { className: styles.body, children: content }), jsx("div", { className: styles.buttons, children: jsx(Button, { withArrow: true, "data-test-selector": "buttonContinueShopping", href:
|
|
13
|
+
return (jsxs("div", { className: styles['no-results'], children: [jsx(Heading, { bold: false, className: styles.title, size: isLg ? 's' : 'xs', tag: "h2", children: title }), jsx("p", { className: styles.body, children: content }), jsx("div", { className: styles.buttons, children: jsx(Button, { withArrow: true, "data-test-selector": "buttonContinueShopping", href: paths.HOME, size: "md", children: jsx(FormattedMessage, { id: "Continue shopping" }) }) })] }));
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
export { NoResults };
|
|
@@ -12,10 +12,12 @@ function useFetchCurrentCartWithAtp({ forceRecalculation = true, select = cartMo
|
|
|
12
12
|
select(atp
|
|
13
13
|
? {
|
|
14
14
|
...cartResult.data,
|
|
15
|
-
cartLines: cartResult.data.cartLines?.map(line =>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
cartLines: cartResult.data.cartLines?.map(line => {
|
|
16
|
+
const matchingAtp = atp.find(a => a.productCode === line.erpNumber);
|
|
17
|
+
if (!matchingAtp)
|
|
18
|
+
return line;
|
|
19
|
+
return { ...line, atp: matchingAtp };
|
|
20
|
+
}),
|
|
19
21
|
}
|
|
20
22
|
: cartResult.data),
|
|
21
23
|
error: cartResult.error || error,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
productId
|
|
3
|
-
}
|
|
1
|
+
interface MarkProductAsRecentlyViewedParams {
|
|
2
|
+
productId: string;
|
|
3
|
+
}
|
|
4
|
+
export declare function useMarkProductAsRecentlyViewed(): import("@tanstack/react-query").UseMutationResult<void, Error, MarkProductAsRecentlyViewedParams, unknown>;
|
|
5
|
+
export {};
|
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
import { useQueryClient,
|
|
1
|
+
import { useQueryClient, useMutation } from '@tanstack/react-query';
|
|
2
2
|
import { markProductAsRecentlyViewed } from '../../services/product-service.js';
|
|
3
3
|
|
|
4
|
-
function useMarkProductAsRecentlyViewed(
|
|
4
|
+
function useMarkProductAsRecentlyViewed() {
|
|
5
5
|
const queryClient = useQueryClient();
|
|
6
|
-
return
|
|
7
|
-
|
|
8
|
-
gcTime: 0,
|
|
9
|
-
queryFn: () => {
|
|
6
|
+
return useMutation({
|
|
7
|
+
mutationFn: async ({ productId }) => {
|
|
10
8
|
markProductAsRecentlyViewed({ productId: productId });
|
|
11
9
|
queryClient.invalidateQueries({
|
|
12
10
|
queryKey: ['products', 'recently-viewed'],
|
|
13
11
|
});
|
|
14
12
|
},
|
|
15
|
-
queryKey: ['mark-product-as-recently-viewed', productId],
|
|
16
|
-
staleTime: 0,
|
|
17
13
|
});
|
|
18
14
|
}
|
|
19
15
|
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { config } from '../../../../config.js';
|
|
2
2
|
import { request } from '../../../fetch/request.js';
|
|
3
|
+
import { TIME } from '../../../utils/time.js';
|
|
3
4
|
|
|
4
5
|
async function fetchCountriesLanguages() {
|
|
5
6
|
const { body } = await request({
|
|
7
|
+
next: {
|
|
8
|
+
revalidate: 1 * TIME.DAY,
|
|
9
|
+
tags: ['countries-languages'],
|
|
10
|
+
},
|
|
6
11
|
url: `${config.SHOP_API_URL}/api/v1/websites/current?expand=languages%2Ccountries`,
|
|
7
12
|
});
|
|
8
13
|
return {
|
|
@@ -12,6 +17,10 @@ async function fetchCountriesLanguages() {
|
|
|
12
17
|
}
|
|
13
18
|
async function fetchCountriesWithLanguages() {
|
|
14
19
|
const { body } = await request({
|
|
20
|
+
next: {
|
|
21
|
+
revalidate: 1 * TIME.DAY,
|
|
22
|
+
tags: ['countries-languages'],
|
|
23
|
+
},
|
|
15
24
|
url: `${config.SHOP_API_URL}/api/v1/custom/countrylanguage`,
|
|
16
25
|
});
|
|
17
26
|
return body;
|
|
@@ -1 +1,5 @@
|
|
|
1
|
-
export
|
|
1
|
+
export interface DebouncedCallback<T extends (...args: any[]) => any> {
|
|
2
|
+
(...args: Parameters<T>): Promise<ReturnType<T>>;
|
|
3
|
+
cancel: VoidFunction;
|
|
4
|
+
}
|
|
5
|
+
export declare function useDebouncedCallback<T extends (...args: any[]) => any>(func: T, delay: number): DebouncedCallback<T>;
|
|
@@ -4,16 +4,16 @@ import { useRef, useCallback } from 'react';
|
|
|
4
4
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
5
|
function useDebouncedCallback(func, delay) {
|
|
6
6
|
const timeoutId = useRef();
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
const debounced = (...args) => new Promise(resolve => {
|
|
8
|
+
if (typeof window === 'undefined')
|
|
9
|
+
return resolve(func(...args));
|
|
10
|
+
clearTimeout(timeoutId.current);
|
|
11
|
+
timeoutId.current = setTimeout(() => {
|
|
12
|
+
resolve(func(...args));
|
|
13
|
+
}, delay);
|
|
14
|
+
});
|
|
15
|
+
debounced.cancel = () => clearTimeout(timeoutId.current);
|
|
16
|
+
return useCallback(debounced, [delay, func]);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export { useDebouncedCallback };
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
3
|
+
export declare const globalQueryClient: QueryClient;
|
|
4
|
+
export declare function ReactQueryContainer({ children, enableDevTools, queryClient, }: {
|
|
5
|
+
children: ReactNode | ((args: {
|
|
6
|
+
queryClient: QueryClient;
|
|
7
|
+
}) => ReactNode | ReactElement);
|
|
4
8
|
enableDevTools?: boolean;
|
|
9
|
+
queryClient?: QueryClient;
|
|
5
10
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -5,7 +5,7 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
|
|
5
5
|
import { environment } from '../utils/environment.js';
|
|
6
6
|
import { TIME } from '../utils/time.js';
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const globalQueryClient = new QueryClient({
|
|
9
9
|
defaultOptions: {
|
|
10
10
|
queries: {
|
|
11
11
|
/* Set gcTime and staleTime to 0 to disable react query cache */
|
|
@@ -15,8 +15,8 @@ const queryClient = new QueryClient({
|
|
|
15
15
|
},
|
|
16
16
|
},
|
|
17
17
|
});
|
|
18
|
-
function ReactQueryContainer({ children, enableDevTools = environment !== 'production', }) {
|
|
19
|
-
return (jsxs(QueryClientProvider, { client: queryClient, children: [enableDevTools && jsx(ReactQueryDevtools, { initialIsOpen: false }), children] }));
|
|
18
|
+
function ReactQueryContainer({ children, enableDevTools = environment !== 'production', queryClient = globalQueryClient, }) {
|
|
19
|
+
return (jsxs(QueryClientProvider, { client: queryClient, children: [enableDevTools && jsx(ReactQueryDevtools, { initialIsOpen: false }), children instanceof Function ? children({ queryClient }) : children] }));
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export { ReactQueryContainer };
|
|
22
|
+
export { ReactQueryContainer, globalQueryClient };
|
|
@@ -3,12 +3,12 @@ import qs from 'query-string';
|
|
|
3
3
|
import { useRouter } from './use-router.js';
|
|
4
4
|
|
|
5
5
|
function useLocation() {
|
|
6
|
-
const { url: { basePathname, pathname, search }, } = useRouter();
|
|
6
|
+
const { url: { basePathname, href, pathname, search }, } = useRouter();
|
|
7
7
|
const query = qs.parse(search || '');
|
|
8
8
|
return {
|
|
9
9
|
basePathname,
|
|
10
10
|
fullPathname: pathname,
|
|
11
|
-
href
|
|
11
|
+
href,
|
|
12
12
|
pathname: pathname.replace(new RegExp(`^${basePathname}`), ''),
|
|
13
13
|
query,
|
|
14
14
|
search,
|
|
@@ -41,8 +41,6 @@ function SidebarProvider({ children }) {
|
|
|
41
41
|
const { close, isDocked, isOpen, transition } = state;
|
|
42
42
|
return (jsxs("div", { className: clsx(styles['sidebar-container'], {
|
|
43
43
|
[styles['transition']]: transition,
|
|
44
|
-
[styles['docked']]: isDocked,
|
|
45
|
-
[styles['open']]: isOpen,
|
|
46
44
|
}), children: [jsx(SidebarDetectBreakpoint, {}), children, jsx(BackgroundOverlay, { isOpen: isDocked && isOpen, onClick: close })] }));
|
|
47
45
|
}
|
|
48
46
|
|
package/dist/styles.css
CHANGED
|
@@ -479,7 +479,7 @@ html {
|
|
|
479
479
|
grid-template-rows: 1fr;
|
|
480
480
|
}
|
|
481
481
|
|
|
482
|
-
.accordion-module-9WvAH .accordion-module-lf9d-:has(.accordion-module--Rwpb[disabled]) {
|
|
482
|
+
.accordion-module-9WvAH .accordion-module-lf9d-:has(.accordion-module--Rwpb[disabled]):not(.accordion-module-RnNRT) {
|
|
483
483
|
border-color: var(--color-brand-light-gray);
|
|
484
484
|
}
|
|
485
485
|
|
|
@@ -2218,6 +2218,21 @@ html {
|
|
|
2218
2218
|
content: '/';
|
|
2219
2219
|
margin-inline: 10px;
|
|
2220
2220
|
}
|
|
2221
|
+
.breadcrumb-module-CQGse .breadcrumb-module-hxhDY.breadcrumb-module-ToeDB {
|
|
2222
|
+
display: flex;
|
|
2223
|
+
}
|
|
2224
|
+
.breadcrumb-module-CQGse .breadcrumb-module-hxhDY.breadcrumb-module-np5GK {
|
|
2225
|
+
display: none;
|
|
2226
|
+
}
|
|
2227
|
+
@media (width >= 768px) {
|
|
2228
|
+
.breadcrumb-module-CQGse .breadcrumb-module-hxhDY.breadcrumb-module-ToeDB {
|
|
2229
|
+
display: none;
|
|
2230
|
+
}
|
|
2231
|
+
|
|
2232
|
+
.breadcrumb-module-CQGse .breadcrumb-module-hxhDY.breadcrumb-module-np5GK {
|
|
2233
|
+
display: flex;
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2221
2236
|
@media (width < 768px) {
|
|
2222
2237
|
.breadcrumb-module-CQGse .breadcrumb-module-hxhDY::after {
|
|
2223
2238
|
display: none;
|
|
@@ -3369,6 +3384,7 @@ html {
|
|
|
3369
3384
|
|
|
3370
3385
|
.product-card-module-pLaiB .product-card-module-XzunM {
|
|
3371
3386
|
z-index: var(--z-top);
|
|
3387
|
+
margin: 0;
|
|
3372
3388
|
grid-area: sku;
|
|
3373
3389
|
justify-self: start;
|
|
3374
3390
|
-webkit-user-select: all;
|
|
@@ -8555,6 +8571,20 @@ button.swiper-pagination-bullet {
|
|
|
8555
8571
|
padding: 64px 48px;
|
|
8556
8572
|
}
|
|
8557
8573
|
|
|
8574
|
+
.product-detail-images-module-cdIHn {
|
|
8575
|
+
display: none;
|
|
8576
|
+
}
|
|
8577
|
+
|
|
8578
|
+
@media (width >= 1024px) {
|
|
8579
|
+
.product-detail-images-module-0udrk {
|
|
8580
|
+
display: none;
|
|
8581
|
+
}
|
|
8582
|
+
|
|
8583
|
+
.product-detail-images-module-cdIHn {
|
|
8584
|
+
display: grid;
|
|
8585
|
+
}
|
|
8586
|
+
}
|
|
8587
|
+
|
|
8558
8588
|
.product-details-panel-module-MXfPm {
|
|
8559
8589
|
display: flex;
|
|
8560
8590
|
flex-direction: column;
|
package/package.json
CHANGED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import Cookies from 'js-cookie';
|
|
4
|
-
import { config } from '../../config.js';
|
|
5
|
-
|
|
6
|
-
const defaultCookieOptions = {
|
|
7
|
-
domain: config.COOKIE_DOMAIN,
|
|
8
|
-
expires: 365,
|
|
9
|
-
path: '/',
|
|
10
|
-
sameSite: 'None',
|
|
11
|
-
secure: true,
|
|
12
|
-
};
|
|
13
|
-
function useCookie(name, options = defaultCookieOptions) {
|
|
14
|
-
const cookieValue = Cookies.get()?.[name];
|
|
15
|
-
const [stateValue, setStateValue] = useState(cookieValue);
|
|
16
|
-
if (cookieValue !== stateValue) {
|
|
17
|
-
setStateValue(cookieValue);
|
|
18
|
-
}
|
|
19
|
-
function setValue(valueOrFn) {
|
|
20
|
-
setStateValue(oldValue => {
|
|
21
|
-
const newValue = typeof valueOrFn === 'function' ? valueOrFn(oldValue) : valueOrFn;
|
|
22
|
-
if (newValue) {
|
|
23
|
-
Cookies.set(name, newValue, options);
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
Cookies.remove(name);
|
|
27
|
-
}
|
|
28
|
-
return newValue;
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
return [stateValue, setValue];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export { defaultCookieOptions, useCookie };
|