@sonic-equipment/ui 192.0.0 → 194.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 (33) hide show
  1. package/dist/background-overlay/background-overlay.js +11 -5
  2. package/dist/exports.d.ts +1 -1
  3. package/dist/header/buttons/account/connected-account-button.d.ts +1 -2
  4. package/dist/header/buttons/account/connected-account-button.js +10 -4
  5. package/dist/header/header.js +3 -2
  6. package/dist/index.js +2 -2
  7. package/dist/navigation/mobile-navigation/mobile-navigation.js +3 -2
  8. package/dist/pages/account/create-account-page/create-account-page.js +5 -4
  9. package/dist/pages/account/sign-in-page/sign-in-page.js +5 -4
  10. package/dist/pages/checkout/cart-page/cart-page.js +7 -5
  11. package/dist/pages/checkout/order-confirmation-page/order-confirmation-page-content.js +4 -3
  12. package/dist/pages/checkout/order-confirmation-page/order-confirmation-page.js +5 -4
  13. package/dist/pages/checkout/payment-page/payment-page-content.js +4 -3
  14. package/dist/pages/checkout/payment-page/payment-page.js +9 -8
  15. package/dist/pages/checkout/shipping-page/components/currency-change-dialog.js +3 -2
  16. package/dist/pages/checkout/shipping-page/components/readonly-address.js +4 -3
  17. package/dist/pages/checkout/shipping-page/shipping-page-content.js +4 -3
  18. package/dist/pages/checkout/shipping-page/shipping-page.js +9 -8
  19. package/dist/pages/error-page/error-page.js +4 -3
  20. package/dist/pages/my-sonic/actions/change-password/connected-change-password-dialog.js +3 -2
  21. package/dist/pages/my-sonic/navigation/connected-my-sonic-navigation.js +3 -2
  22. package/dist/pages/my-sonic/navigation/my-sonic-desktop-navigation.js +2 -1
  23. package/dist/pages/my-sonic/navigation/my-sonic-mobile-navigation.js +2 -1
  24. package/dist/pages/my-sonic/navigation/my-sonic-navigation-items.d.ts +1 -1
  25. package/dist/pages/my-sonic/navigation/my-sonic-navigation-items.js +31 -23
  26. package/dist/shared/routing/route-provider.d.ts +3 -2
  27. package/dist/shared/routing/route-provider.js +2 -1
  28. package/dist/shared/routing/types.d.ts +18 -0
  29. package/dist/shared/routing/use-paths.d.ts +2 -0
  30. package/dist/shared/routing/use-paths.js +10 -0
  31. package/package.json +3 -3
  32. package/dist/pages/paths.d.ts +0 -17
  33. package/dist/pages/paths.js +0 -19
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { useMemo, useEffect } from 'react';
2
+ import { useState, useEffect } from 'react';
3
3
  import { BackgroundOverlayManager } from './background-overlay-manager.js';
4
4
 
5
5
  /**
@@ -10,10 +10,16 @@ function BackgroundOverlay({ isOpen, onClick, onClose, position = 'in-front', })
10
10
  * An instance of the BackgroundOverlay class is
11
11
  * created using the BackgroundOverlayManager.
12
12
  */
13
- const backgroundOverlay = useMemo(() => BackgroundOverlayManager.createBackgroundOverlay(), []);
13
+ const [backgroundOverlay, setBackgroundOverlay] = useState();
14
14
  useEffect(() => {
15
+ // eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
16
+ setBackgroundOverlay(backgroundOverlay => {
17
+ if (backgroundOverlay)
18
+ return backgroundOverlay;
19
+ return BackgroundOverlayManager.createBackgroundOverlay();
20
+ });
15
21
  /* Mount or update the background overlay instance */
16
- backgroundOverlay.mountOrUpdate({
22
+ backgroundOverlay?.mountOrUpdate({
17
23
  isVisible: isOpen,
18
24
  onClick,
19
25
  onClose,
@@ -22,11 +28,11 @@ function BackgroundOverlay({ isOpen, onClick, onClose, position = 'in-front', })
22
28
  }, [backgroundOverlay, isOpen, onClick, onClose, position]);
23
29
  useEffect(() => {
24
30
  /* Show or hide the background overlay */
25
- backgroundOverlay.show(isOpen);
31
+ backgroundOverlay?.show(isOpen);
26
32
  }, [backgroundOverlay, isOpen]);
27
33
  useEffect(() => {
28
34
  /* Unmount the background overlay instance */
29
- return () => backgroundOverlay.unmount();
35
+ return () => backgroundOverlay?.unmount();
30
36
  }, [backgroundOverlay]);
31
37
  return null;
32
38
  }
package/dist/exports.d.ts CHANGED
@@ -267,7 +267,6 @@ export * from './pages/my-sonic/widgets/connected-bill-to-address-widget';
267
267
  export * from './pages/my-sonic/widgets/connected-customer-information-widget';
268
268
  export * from './pages/my-sonic/widgets/connected-ship-to-address-widget';
269
269
  export * from './pages/my-sonic/widgets/connected-user-account-widget';
270
- export * from './pages/paths';
271
270
  export * from './pages/product/components/product-overview';
272
271
  export * from './pages/product/layouts/product-details-page-layout/product-details-page-layout';
273
272
  export * from './pages/product/product-details-page/components/product-details-images/product-detail-images';
@@ -404,6 +403,7 @@ export * from './shared/routing/types';
404
403
  export * from './shared/routing/use-location';
405
404
  export * from './shared/routing/use-navigate';
406
405
  export * from './shared/routing/use-on-navigate';
406
+ export * from './shared/routing/use-paths';
407
407
  export * from './shared/routing/use-route-link';
408
408
  export * from './shared/routing/use-route-link-element';
409
409
  export * from './shared/routing/with-routing';
@@ -1,7 +1,6 @@
1
1
  export interface ConnectedAccountButtonProps {
2
2
  className?: string;
3
3
  'data-test-selector'?: string;
4
- href?: string;
5
4
  onClick?: () => void;
6
5
  }
7
- export declare function ConnectedAccountButton({ className, 'data-test-selector': dataTestSelector, href, onClick, }: ConnectedAccountButtonProps): import("react/jsx-runtime").JSX.Element;
6
+ export declare function ConnectedAccountButton({ className, 'data-test-selector': dataTestSelector, onClick, }: ConnectedAccountButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -3,12 +3,18 @@ import { jsx } from 'react/jsx-runtime';
3
3
  import { IconButton } from '../../../buttons/icon-button/icon-button.js';
4
4
  import { useFormattedMessage } from '../../../intl/use-formatted-message.js';
5
5
  import { AccountIcon } from '../../../navigation/account-icon/account-icon.js';
6
- import { useFetchSession } from '../../../shared/api/storefront/hooks/authentication/use-fetch-session.js';
6
+ import { useIsAuthenticated } from '../../../shared/api/storefront/hooks/authentication/use-is-authenticated.js';
7
+ import { useLocation } from '../../../shared/routing/use-location.js';
8
+ import { usePaths } from '../../../shared/routing/use-paths.js';
7
9
 
8
- function ConnectedAccountButton({ className, 'data-test-selector': dataTestSelector, href, onClick, }) {
10
+ function ConnectedAccountButton({ className, 'data-test-selector': dataTestSelector, onClick, }) {
11
+ const paths = usePaths();
9
12
  const t = useFormattedMessage();
10
- const { data: { isAuthenticated } = {} } = useFetchSession();
11
- return (jsx(IconButton, { className: className, "data-authenticated": isAuthenticated ? true : false, "data-test-selector": dataTestSelector, href: href, onClick: onClick, children: jsx(AccountIcon, { "aria-label": isAuthenticated ? t('My Sonic') : t('Sign in or create account'), isAuthenticated: isAuthenticated }) }));
13
+ const isAuthenticated = useIsAuthenticated();
14
+ const { href: returnUrl } = useLocation();
15
+ return (jsx(IconButton, { className: className, "data-authenticated": isAuthenticated ? true : false, "data-test-selector": dataTestSelector, href: isAuthenticated
16
+ ? paths.ACCOUNT
17
+ : `${paths.SIGN_IN}${returnUrl ? `?returnUrl=${encodeURIComponent(returnUrl)}` : ''}`, onClick: onClick, children: jsx(AccountIcon, { "aria-label": isAuthenticated ? t('My Sonic') : t('Sign in or create account'), isAuthenticated: isAuthenticated }) }));
12
18
  }
13
19
 
14
20
  export { ConnectedAccountButton };
@@ -5,11 +5,11 @@ import clsx from 'clsx';
5
5
  import { useDrawer } from '../drawer/use-drawer.js';
6
6
  import { useGlobalSearchDisclosure } from '../global-search/global-search-provider/use-search-disclosure.js';
7
7
  import { useFormattedMessage } from '../intl/use-formatted-message.js';
8
- import { PATHS } from '../pages/paths.js';
9
8
  import { isNavigationLink, isNavigationSection, isNavigationLinkItem } from '../shared/api/bff/model/bff.model.js';
10
9
  import { useIsBreakpoint } from '../shared/hooks/use-is-breakpoint.js';
11
10
  import { useResizeObserver } from '../shared/hooks/use-resize-observer.js';
12
11
  import { useOnNavigate } from '../shared/routing/use-on-navigate.js';
12
+ import { usePaths } from '../shared/routing/use-paths.js';
13
13
  import { ConnectedAccountButton } from './buttons/account/connected-account-button.js';
14
14
  import { ConnectedCartButton } from './buttons/cart/connected-cart-button.js';
15
15
  import { ConnectedFavoritesButton } from './buttons/favorites/connected-favorites-button.js';
@@ -24,6 +24,7 @@ import { SonicLogo } from './sonic-logo/sonic-logo.js';
24
24
  import styles from './header.module.css.js';
25
25
 
26
26
  function Header({ className, headerNavigationSection, sticky, }) {
27
+ const paths = usePaths();
27
28
  const [activeLinkGroup, setActiveLinkGroup] = useState();
28
29
  const t = useFormattedMessage();
29
30
  const isXl = useIsBreakpoint('xl');
@@ -72,7 +73,7 @@ function Header({ className, headerNavigationSection, sticky, }) {
72
73
  const mainNavigationSection = headerNavigationSection?.items
73
74
  .filter(isNavigationSection)
74
75
  .find(item => item.key === 'main-navigation');
75
- return (jsxs(Fragment, { children: [jsx("header", { ref: headerRef, className: clsx(styles['header'], sticky && styles['sticky'], className), "data-test-selector": "pageHeader", children: jsx(HeaderLayout, { hamburgerButton: jsx(HamburgerButton, { "aria-controls": "mobile-navigation", "data-test-selector": "pageHeaderHamburgerButton", isActive: mobileNavigationOpen, onActiveChange: toggleMobileNavigation }), hasDrawersOpen: hasDrawersOpen, logo: jsx(SonicLogo, { "data-test-selector": "pageHeaderLogo", href: homeLink?.href || undefined, title: t('Home') }), mainNavigation: jsx(NavigationLinkList, { activeLink: activeLinkGroup, "data-test-selector": "pageHeaderMainNavigation", navigationSection: mainNavigationSection, onSubmenuToggle: toggleActiveSubmenu }), navigationActions: jsxs(Fragment, { children: [jsx(ConnectedAccountButton, { "data-test-selector": "pageHeaderAccountButton", href: PATHS.ACCOUNT }), jsx(ConnectedFavoritesButton, { "data-test-selector": "pageHeaderFavoritesButton", href: PATHS.FAVORITES }), jsx(ConnectedCartButton, { "data-test-selector": "pageHeaderCartButton", href: PATHS.CART })] }), search: jsx(SearchButton, { "aria-controls": "global-search", "data-test-selector": "pageHeaderSearchButton", isActive: searchOpen, onActiveChange: toggleSearch }) }) }), jsx(SearchDrawer, { groupId: searchGroupId, instanceId: searchInstanceId }), !isXl && (jsx(MobileNavigationDrawer, { groupId: mobileNavigationDrawer.groupId, instanceId: mobileNavigationDrawer.instanceId, linkItems: mainNavigationSection?.items.filter(isNavigationLinkItem) })), isXl && (jsx(DesktopNavigationDrawer, { groupId: desktopNavigationDrawer.groupId, instanceId: desktopNavigationDrawer.instanceId, linkGroup: activeLinkGroup, onClosed: () => setActiveLinkGroup(undefined) }))] }));
76
+ return (jsxs(Fragment, { children: [jsx("header", { ref: headerRef, className: clsx(styles['header'], sticky && styles['sticky'], className), "data-test-selector": "pageHeader", children: jsx(HeaderLayout, { hamburgerButton: jsx(HamburgerButton, { "aria-controls": "mobile-navigation", "data-test-selector": "pageHeaderHamburgerButton", isActive: mobileNavigationOpen, onActiveChange: toggleMobileNavigation }), hasDrawersOpen: hasDrawersOpen, logo: jsx(SonicLogo, { "data-test-selector": "pageHeaderLogo", href: homeLink?.href || undefined, title: t('Home') }), mainNavigation: jsx(NavigationLinkList, { activeLink: activeLinkGroup, "data-test-selector": "pageHeaderMainNavigation", navigationSection: mainNavigationSection, onSubmenuToggle: toggleActiveSubmenu }), navigationActions: jsxs(Fragment, { children: [jsx(ConnectedAccountButton, { "data-test-selector": "pageHeaderAccountButton" }), jsx(ConnectedFavoritesButton, { "data-test-selector": "pageHeaderFavoritesButton", href: paths.FAVORITES }), jsx(ConnectedCartButton, { "data-test-selector": "pageHeaderCartButton", href: paths.CART })] }), search: jsx(SearchButton, { "aria-controls": "global-search", "data-test-selector": "pageHeaderSearchButton", isActive: searchOpen, onActiveChange: toggleSearch }) }) }), jsx(SearchDrawer, { groupId: searchGroupId, instanceId: searchInstanceId }), !isXl && (jsx(MobileNavigationDrawer, { groupId: mobileNavigationDrawer.groupId, instanceId: mobileNavigationDrawer.instanceId, linkItems: mainNavigationSection?.items.filter(isNavigationLinkItem) })), isXl && (jsx(DesktopNavigationDrawer, { groupId: desktopNavigationDrawer.groupId, instanceId: desktopNavigationDrawer.instanceId, linkGroup: activeLinkGroup, onClosed: () => setActiveLinkGroup(undefined) }))] }));
76
77
  }
77
78
 
78
79
  export { Header };
package/dist/index.js CHANGED
@@ -262,14 +262,13 @@ export { MySonicLayoutTitle } from './pages/my-sonic/layouts/my-sonic-layout/my-
262
262
  export { ConnectedMySonicNavigation } from './pages/my-sonic/navigation/connected-my-sonic-navigation.js';
263
263
  export { MySonicDesktopNavigation } from './pages/my-sonic/navigation/my-sonic-desktop-navigation.js';
264
264
  export { MySonicMobileNavigation } from './pages/my-sonic/navigation/my-sonic-mobile-navigation.js';
265
- export { mySonicNavigationItems } from './pages/my-sonic/navigation/my-sonic-navigation-items.js';
265
+ export { useMySonicNavigationItems } from './pages/my-sonic/navigation/my-sonic-navigation-items.js';
266
266
  export { OrderHistory } from './pages/my-sonic/pages/order-history/order-history.js';
267
267
  export { AddressDataCard } from './pages/my-sonic/widgets/components/address-data-card.js';
268
268
  export { ConnectedBillToAddressWidget } from './pages/my-sonic/widgets/connected-bill-to-address-widget.js';
269
269
  export { ConnectedCustomerInformationWidget } from './pages/my-sonic/widgets/connected-customer-information-widget.js';
270
270
  export { ConnectedShipToAddressWidget } from './pages/my-sonic/widgets/connected-ship-to-address-widget.js';
271
271
  export { ConnectedUserAccountWidget } from './pages/my-sonic/widgets/connected-user-account-widget.js';
272
- export { PATHS } from './pages/paths.js';
273
272
  export { ProductOverview } from './pages/product/components/product-overview.js';
274
273
  export { ProductDetailsPageLayout } from './pages/product/layouts/product-details-page-layout/product-details-page-layout.js';
275
274
  export { ProductDetailImages } from './pages/product/product-details-page/components/product-details-images/product-detail-images.js';
@@ -403,6 +402,7 @@ export { buildHref } from './shared/routing/route-utils.js';
403
402
  export { useLocation } from './shared/routing/use-location.js';
404
403
  export { useNavigate } from './shared/routing/use-navigate.js';
405
404
  export { useOnNavigate } from './shared/routing/use-on-navigate.js';
405
+ export { usePaths } from './shared/routing/use-paths.js';
406
406
  export { useRouteLink } from './shared/routing/use-route-link.js';
407
407
  export { useRouteLinkElement } from './shared/routing/use-route-link-element.js';
408
408
  export { withRouting } from './shared/routing/with-routing.js';
@@ -6,9 +6,9 @@ import { SonicLogo } from '../../header/sonic-logo/sonic-logo.js';
6
6
  import { useFormattedMessage } from '../../intl/use-formatted-message.js';
7
7
  import { MenuList } from '../../lists/menu-list/menu-list.js';
8
8
  import { MenuListItem } from '../../lists/menu-list/menu-list-item.js';
9
- import { PATHS } from '../../pages/paths.js';
10
9
  import { useFetchSession } from '../../shared/api/storefront/hooks/authentication/use-fetch-session.js';
11
10
  import { useFetchCurrentCartCount } from '../../shared/api/storefront/hooks/cart/use-fetch-current-cart-count.js';
11
+ import { usePaths } from '../../shared/routing/use-paths.js';
12
12
  import { AccountIcon } from '../account-icon/account-icon.js';
13
13
  import { CartIcon } from '../cart-icon/cart-icon.js';
14
14
  import { FavoriteIcon } from '../favorite-icon/favorite-icon.js';
@@ -17,9 +17,10 @@ import styles from './mobile-navigation.module.css.js';
17
17
 
18
18
  function MobileNavigation({ id, isActive, linkItems, onActiveChange, }) {
19
19
  const t = useFormattedMessage();
20
+ const paths = usePaths();
20
21
  const { data: { isAuthenticated } = {} } = useFetchSession();
21
22
  const cartCount = useFetchCurrentCartCount();
22
- return (jsxs("section", { "aria-label": t('Main menu'), className: clsx(styles['mobile-navigation'], isActive && styles['active']), "data-test-selector": "mobileNavigationMenu", id: id, children: [jsxs("header", { className: styles['header'], children: [jsx("div", { className: styles['logo'], role: "presentation", children: jsx(SonicLogo, {}) }), jsx("div", { className: styles['hamburger'], children: jsx(HamburgerButton, { "aria-controls": "mobile-navigation", "data-test-selector": "mobileNavigationHamburgerButton", isActive: isActive, onActiveChange: onActiveChange }) })] }), jsx(PanelNavigation, { allowBack: true, className: styles['panels'], "data-test-selector": "mobileNavigationPanel", isNarrow: true, linkItems: linkItems, variant: "primary", children: jsxs(MenuList, { header: { label: t('My Sonic') }, scrollable: false, children: [jsx(MenuListItem, { badge: jsx(AccountIcon, { isAuthenticated: isAuthenticated }), "data-authenticated": isAuthenticated ? true : false, "data-test-selector": "mobileNavigationAccountButton", href: PATHS.ACCOUNT, children: isAuthenticated ? t('My Sonic') : t('Sign in or create account') }), jsx(MenuListItem, { badge: jsx(FavoriteIcon, {}), "data-test-selector": "mobileNavigationFavoritesButton", href: PATHS.FAVORITES, children: t('Favorites') }), jsx(MenuListItem, { badge: jsx(CartIcon, { count: cartCount }), "data-count": cartCount, "data-test-selector": "mobileNavigationCartButton", href: PATHS.CART, children: t('Shopping cart') })] }) })] }));
23
+ return (jsxs("section", { "aria-label": t('Main menu'), className: clsx(styles['mobile-navigation'], isActive && styles['active']), "data-test-selector": "mobileNavigationMenu", id: id, children: [jsxs("header", { className: styles['header'], children: [jsx("div", { className: styles['logo'], role: "presentation", children: jsx(SonicLogo, {}) }), jsx("div", { className: styles['hamburger'], children: jsx(HamburgerButton, { "aria-controls": "mobile-navigation", "data-test-selector": "mobileNavigationHamburgerButton", isActive: isActive, onActiveChange: onActiveChange }) })] }), jsx(PanelNavigation, { allowBack: true, className: styles['panels'], "data-test-selector": "mobileNavigationPanel", isNarrow: true, linkItems: linkItems, variant: "primary", children: jsxs(MenuList, { header: { label: t('My Sonic') }, scrollable: false, children: [jsx(MenuListItem, { badge: jsx(AccountIcon, { isAuthenticated: isAuthenticated }), "data-authenticated": isAuthenticated ? true : false, "data-test-selector": "mobileNavigationAccountButton", href: paths.ACCOUNT, children: isAuthenticated ? t('My Sonic') : t('Sign in or create account') }), jsx(MenuListItem, { badge: jsx(FavoriteIcon, {}), "data-test-selector": "mobileNavigationFavoritesButton", href: paths.FAVORITES, children: t('Favorites') }), jsx(MenuListItem, { badge: jsx(CartIcon, { count: cartCount }), "data-count": cartCount, "data-test-selector": "mobileNavigationCartButton", href: paths.CART, children: t('Shopping cart') })] }) })] }));
23
24
  }
24
25
 
25
26
  export { MobileNavigation };
@@ -8,19 +8,20 @@ import { useCreateAccount } from '../../../shared/api/storefront/hooks/account/u
8
8
  import { useFetchSession } from '../../../shared/api/storefront/hooks/authentication/use-fetch-session.js';
9
9
  import { ExistingAccountError } from '../../../shared/api/storefront/services/account-service.js';
10
10
  import { useNavigate } from '../../../shared/routing/use-navigate.js';
11
+ import { usePaths } from '../../../shared/routing/use-paths.js';
11
12
  import { LoadingPage } from '../../loading-page/loading-page.js';
12
- import { PATHS } from '../../paths.js';
13
13
  import { CreateAccountForm } from '../components/create-account-form/create-account-form.js';
14
14
  import { SignInPageLayout } from '../layouts/sign-in-page-layout/sign-in-page-layout.js';
15
15
 
16
16
  function CreateAccountPage({ returnUrl } = {}) {
17
+ const paths = usePaths();
17
18
  const { navigate } = useNavigate();
18
19
  const { data: session, isLoading: isLoadingSession } = useFetchSession();
19
20
  const { error: errorCreateAccount, isPending: isPendingCreateAccount, isSuccess, mutate: createAccount, } = useCreateAccount();
20
21
  const isExistingAccount = errorCreateAccount instanceof ExistingAccountError;
21
22
  const isDisabled = isSuccess || isExistingAccount;
22
- const continuePath = returnUrl && returnUrl !== PATHS.ACCOUNT_CREATE ? returnUrl : PATHS.ACCOUNT;
23
- const isReturnToShipping = returnUrl === PATHS.CHECKOUT_SHIPPING;
23
+ const continuePath = returnUrl && returnUrl !== paths.ACCOUNT_CREATE ? returnUrl : paths.ACCOUNT;
24
+ const isReturnToShipping = returnUrl === paths.CHECKOUT_SHIPPING;
24
25
  const onSubmit = ({ data }) => {
25
26
  createAccount(data, {
26
27
  onSuccess() {
@@ -39,7 +40,7 @@ function CreateAccountPage({ returnUrl } = {}) {
39
40
  navigate(continuePath, { reload: true });
40
41
  return;
41
42
  }
42
- 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." }) }) })] }));
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." }) }) })] }));
43
44
  }
44
45
 
45
46
  export { CreateAccountPage };
@@ -8,11 +8,12 @@ import { useSignIn } from '../../../shared/api/storefront/hooks/authentication/u
8
8
  import { isRequestError } from '../../../shared/fetch/request.js';
9
9
  import { useDisclosure } from '../../../shared/hooks/use-disclosure.js';
10
10
  import { useNavigate } from '../../../shared/routing/use-navigate.js';
11
- import { PATHS } from '../../paths.js';
11
+ import { usePaths } from '../../../shared/routing/use-paths.js';
12
12
  import { SignInForm } from '../components/sign-in-form/sign-in-form.js';
13
13
  import { SignInPageLayout } from '../layouts/sign-in-page-layout/sign-in-page-layout.js';
14
14
 
15
15
  function SignInPage({ returnUrl } = {}) {
16
+ const paths = usePaths();
16
17
  const { navigate } = useNavigate();
17
18
  const [isSuccess, setIsSuccess] = useState(false);
18
19
  const { isOpen: isRecoverPasswordDialogOpen, setIsOpen: setRecoverPasswordDialogOpen, } = useDisclosure(false);
@@ -33,10 +34,10 @@ function SignInPage({ returnUrl } = {}) {
33
34
  }, [errorCreateGuest, errorSignIn]);
34
35
  const onSuccess = () => {
35
36
  setIsSuccess(true);
36
- navigate(returnUrl || PATHS.HOME, { reload: true });
37
+ navigate(returnUrl || paths.HOME, { reload: true });
37
38
  };
38
- const allowGuestSignIn = returnUrl === PATHS.CHECKOUT_SHIPPING;
39
- const createAccountPath = `${PATHS.ACCOUNT_CREATE}${returnUrl ? `?returnUrl=${returnUrl}` : ''}`;
39
+ const allowGuestSignIn = returnUrl === paths.CHECKOUT_SHIPPING;
40
+ const createAccountPath = `${paths.ACCOUNT_CREATE}${returnUrl ? `?returnUrl=${returnUrl}` : ''}`;
40
41
  const onSubmit = ({ data }) => {
41
42
  resetSignIn();
42
43
  resetCreateGuest();
@@ -19,11 +19,12 @@ import { Button } from '../../../buttons/button/button.js';
19
19
  import { useFetchCurrentCartLinesWithAtp } from '../../../shared/api/storefront/hooks/cart/use-fetch-current-cart-lines-with-atp.js';
20
20
  import { useFetchCurrentCartWithAtp } from '../../../shared/api/storefront/hooks/cart/use-fetch-current-cart-with-atp.js';
21
21
  import { getCurrencyCodeBySymbol } from '../../../shared/model/currency.js';
22
+ import { usePaths } from '../../../shared/routing/use-paths.js';
22
23
  import { ensureNumber } from '../../../shared/utils/number.js';
23
- import { PATHS } from '../../paths.js';
24
24
  import { EmptyCart } from './components/empty-cart-page.js';
25
25
 
26
26
  function CartContent({ cartLines }) {
27
+ const paths = usePaths();
27
28
  const { addToast } = useToast();
28
29
  const { data: currentCart } = useFetchCurrentCartWithAtp();
29
30
  const saveCartForLater = useSaveCartForLater({
@@ -84,7 +85,7 @@ function CartContent({ cartLines }) {
84
85
  primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutShippingCartTotalContinueButton", href: "/CheckoutShipping", children: jsx(FormattedMessage, { id: "Start checkout" }) })),
85
86
  secondary: isAuthenticated ? (jsx(Button, { color: "secondary", "data-test-selector": "saveCartForLaterButton", onClick: () => {
86
87
  saveCartForLater.mutate({ cart: currentCart });
87
- }, 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" }) })),
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" }) })),
88
89
  }, mobileSummary: jsx(CartTotalsSummary, { currencyCode: currencyCode, totalAmount: currentCart.orderGrandTotal }), overview: jsx(CartTotals, { currencyCode: currencyCode, shippingCost: currentCart.shippingAndHandling, subtotal: currentCart.orderSubTotal, tax: currentCart.totalTax, total: currentCart.orderGrandTotal, vatPercentage: cartLines[0]?.pricing?.vatRate || 0 }), children: jsx(OrderLineList, { onRemoveAll: () => deleteCurrentCart.mutate(), children: cartLines.map(cartLine => (jsx(ConnectedOrderLineCard, { deliveryDate: cartLine.atp?.date ?? null, href: cartLine.productUri, image: {
89
90
  fit: 'contain',
90
91
  image: {
@@ -102,6 +103,7 @@ function CartContent({ cartLines }) {
102
103
  }, productId: cartLine.productId || '', sku: cartLine.erpNumber || '', tags: [cartLine.properties.label].filter(Boolean), title: cartLine.shortDescription }, cartLine.id))) }) }));
103
104
  }
104
105
  function CartPage() {
106
+ const paths = usePaths();
105
107
  const t = useFormattedMessage();
106
108
  const { data: cartLines, error, isLoading, } = useFetchCurrentCartLinesWithAtp();
107
109
  if (error)
@@ -109,9 +111,9 @@ function CartPage() {
109
111
  if (isLoading)
110
112
  return jsx(LoadingPage, {});
111
113
  return (jsx(Page, { breadcrumb: [
112
- { href: PATHS.HOME, label: 'home' },
113
- { href: PATHS.CART, label: t('Cart') },
114
- ], canonicalUrl: PATHS.CART, "data-test-selector": "cartPage", title: t('Cart'), children: cartLines?.length ? (jsx(CartContent, { cartLines: cartLines })) : (jsx(EmptyCart, {})) }));
114
+ { href: paths.HOME, label: 'home' },
115
+ { href: paths.CART, label: t('Cart') },
116
+ ], canonicalUrl: paths.CART, "data-test-selector": "cartPage", title: t('Cart'), children: cartLines?.length ? (jsx(CartContent, { cartLines: cartLines })) : (jsx(EmptyCart, {})) }));
115
117
  }
116
118
 
117
119
  export { CartPage };
@@ -11,10 +11,10 @@ import { useFormattedMessage } from '../../../intl/use-formatted-message.js';
11
11
  import { OrderLineList } from '../../../lists/orderline-list/orderline-list.js';
12
12
  import { useSaveCartForLater } from '../../../shared/api/storefront/hooks/cart/use-save-cart-for-later.js';
13
13
  import { getCurrencyCodeBySymbol } from '../../../shared/model/currency.js';
14
+ import { usePaths } from '../../../shared/routing/use-paths.js';
14
15
  import { ensureNumber } from '../../../shared/utils/number.js';
15
16
  import { useToast } from '../../../toast/use-toast.js';
16
17
  import { Page } from '../../components/page/page.js';
17
- import { PATHS } from '../../paths.js';
18
18
  import { BillingAndInvoiceInformation } from '../components/billing-and-invoice-information.js';
19
19
  import { CheckoutPageLayout } from '../layouts/checkout-page-layout/checkout-page-layout.js';
20
20
  import { CheckoutPageSection } from '../layouts/checkout-page-layout/components/checkout-page-section.js';
@@ -23,6 +23,7 @@ import styles from './order-confirmation-page.module.css.js';
23
23
 
24
24
  function OrderConfirmationPageContent({ cart, }) {
25
25
  const t = useFormattedMessage();
26
+ const paths = usePaths();
26
27
  const { addToast } = useToast();
27
28
  const saveCartForLater = useSaveCartForLater({
28
29
  onError: () => {
@@ -44,9 +45,9 @@ function OrderConfirmationPageContent({ cart, }) {
44
45
  if (!currencyCode)
45
46
  throw new Error(`Currency code not found for symbol ${cart.currencySymbol}`);
46
47
  return (jsx(Page, { breadcrumb: [
47
- { href: PATHS.HOME, label: t('Home') },
48
+ { href: paths.HOME, label: t('Home') },
48
49
  {
49
- href: `${PATHS.ORDER_CONFIRMATION}?cartId=${cart.id}`,
50
+ href: `${paths.ORDER_CONFIRMATION}?cartId=${cart.id}`,
50
51
  label: t('Order confirmation'),
51
52
  },
52
53
  ], "data-test-selector": "orderConfirmationPage", title: t('Order confirmation'), children: jsx(CheckoutPageLayout, { actions: {
@@ -5,12 +5,13 @@ import { LoadingPage } from '../../loading-page/loading-page.js';
5
5
  import { useIsAuthenticated } from '../../../shared/api/storefront/hooks/authentication/use-is-authenticated.js';
6
6
  import { useFetchCartById } from '../../../shared/api/storefront/hooks/cart/use-fetch-cart-by-id.js';
7
7
  import { useNavigate } from '../../../shared/routing/use-navigate.js';
8
+ import { usePaths } from '../../../shared/routing/use-paths.js';
8
9
  import { hasNo } from '../../../shared/utils/types.js';
9
10
  import { ErrorPage } from '../../error-page/error-page.js';
10
- import { PATHS } from '../../paths.js';
11
11
  import { OrderConfirmationPageContent } from './order-confirmation-page-content.js';
12
12
 
13
13
  function OrderConfirmationPage({ cartId }) {
14
+ const paths = usePaths();
14
15
  const isAuthenticated = useIsAuthenticated();
15
16
  const { isNavigating, navigate } = useNavigate();
16
17
  const { data: cart, error, isLoading: cartIsLoading, } = useFetchCartById({
@@ -22,10 +23,10 @@ function OrderConfirmationPage({ cartId }) {
22
23
  if (isAuthenticated === undefined)
23
24
  return;
24
25
  if (!isAuthenticated)
25
- return navigate(PATHS.CART);
26
+ return navigate(paths.CART);
26
27
  if (cart.status === 'Cart')
27
- navigate(PATHS.CART);
28
- }, [cart, navigate, isAuthenticated]);
28
+ navigate(paths.CART);
29
+ }, [cart, navigate, isAuthenticated, paths]);
29
30
  if (error)
30
31
  return jsx(ErrorPage, { error: error });
31
32
  if (cartIsLoading || isNavigating)
@@ -8,9 +8,9 @@ import { FormattedMessage } from '../../../intl/formatted-message.js';
8
8
  import { useFormattedMessage } from '../../../intl/use-formatted-message.js';
9
9
  import { OrderLineList } from '../../../lists/orderline-list/orderline-list.js';
10
10
  import { getCurrencyCodeBySymbol } from '../../../shared/model/currency.js';
11
+ import { usePaths } from '../../../shared/routing/use-paths.js';
11
12
  import { ensureNumber } from '../../../shared/utils/number.js';
12
13
  import { Page } from '../../components/page/page.js';
13
- import { PATHS } from '../../paths.js';
14
14
  import { CheckoutPageLayout } from '../layouts/checkout-page-layout/checkout-page-layout.js';
15
15
  import { CheckoutPageSection } from '../layouts/checkout-page-layout/components/checkout-page-section.js';
16
16
  import { CheckoutPageSectionContent } from '../layouts/checkout-page-layout/components/checkout-page-section-content.js';
@@ -18,13 +18,14 @@ import { Payment } from './components/payment.js';
18
18
 
19
19
  function PaymentPageContent({ atp, cart, formId, hasAtp, isProcessing, onPaymentComplete, setIsProcessing, }) {
20
20
  const t = useFormattedMessage();
21
+ const paths = usePaths();
21
22
  const currencyCode = getCurrencyCodeBySymbol(cart.currencySymbol);
22
23
  if (!currencyCode)
23
24
  throw new Error(`Currency code not found for symbol ${cart.currencySymbol}`);
24
25
  return (jsx(Page, { breadcrumb: [
25
- { href: PATHS.HOME, label: t('Home') },
26
+ { href: paths.HOME, label: t('Home') },
26
27
  {
27
- href: PATHS.REVIEW_AND_SUBMIT,
28
+ href: paths.REVIEW_AND_SUBMIT,
28
29
  label: t('Review and payment'),
29
30
  },
30
31
  ], "data-test-selector": "paymentPage", title: t('Review and payment'), children: jsxs(CheckoutPageLayout, { actions: {
@@ -5,15 +5,16 @@ import { useIsAuthenticated } from '../../../shared/api/storefront/hooks/authent
5
5
  import { useFetchCurrentCheckoutAtp } from '../../../shared/api/storefront/hooks/cart/use-fetch-current-cart-checkout-atp.js';
6
6
  import { useFetchCurrentCartWithAtp } from '../../../shared/api/storefront/hooks/cart/use-fetch-current-cart-with-atp.js';
7
7
  import { useNavigate } from '../../../shared/routing/use-navigate.js';
8
+ import { usePaths } from '../../../shared/routing/use-paths.js';
8
9
  import { hasNo } from '../../../shared/utils/types.js';
9
10
  import { ErrorPage } from '../../error-page/error-page.js';
10
11
  import { LoadingPage } from '../../loading-page/loading-page.js';
11
- import { PATHS } from '../../paths.js';
12
12
  import { useHasReturnedFromAdyen } from './hooks/use-has-returned-from-adyen.js';
13
13
  import { PaymentPageContent } from './payment-page-content.js';
14
14
 
15
15
  const PAYMENT_FORM_ID = 'paymentForm';
16
16
  function PaymentPage() {
17
+ const paths = usePaths();
17
18
  const hasReturnedFromAdyen = useHasReturnedFromAdyen();
18
19
  const isAuthenticated = useIsAuthenticated();
19
20
  const { data: cart, error, isLoading: isLoadingCart, } = useFetchCurrentCartWithAtp({
@@ -25,24 +26,24 @@ function PaymentPage() {
25
26
  const [isProcessing, setIsProcessing] = useState(false);
26
27
  const { isNavigating, navigate } = useNavigate();
27
28
  const onPaymentComplete = useCallback(({ cartId }) => {
28
- navigate(`${PATHS.ORDER_CONFIRMATION}?cartId=${cartId}`);
29
- }, [navigate]);
29
+ navigate(`${paths.ORDER_CONFIRMATION}?cartId=${cartId}`);
30
+ }, [navigate, paths]);
30
31
  useEffect(() => {
31
32
  if (isNavigating)
32
33
  return;
33
34
  if (isAuthenticated === undefined)
34
35
  return;
35
36
  if (!isAuthenticated)
36
- return navigate(PATHS.CHECKOUT_SHIPPING_VIA_SIGNIN);
37
+ return navigate(paths.CHECKOUT_SHIPPING_VIA_SIGNIN);
37
38
  if (hasNo(cart))
38
39
  return;
39
40
  if (hasNo(cart.cartLines) || cart.cartLines.length === 0)
40
- return navigate(PATHS.CART);
41
+ return navigate(paths.CART);
41
42
  if (hasNo(cart.billTo))
42
- return navigate(PATHS.CHECKOUT_SHIPPING_VIA_SIGNIN);
43
+ return navigate(paths.CHECKOUT_SHIPPING_VIA_SIGNIN);
43
44
  if (hasNo(cart.billTo.address1))
44
- return navigate(PATHS.CHECKOUT_SHIPPING);
45
- }, [cart, navigate, isAuthenticated, isNavigating]);
45
+ return navigate(paths.CHECKOUT_SHIPPING);
46
+ }, [cart, navigate, isAuthenticated, isNavigating, paths]);
46
47
  if (error)
47
48
  return jsx(ErrorPage, { error: error });
48
49
  if (!isAtpLoading && !atp)
@@ -4,11 +4,12 @@ import { Link } from '../../../../buttons/link/link.js';
4
4
  import { FormattedMessage } from '../../../../intl/formatted-message.js';
5
5
  import { useFormattedMessage } from '../../../../intl/use-formatted-message.js';
6
6
  import { Dialog } from '../../../../modals/dialog/dialog.js';
7
- import { PATHS } from '../../../paths.js';
7
+ import { usePaths } from '../../../../shared/routing/use-paths.js';
8
8
 
9
9
  function CurrencyChangeDialog({ isOpen, onOpenChange, onSubmit, }) {
10
10
  const t = useFormattedMessage();
11
- return (jsx(Dialog, { "data-test-selector": "currencyChangeDialog", isOpen: isOpen, onOpenChange: onOpenChange, onSubmit: onSubmit, shouldCloseOnInteractOutside: true, submitLabel: "Continue", title: t('Currency Change'), children: jsxs("p", { children: [jsx(FormattedMessage, { id: "You selected a country where we invoice in a different currency. This will result in your cart being converted to the new currency. If you would like to review your order, " }), jsx(Link, { hasUnderline: true, color: "secondary", href: PATHS.CART, onClick: onSubmit, children: jsx(FormattedMessage, { id: "please go back to your cart." }) }), ' ', jsx(FormattedMessage, { id: "If you want to proceed, click the continue button. If you want to change your country, close this message and select a different country." })] }) }));
11
+ const paths = usePaths();
12
+ return (jsx(Dialog, { "data-test-selector": "currencyChangeDialog", isOpen: isOpen, onOpenChange: onOpenChange, onSubmit: onSubmit, shouldCloseOnInteractOutside: true, submitLabel: "Continue", title: t('Currency Change'), children: jsxs("p", { children: [jsx(FormattedMessage, { id: "You selected a country where we invoice in a different currency. This will result in your cart being converted to the new currency. If you would like to review your order, " }), jsx(Link, { hasUnderline: true, color: "secondary", href: paths.CART, onClick: onSubmit, children: jsx(FormattedMessage, { id: "please go back to your cart." }) }), ' ', jsx(FormattedMessage, { id: "If you want to proceed, click the continue button. If you want to change your country, close this message and select a different country." })] }) }));
12
13
  }
13
14
 
14
15
  export { CurrencyChangeDialog };
@@ -7,7 +7,7 @@ import { Checkbox } from '../../../../forms/elements/checkbox/checkbox.js';
7
7
  import { TextField } from '../../../../forms/fields/text-field/text-field.js';
8
8
  import { FormattedMessage } from '../../../../intl/formatted-message.js';
9
9
  import { useFormattedMessage } from '../../../../intl/use-formatted-message.js';
10
- import { PATHS } from '../../../paths.js';
10
+ import { usePaths } from '../../../../shared/routing/use-paths.js';
11
11
  import { CheckoutPageSection } from '../../layouts/checkout-page-layout/components/checkout-page-section.js';
12
12
  import { CheckoutPageSectionContent } from '../../layouts/checkout-page-layout/components/checkout-page-section-content.js';
13
13
  import { CheckoutPageSectionLink } from '../../layouts/checkout-page-layout/components/checkout-page-section-link.js';
@@ -17,6 +17,7 @@ import styles from './readonly-address.module.css.js';
17
17
 
18
18
  function ReadOnlyAddresses({ billTo, isLoading, isPickup, notes, onSubmit, shipTo, }) {
19
19
  const t = useFormattedMessage();
20
+ const paths = usePaths();
20
21
  return (jsxs(Form, { id: EDIT_ADDRESS_FORM_ID, onSubmit: e => {
21
22
  e.preventDefault();
22
23
  const formData = new FormData(e.currentTarget);
@@ -25,7 +26,7 @@ function ReadOnlyAddresses({ billTo, isLoading, isPickup, notes, onSubmit, shipT
25
26
  ? undefined
26
27
  : formData.get('notes')?.toString() || '',
27
28
  });
28
- }, children: [jsxs(CheckoutPageSection, { title: jsx(FormattedMessage, { id: "Billing address" }), children: [jsx(CheckoutPageSectionLink, { children: jsxs(Link, { color: "secondary", href: PATHS.ACCOUNT_ADDRESSES, isDisabled: isLoading, children: [jsx(FormattedMessage, { id: "Edit billing address" }), " >"] }) }), jsxs(CheckoutPageSectionContent, { children: [billTo && (jsx(AddressInfoDisplay, { address: {
29
+ }, children: [jsxs(CheckoutPageSection, { title: jsx(FormattedMessage, { id: "Billing address" }), children: [jsx(CheckoutPageSectionLink, { children: jsxs(Link, { color: "secondary", href: paths.ACCOUNT_ADDRESSES, isDisabled: isLoading, children: [jsx(FormattedMessage, { id: "Edit billing address" }), " >"] }) }), jsxs(CheckoutPageSectionContent, { children: [billTo && (jsx(AddressInfoDisplay, { address: {
29
30
  address1: billTo.address1,
30
31
  address2: billTo.address2,
31
32
  address3: billTo.address3,
@@ -38,7 +39,7 @@ function ReadOnlyAddresses({ billTo, isLoading, isPickup, notes, onSubmit, shipT
38
39
  lastName: billTo.lastName,
39
40
  phone: billTo.phone,
40
41
  postalCode: billTo.postalCode,
41
- }, "data-test-selector": "billToAddress" })), jsx("div", { className: styles.notes, children: jsx(TextField, { defaultValue: notes, isDisabled: isLoading, isMultiline: true, label: t('Add order notes'), name: "notes", rows: 3, showLabel: true }) })] })] }), jsxs(CheckoutPageSection, { title: jsx(FormattedMessage, { id: isPickup ? 'Pickup address' : 'Shipping address' }), children: [!isPickup && (jsx(CheckoutPageSectionLink, { children: jsxs(Link, { color: "secondary", href: PATHS.ACCOUNT_ADDRESSES, isDisabled: isLoading, children: [jsx(FormattedMessage, { id: "Edit shipping address" }), " >"] }) })), jsx(CheckoutPageSectionContent, { children: isPickup ? (jsx(SonicAddress, {})) : (jsxs(Fragment, { children: [jsx(Checkbox, { className: styles['use-invoice-checkbox'], "data-test-selector": "checkboxUseBillingAddress", isDisabled: true, isSelected: true, children: jsx(FormattedMessage, { id: "Use billing address" }) }), shipTo && (jsx(AddressInfoDisplay, { address: {
42
+ }, "data-test-selector": "billToAddress" })), jsx("div", { className: styles.notes, children: jsx(TextField, { defaultValue: notes, isDisabled: isLoading, isMultiline: true, label: t('Add order notes'), name: "notes", rows: 3, showLabel: true }) })] })] }), jsxs(CheckoutPageSection, { title: jsx(FormattedMessage, { id: isPickup ? 'Pickup address' : 'Shipping address' }), children: [!isPickup && (jsx(CheckoutPageSectionLink, { children: jsxs(Link, { color: "secondary", href: paths.ACCOUNT_ADDRESSES, isDisabled: isLoading, children: [jsx(FormattedMessage, { id: "Edit shipping address" }), " >"] }) })), jsx(CheckoutPageSectionContent, { children: isPickup ? (jsx(SonicAddress, {})) : (jsxs(Fragment, { children: [jsx(Checkbox, { className: styles['use-invoice-checkbox'], "data-test-selector": "checkboxUseBillingAddress", isDisabled: true, isSelected: true, children: jsx(FormattedMessage, { id: "Use billing address" }) }), shipTo && (jsx(AddressInfoDisplay, { address: {
42
43
  address1: shipTo.address1,
43
44
  address2: shipTo.address2,
44
45
  address3: shipTo.address3,
@@ -7,8 +7,8 @@ import { Select } from '../../../forms/elements/select/select.js';
7
7
  import { FormattedMessage } from '../../../intl/formatted-message.js';
8
8
  import { useFormattedMessage } from '../../../intl/use-formatted-message.js';
9
9
  import { getCurrencyCodeBySymbol } from '../../../shared/model/currency.js';
10
+ import { usePaths } from '../../../shared/routing/use-paths.js';
10
11
  import { Page } from '../../components/page/page.js';
11
- import { PATHS } from '../../paths.js';
12
12
  import { CheckoutPageLayout } from '../layouts/checkout-page-layout/checkout-page-layout.js';
13
13
  import { CheckoutPageSection } from '../layouts/checkout-page-layout/components/checkout-page-section.js';
14
14
  import { CheckoutPageSectionContent } from '../layouts/checkout-page-layout/components/checkout-page-section-content.js';
@@ -17,6 +17,7 @@ import styles from './shipping-page.module.css.js';
17
17
 
18
18
  function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulfillmentMethods, isGuest, isLoadingFulfillmentMethods, isPatching, isPatchingSession, onChangeFulfillmentMethod, readOnlyAddress, }) {
19
19
  const t = useFormattedMessage();
20
+ const paths = usePaths();
20
21
  const fulfillmentMethodOptions = fulfillmentMethods?.reduce((acc, method) => ({
21
22
  ...acc,
22
23
  [method]: t(`fulfillmentmethod.${method}`),
@@ -26,9 +27,9 @@ function ShippingPageContent({ cart, editAddress, errorPatchBillingAddress, fulf
26
27
  if (!currencyCode)
27
28
  throw new Error(`Currency code not found for symbol ${cart.currencySymbol}`);
28
29
  return (jsx(Page, { breadcrumb: [
29
- { href: PATHS.HOME, label: t('Home') },
30
+ { href: paths.HOME, label: t('Home') },
30
31
  {
31
- href: PATHS.CHECKOUT_SHIPPING,
32
+ href: paths.CHECKOUT_SHIPPING,
32
33
  label: t('Shipping details'),
33
34
  },
34
35
  ], "data-test-selector": "shippingPage", title: t('Shipping details'), children: jsxs(CheckoutPageLayout, { actions: {
@@ -9,10 +9,10 @@ import { useFetchFulfillmentMethodsForCurrentCart } from '../../../shared/api/st
9
9
  import { useDataLayer } from '../../../shared/ga/use-data-layer.js';
10
10
  import { useDisclosure } from '../../../shared/hooks/use-disclosure.js';
11
11
  import { useNavigate } from '../../../shared/routing/use-navigate.js';
12
+ import { usePaths } from '../../../shared/routing/use-paths.js';
12
13
  import { hasNo } from '../../../shared/utils/types.js';
13
14
  import { ErrorPage } from '../../error-page/error-page.js';
14
15
  import { LoadingPage } from '../../loading-page/loading-page.js';
15
- import { PATHS } from '../../paths.js';
16
16
  import { CurrencyChangeDialog } from './components/currency-change-dialog.js';
17
17
  import { EditCheckoutBillToAddressForm } from './components/edit-checkout-bill-to-address-form.js';
18
18
  import { ReadOnlyAddresses } from './components/readonly-address.js';
@@ -20,6 +20,7 @@ import { usePatchShippingDetails } from './hooks/use-patch-shipping-details.js';
20
20
  import { ShippingPageContent } from './shipping-page-content.js';
21
21
 
22
22
  function ShippingPage() {
23
+ const paths = usePaths();
23
24
  const { createEcommerceEvent, dataLayer } = useDataLayer();
24
25
  const gaEventPushed = useRef(false);
25
26
  const { data: cart, error: errorFetchCart, isLoading: isLoadingCart, refetch: refetchCart, } = useFetchCurrentCart();
@@ -48,14 +49,14 @@ function ShippingPage() {
48
49
  if (isAuthenticated === undefined)
49
50
  return;
50
51
  if (!isAuthenticated)
51
- return navigate(PATHS.CHECKOUT_SHIPPING_VIA_SIGNIN);
52
+ return navigate(paths.CHECKOUT_SHIPPING_VIA_SIGNIN);
52
53
  if (hasNo(cart))
53
54
  return;
54
55
  if (hasNo(cart.cartLines) || cart.cartLines.length === 0)
55
- return navigate(PATHS.CART);
56
+ return navigate(paths.CART);
56
57
  if (hasNo(cart.billTo))
57
- return navigate(PATHS.CHECKOUT_SHIPPING_VIA_SIGNIN);
58
- }, [cart, navigate, isAuthenticated, isNavigating]);
58
+ return navigate(paths.CHECKOUT_SHIPPING_VIA_SIGNIN);
59
+ }, [cart, navigate, isAuthenticated, isNavigating, paths]);
59
60
  useEffect(() => {
60
61
  /* Guards for when the bill to address is saved and we should navigate to the next page */
61
62
  if (isPatching)
@@ -68,8 +69,8 @@ function ShippingPage() {
68
69
  return location?.reload();
69
70
  if (hasNo(cart?.billTo?.address1))
70
71
  return;
71
- return navigate(PATHS.REVIEW_AND_SUBMIT);
72
- }, [isSuccess, cart, navigate, isNavigating, isPatching, isError]);
72
+ return navigate(paths.REVIEW_AND_SUBMIT);
73
+ }, [isSuccess, cart, paths, navigate, isNavigating, isPatching, isError]);
73
74
  useEffect(() => {
74
75
  if (!cart || gaEventPushed.current)
75
76
  return;
@@ -157,7 +158,7 @@ function ShippingPage() {
157
158
  if (!cart.billTo)
158
159
  return;
159
160
  if (notes === undefined) {
160
- navigate(PATHS.REVIEW_AND_SUBMIT);
161
+ navigate(paths.REVIEW_AND_SUBMIT);
161
162
  }
162
163
  else {
163
164
  await patchShippingDetails({ cart, notes });
@@ -3,18 +3,19 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import { useEffect } from 'react';
4
4
  import { logger } from '../../logging/logger.js';
5
5
  import { isRequestError } from '../../shared/fetch/request.js';
6
+ import { usePaths } from '../../shared/routing/use-paths.js';
6
7
  import { environment } from '../../shared/utils/environment.js';
7
8
  import { Heading } from '../../typography/heading/heading.js';
8
9
  import { Page } from '../components/page/page.js';
9
- import { PATHS } from '../paths.js';
10
10
 
11
11
  function ErrorPage({ error }) {
12
+ const paths = usePaths();
12
13
  useEffect(() => {
13
14
  logger.error('ErrorPage error:', error);
14
15
  }, [error]);
15
16
  return (jsx(Page, { breadcrumb: [
16
- { href: PATHS.HOME, label: 'Home' },
17
- { href: PATHS.HOME, label: 'Error' },
17
+ { href: paths.HOME, label: 'Home' },
18
+ { href: paths.HOME, label: 'Error' },
18
19
  ], "data-test-selector": "errorPage", title: "Something went wrong", children: environment !== 'production' && (jsxs(Fragment, { children: [jsx(Heading, { size: "l", children: isRequestError(error) ? (jsxs(Fragment, { children: [error.status, " - ", error.statusText || 'Unknown error'] })) : (jsx(Fragment, { children: error.message })) }), isRequestError(error) && (jsxs(Fragment, { children: [jsx(Heading, { size: "xs", children: "Error details" }), jsx(Heading, { size: "xxs", children: "Body" }), jsx("pre", { children: JSON.stringify(error.body, null, 2) }), jsx(Heading, { size: "xxs", children: "Options" }), jsx("pre", { children: JSON.stringify(error.options, null, 2) })] }))] })) }));
19
20
  }
20
21
 
@@ -3,11 +3,12 @@ import { FormattedMessage } from '../../../../intl/formatted-message.js';
3
3
  import { useFetchCurrentAccount } from '../../../../shared/api/storefront/hooks/account/use-fetch-current-account.js';
4
4
  import { usePatchSession } from '../../../../shared/api/storefront/hooks/authentication/use-patch-session.js';
5
5
  import { useNavigate } from '../../../../shared/routing/use-navigate.js';
6
+ import { usePaths } from '../../../../shared/routing/use-paths.js';
6
7
  import { useToast } from '../../../../toast/use-toast.js';
7
- import { PATHS } from '../../../paths.js';
8
8
  import { ChangePasswordDialog } from './change-password-dialog.js';
9
9
 
10
10
  function ConnectedChangePasswordDialog({ isOpen, onClose, }) {
11
+ const paths = usePaths();
11
12
  const { error: errorPatchSession, isLoading: isUpdating, mutate: patchSession, } = usePatchSession();
12
13
  const { addToast } = useToast();
13
14
  const { navigate } = useNavigate();
@@ -30,7 +31,7 @@ function ConnectedChangePasswordDialog({ isOpen, onClose, }) {
30
31
  messageType: 'success',
31
32
  });
32
33
  onClose();
33
- navigate(`${PATHS.SIGN_IN}${location?.pathname ? `?returnUrl=${encodeURIComponent(location.pathname + location.search)}` : ''}`);
34
+ navigate(`${paths.SIGN_IN}${location?.pathname ? `?returnUrl=${encodeURIComponent(location.pathname + location.search)}` : ''}`);
34
35
  }, username: account?.email }));
35
36
  }
36
37
 
@@ -5,12 +5,13 @@ import { logger } from '../../../logging/logger.js';
5
5
  import { useSignOut } from '../../../shared/api/storefront/hooks/authentication/use-sign-out.js';
6
6
  import { useLocation } from '../../../shared/routing/use-location.js';
7
7
  import { useNavigate } from '../../../shared/routing/use-navigate.js';
8
- import { PATHS } from '../../paths.js';
8
+ import { usePaths } from '../../../shared/routing/use-paths.js';
9
9
  import { MySonicDesktopNavigation } from './my-sonic-desktop-navigation.js';
10
10
  import { MySonicMobileNavigation } from './my-sonic-mobile-navigation.js';
11
11
  import styles from './connected-my-sonic-navigation.module.css.js';
12
12
 
13
13
  function ConnectedMySonicNavigation() {
14
+ const paths = usePaths();
14
15
  const { pathname } = useLocation();
15
16
  const { navigate } = useNavigate();
16
17
  const { mutate } = useSignOut({
@@ -18,7 +19,7 @@ function ConnectedMySonicNavigation() {
18
19
  onSuccess: () => {
19
20
  // TODO: Remove when Spire is deprecated
20
21
  Cookies.remove('NavigationMode');
21
- navigate(PATHS.HOME, { reload: true });
22
+ navigate(paths.HOME, { reload: true });
22
23
  },
23
24
  });
24
25
  return (jsxs("div", { style: { display: 'grid' }, children: [jsx(MySonicDesktopNavigation, { className: styles['large'], currentPath: pathname, onLogout: mutate }), jsx(MySonicMobileNavigation, { className: styles['small'], currentPath: pathname, onLogout: mutate })] }));
@@ -2,10 +2,11 @@ import { jsx } from 'react/jsx-runtime';
2
2
  import { FormattedMessage } from '../../../intl/formatted-message.js';
3
3
  import { MenuList } from '../../../lists/menu-list/menu-list.js';
4
4
  import { MenuListItem } from '../../../lists/menu-list/menu-list-item.js';
5
- import { mySonicNavigationItems } from './my-sonic-navigation-items.js';
5
+ import { useMySonicNavigationItems } from './my-sonic-navigation-items.js';
6
6
  import styles from './my-sonic-desktop-navigation.module.css.js';
7
7
 
8
8
  function MySonicDesktopNavigation({ className, currentPath, onLogout, }) {
9
+ const mySonicNavigationItems = useMySonicNavigationItems();
9
10
  return (jsx(MenuList, { collapsible: true, className: className, children: mySonicNavigationItems.map(item => (jsx(MenuListItem, { badge: jsx(item.Icon, {}), ...(item.type === 'action'
10
11
  ? item.action === 'logout'
11
12
  ? { onClick: onLogout }
@@ -3,9 +3,10 @@ import { jsx } from 'react/jsx-runtime';
3
3
  import { Select } from '../../../forms/elements/select/select.js';
4
4
  import { useFormattedMessage } from '../../../intl/use-formatted-message.js';
5
5
  import { useNavigate } from '../../../shared/routing/use-navigate.js';
6
- import { mySonicNavigationItems } from './my-sonic-navigation-items.js';
6
+ import { useMySonicNavigationItems } from './my-sonic-navigation-items.js';
7
7
 
8
8
  function MySonicMobileNavigation({ className, currentPath, onLogout, }) {
9
+ const mySonicNavigationItems = useMySonicNavigationItems();
9
10
  const { navigate } = useNavigate();
10
11
  const t = useFormattedMessage();
11
12
  return (jsx(Select, { className: className, label: t('Navigate to...'), onChange: option => {
@@ -14,5 +14,5 @@ interface MySonicNavigationAction extends MySonicNavigationItemBase {
14
14
  type: 'action';
15
15
  }
16
16
  type MySonicNavigationItem = MySonicNavigationLink | MySonicNavigationAction;
17
- export declare const mySonicNavigationItems: MySonicNavigationItem[];
17
+ export declare function useMySonicNavigationItems(): MySonicNavigationItem[];
18
18
  export {};
@@ -2,28 +2,36 @@ import { SolidCartIcon } from '../../../icons/solid/solid-cart-icon.js';
2
2
  import { SolidFavoriteIcon } from '../../../icons/solid/solid-favorite-icon.js';
3
3
  import { SolidLoginIcon } from '../../../icons/solid/solid-login-icon.js';
4
4
  import { SolidLogOutIcon } from '../../../icons/solid/solid-logout-icon.js';
5
- import { PATHS } from '../../paths.js';
5
+ import { usePaths } from '../../../shared/routing/use-paths.js';
6
6
 
7
- const mySonicNavigationItems = [
8
- {
9
- Icon: SolidLoginIcon,
10
- label: 'Account',
11
- path: PATHS.ACCOUNT_SETTINGS.toLowerCase(),
12
- type: 'link',
13
- },
14
- {
15
- Icon: SolidFavoriteIcon,
16
- label: 'Favorites',
17
- path: PATHS.ACCOUNT_MY_LISTS.toLowerCase(),
18
- type: 'link',
19
- },
20
- {
21
- Icon: SolidCartIcon,
22
- label: 'Orders',
23
- path: PATHS.ACCOUNT_ORDERS.toLowerCase(),
24
- type: 'link',
25
- },
26
- { Icon: SolidLogOutIcon, action: 'logout', label: 'Log out', type: 'action' },
27
- ];
7
+ function useMySonicNavigationItems() {
8
+ const paths = usePaths();
9
+ return [
10
+ {
11
+ Icon: SolidLoginIcon,
12
+ label: 'Account',
13
+ path: paths.ACCOUNT_SETTINGS.toLowerCase(),
14
+ type: 'link',
15
+ },
16
+ {
17
+ Icon: SolidFavoriteIcon,
18
+ label: 'Favorites',
19
+ path: paths.ACCOUNT_MY_LISTS.toLowerCase(),
20
+ type: 'link',
21
+ },
22
+ {
23
+ Icon: SolidCartIcon,
24
+ label: 'Orders',
25
+ path: paths.ACCOUNT_ORDERS.toLowerCase(),
26
+ type: 'link',
27
+ },
28
+ {
29
+ Icon: SolidLogOutIcon,
30
+ action: 'logout',
31
+ label: 'Log out',
32
+ type: 'action',
33
+ },
34
+ ];
35
+ }
28
36
 
29
- export { mySonicNavigationItems };
37
+ export { useMySonicNavigationItems };
@@ -1,13 +1,14 @@
1
1
  import { ElementType, ReactNode } from 'react';
2
- import { NavigateFunction, RouteLinkElementProps } from './types';
2
+ import { NavigateFunction, Paths, RouteLinkElementProps } from './types';
3
3
  export interface RouteProviderProps {
4
4
  Link?: ElementType<RouteLinkElementProps>;
5
5
  children: ReactNode;
6
6
  navigate: NavigateFunction;
7
+ paths: Paths;
7
8
  url: {
8
9
  basePathname?: string;
9
10
  pathname: string;
10
11
  search: string;
11
12
  };
12
13
  }
13
- export declare function RouteProvider({ children, Link, navigate, url, }: RouteProviderProps): import("react/jsx-runtime").JSX.Element;
14
+ export declare function RouteProvider({ children, Link, navigate, paths, url, }: RouteProviderProps): import("react/jsx-runtime").JSX.Element;
@@ -3,10 +3,11 @@ import { jsx, Fragment } from 'react/jsx-runtime';
3
3
  import { useGlobalState } from '../providers/global-state-provider.js';
4
4
  import { withRouting } from './with-routing.js';
5
5
 
6
- function RouteProvider({ children, Link = FallbackRouteLink, navigate, url, }) {
6
+ function RouteProvider({ children, Link = FallbackRouteLink, navigate, paths, url, }) {
7
7
  useGlobalState('routing', {
8
8
  Link,
9
9
  navigate,
10
+ paths,
10
11
  url,
11
12
  });
12
13
  return jsx(Fragment, { children: children });
@@ -1,7 +1,25 @@
1
1
  import { ElementType } from 'react';
2
+ export interface Paths {
3
+ ACCOUNT: string;
4
+ ACCOUNT_ADDRESSES: string;
5
+ ACCOUNT_CREATE: string;
6
+ ACCOUNT_INVOICES: string;
7
+ ACCOUNT_MY_LISTS: string;
8
+ ACCOUNT_ORDERS: string;
9
+ ACCOUNT_SETTINGS: string;
10
+ CART: string;
11
+ CHECKOUT_SHIPPING: string;
12
+ CHECKOUT_SHIPPING_VIA_SIGNIN: string;
13
+ FAVORITES: string;
14
+ HOME: string;
15
+ ORDER_CONFIRMATION: string;
16
+ REVIEW_AND_SUBMIT: string;
17
+ SIGN_IN: string;
18
+ }
2
19
  export interface RouteContext {
3
20
  Link?: ElementType<RouteLinkElementProps>;
4
21
  navigate: NavigateFunction;
22
+ paths: Paths;
5
23
  url: {
6
24
  basePathname?: string;
7
25
  pathname: string;
@@ -0,0 +1,2 @@
1
+ import { Paths } from './types';
2
+ export declare function usePaths(): Paths;
@@ -0,0 +1,10 @@
1
+ import { useGlobalState } from '../providers/global-state-provider.js';
2
+
3
+ function usePaths() {
4
+ const [routeState] = useGlobalState('routing');
5
+ if (!routeState)
6
+ throw new Error('usePaths must be used within a RouteProvider context');
7
+ return routeState.paths;
8
+ }
9
+
10
+ export { usePaths };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonic-equipment/ui",
3
- "version": "192.0.0",
3
+ "version": "194.0.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -145,8 +145,8 @@
145
145
  "instantsearch.js": "4.78.3",
146
146
  "js-cookie": "3.0.5",
147
147
  "query-string": "9.2.0",
148
- "react-aria": "3.40.0",
149
- "react-aria-components": "1.9.0",
148
+ "react-aria": "3.42.0",
149
+ "react-aria-components": "1.11.0",
150
150
  "react-instantsearch": "7.15.8",
151
151
  "react-toastify": "10.0.6",
152
152
  "react-transition-group": "4.4.5",
@@ -1,17 +0,0 @@
1
- export declare const PATHS: {
2
- readonly ACCOUNT: "/MyAccount";
3
- readonly ACCOUNT_ADDRESSES: "/MyAccount/Addresses";
4
- readonly ACCOUNT_CREATE: "/MyAccount/CreateAccount";
5
- readonly ACCOUNT_INVOICES: "/MyAccount/Invoices";
6
- readonly ACCOUNT_MY_LISTS: "/MyAccount/MyLists";
7
- readonly ACCOUNT_ORDERS: "/MyAccount/Orders";
8
- readonly ACCOUNT_SETTINGS: "/MyAccount/AccountSettings";
9
- readonly CART: "/Cart";
10
- readonly CHECKOUT_SHIPPING: "/CheckoutShipping";
11
- readonly CHECKOUT_SHIPPING_VIA_SIGNIN: "/SignIn?returnUrl=/CheckoutShipping";
12
- readonly FAVORITES: "/MyAccount/MyLists";
13
- readonly HOME: "/";
14
- readonly ORDER_CONFIRMATION: "/OrderConfirmation";
15
- readonly REVIEW_AND_SUBMIT: "/CheckoutReviewAndSubmit";
16
- readonly SIGN_IN: "/SignIn";
17
- };
@@ -1,19 +0,0 @@
1
- const PATHS = {
2
- ACCOUNT: '/MyAccount',
3
- ACCOUNT_ADDRESSES: '/MyAccount/Addresses',
4
- ACCOUNT_CREATE: '/MyAccount/CreateAccount',
5
- ACCOUNT_INVOICES: '/MyAccount/Invoices',
6
- ACCOUNT_MY_LISTS: '/MyAccount/MyLists',
7
- ACCOUNT_ORDERS: '/MyAccount/Orders',
8
- ACCOUNT_SETTINGS: '/MyAccount/AccountSettings',
9
- CART: '/Cart',
10
- CHECKOUT_SHIPPING: '/CheckoutShipping',
11
- CHECKOUT_SHIPPING_VIA_SIGNIN: '/SignIn?returnUrl=/CheckoutShipping',
12
- FAVORITES: '/MyAccount/MyLists',
13
- HOME: '/',
14
- ORDER_CONFIRMATION: '/OrderConfirmation',
15
- REVIEW_AND_SUBMIT: '/CheckoutReviewAndSubmit',
16
- SIGN_IN: '/SignIn',
17
- };
18
-
19
- export { PATHS };