@evenicanpm/storefront-core 1.3.0 → 1.6.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 (188) hide show
  1. package/__mocks__/get-product-by-id.ts +0 -1
  2. package/__mocks__/query-client.ts +1 -1
  3. package/package.json +3 -3
  4. package/src/api-manager/datasources/d365/d365-address.datasource.ts +2 -2
  5. package/src/api-manager/datasources/d365/d365-cart.datasource.ts +4 -5
  6. package/src/api-manager/datasources/d365/d365-categories.datasource.ts +1 -1
  7. package/src/api-manager/datasources/d365/d365-product.datasource.ts +21 -7
  8. package/src/api-manager/datasources/d365/d365-session.datasource.ts +5 -7
  9. package/src/api-manager/datasources/d365/d365-user.datasource.ts +12 -23
  10. package/src/api-manager/datasources/d365/d365.datasource.ts +0 -2
  11. package/src/api-manager/datasources/d365/index.ts +2 -4
  12. package/src/api-manager/datasources/d365/utils/decode-jwt.ts +1 -2
  13. package/src/api-manager/datasources/d365/utils/parse-object.ts +1 -1
  14. package/src/api-manager/datasources/e4/address/e4-address.remaps.ts +2 -2
  15. package/src/api-manager/datasources/e4/address/e4-address.translator.ts +1 -1
  16. package/src/api-manager/datasources/e4/cart/e4-cart.datasource.ts +28 -27
  17. package/src/api-manager/datasources/e4/cart/e4-cart.remaps.ts +1 -1
  18. package/src/api-manager/datasources/e4/cart/e4-cart.translator.ts +1 -1
  19. package/src/api-manager/datasources/e4/categories/e4-categories.translator.ts +20 -20
  20. package/src/api-manager/datasources/e4/graphqlRequestSdk.ts +471 -7
  21. package/src/api-manager/datasources/e4/order/e4-order.remaps.ts +2 -2
  22. package/src/api-manager/datasources/e4/organization/e4-organization.datasource.ts +2 -8
  23. package/src/api-manager/datasources/e4/product/e4-product.remaps.ts +3 -3
  24. package/src/api-manager/datasources/e4/product/e4-product.translator.ts +13 -29
  25. package/src/api-manager/datasources/e4/session/e4-session.datasource.ts +1 -3
  26. package/src/api-manager/datasources/e4/user/e4-user.remaps.ts +2 -4
  27. package/src/api-manager/datasources/e4/utils/unwrap-e4-variants.ts +4 -4
  28. package/src/api-manager/index.ts +1 -1
  29. package/src/api-manager/lib/category-helpers.ts +3 -2
  30. package/src/api-manager/lib/get-graphql-client.ts +1 -2
  31. package/src/api-manager/services/cart/mutations/add-discount-code.ts +2 -2
  32. package/src/api-manager/services/cart/mutations/add-to-cart.ts +2 -2
  33. package/src/api-manager/services/product/server/product.server.ts +1 -1
  34. package/src/api-manager/types/Datasource.ts +4 -9
  35. package/src/auth/auth-options.test.ts +2 -58
  36. package/src/auth/auth-options.ts +1 -2
  37. package/src/auth/next-auth-cookie-manager.ts +0 -2
  38. package/src/auth/refresh-token.ts +3 -8
  39. package/src/auth/signout.ts +1 -1
  40. package/src/cms/blocks/block-manager.tsx +3 -3
  41. package/src/cms/blocks/components/category-card.tsx +1 -1
  42. package/src/cms/blocks/components/category-carousel/index.tsx +3 -1
  43. package/src/cms/blocks/components/footer/index.tsx +2 -2
  44. package/src/cms/blocks/components/footer/sections/footer-links.tsx +2 -2
  45. package/src/cms/blocks/components/footer/sections/footer-logo.tsx +1 -1
  46. package/src/cms/blocks/components/footer/sections/footer-social-links.tsx +10 -2
  47. package/src/cms/blocks/components/hero-carousel/index.tsx +29 -25
  48. package/src/cms/blocks/components/media-card.tsx +1 -1
  49. package/src/cms/blocks/components/product-carousel/index.tsx +1 -1
  50. package/src/cms/blocks/components/product-section-fullwidth/index.tsx +2 -2
  51. package/src/cms/blocks/components/seo/index.tsx +5 -1
  52. package/src/cms/blocks/components/services/index.tsx +1 -1
  53. package/src/cms/blocks/components/services/service-card.tsx +1 -1
  54. package/src/cms/blocks/components/shared/featured-product-card.tsx +4 -1
  55. package/src/cms/blocks/components/shared/product-category-item.tsx +1 -1
  56. package/src/cms/blocks/components/shared/product-grid.tsx +4 -1
  57. package/src/cms/blocks/components/shared/top-categories-card.tsx +5 -1
  58. package/src/cms/blocks/components/shared/top-rating-product-card.tsx +1 -1
  59. package/src/components-v2/BazaarImage.tsx +1 -1
  60. package/src/components-v2/BazaarMenu.tsx +2 -2
  61. package/src/components-v2/BazaarTextField.tsx +3 -3
  62. package/src/components-v2/BorderShadowCard.stories.tsx +1 -1
  63. package/src/components-v2/DropZone.tsx +1 -2
  64. package/src/components-v2/Typography.tsx +12 -12
  65. package/src/components-v2/accordion/accordion-header.tsx +1 -1
  66. package/src/components-v2/categories/category-list/styles.ts +0 -7
  67. package/src/components-v2/categories/category-list-item/category-menu-item.tsx +1 -1
  68. package/src/components-v2/categories/category-menu.tsx +16 -13
  69. package/src/components-v2/categories/mega-menu/mega-menu-1.tsx +1 -1
  70. package/src/components-v2/categories/mega-menu/mega-menu-2.tsx +2 -2
  71. package/src/components-v2/header/components/user.tsx +5 -5
  72. package/src/components-v2/mini-cart/__tests__/cart-item.test.tsx +13 -13
  73. package/src/components-v2/mini-cart/components/bottom-actions.tsx +1 -1
  74. package/src/components-v2/mini-cart/components/cart-item.tsx +3 -3
  75. package/src/components-v2/mini-cart/components/top-header.tsx +2 -2
  76. package/src/components-v2/mobile-navigation/mobile-navigation-bar.tsx +1 -1
  77. package/src/components-v2/nav-link/nav-link-2.tsx +1 -1
  78. package/src/components-v2/nav-link/nav-link-3.tsx +1 -1
  79. package/src/components-v2/nav-link/nav-link.tsx +1 -1
  80. package/src/components-v2/navbar/categories.tsx +3 -1
  81. package/src/components-v2/navbar/category-based-menu/category-based-menu.tsx +2 -2
  82. package/src/components-v2/navbar/mobile-menu/mobile-menu.tsx +11 -3
  83. package/src/components-v2/navbar/nav-list/nav-item-child.tsx +1 -1
  84. package/src/components-v2/navbar/nav-list/nav-list.tsx +118 -80
  85. package/src/components-v2/navbar/navbar.tsx +1 -1
  86. package/src/components-v2/no-records.tsx +1 -1
  87. package/src/components-v2/product-cards/favorite-button.tsx +1 -1
  88. package/src/components-v2/product-cards/product-card/product-card.tsx +5 -7
  89. package/src/components-v2/product-cards/product-card-plp/product-card.tsx +7 -6
  90. package/src/components-v2/product-cards/product-card-plp-list/components/tags.tsx +1 -1
  91. package/src/components-v2/product-cards/product-card-plp-list/product-card.tsx +7 -4
  92. package/src/components-v2/product-cards/product-card-search/product-card.tsx +4 -2
  93. package/src/components-v2/product-cards/product-price.tsx +1 -1
  94. package/src/components-v2/product-cards/product-rating.tsx +1 -1
  95. package/src/components-v2/product-cards/product-title.tsx +1 -1
  96. package/src/components-v2/product-cards/quantity-buttons.tsx +1 -1
  97. package/src/components-v2/product-dialog/compound/product-dialog.tsx +2 -2
  98. package/src/components-v2/product-dialog/index.tsx +1 -1
  99. package/src/components-v2/product-dimensions/compound/dimensions-group-list.tsx +6 -1
  100. package/src/components-v2/product-dimensions/index.tsx +3 -3
  101. package/src/components-v2/product-quantity-buttons/compound/quantity-buttons-root.tsx +1 -1
  102. package/src/components-v2/product-quantity-variants/index.tsx +1 -2
  103. package/src/components-v2/products-view/ProductsList.stories.tsx +0 -2
  104. package/src/components-v2/products-view/compound/products-grid-view.tsx +2 -2
  105. package/src/components-v2/products-view/compound/products-list-view.tsx +3 -3
  106. package/src/components-v2/products-view/index.tsx +2 -2
  107. package/src/components-v2/progress/progress.tsx +1 -1
  108. package/src/components-v2/scrollbar/scrollbar.tsx +1 -1
  109. package/src/components-v2/search-bar/compound/results-suspense.tsx +1 -2
  110. package/src/components-v2/search-bar/compound/results.tsx +6 -3
  111. package/src/components-v2/search-bar/compound/search-bar-root.tsx +4 -2
  112. package/src/components-v2/search-bar/compound/textfield-adornment-category.tsx +25 -27
  113. package/src/components-v2/search-bar/compound/textfield.tsx +0 -1
  114. package/src/components-v2/search-bar/hooks/use-search.ts +1 -1
  115. package/src/components-v2/section/Section.stories.tsx +1 -1
  116. package/src/components-v2/side-nav/side-nav.tsx +1 -1
  117. package/src/components-v2/wishlist-dialogs/add-to-wishlist/compound/add-to-wishlist-dialog.tsx +1 -1
  118. package/src/components-v2/wishlist-dialogs/add-to-wishlist/compound/add-to-wishlist-list.tsx +2 -2
  119. package/src/components-v2/wishlist-dialogs/add-to-wishlist/hooks/use-add-to-wishlist.ts +2 -0
  120. package/src/components-v2/wishlist-dialogs/add-to-wishlist/index.tsx +11 -13
  121. package/src/components-v2/wishlist-dialogs/create-wishlist/compound/create-wishlist-dialog.tsx +2 -1
  122. package/src/hooks/use-variants.ts +25 -27
  123. package/src/lib/build-detail-url.ts +1 -1
  124. package/src/lib/category-helpers.ts +3 -3
  125. package/src/lib/get-palette-color.ts +35 -15
  126. package/src/lib/hexToLuma.ts +2 -2
  127. package/src/lib/store-hours-helper.ts +5 -5
  128. package/src/pages-v2/account/addresses/address-form.tsx +10 -8
  129. package/src/pages-v2/account/addresses/address-item.tsx +1 -1
  130. package/src/pages-v2/account/orders/order-progress.tsx +1 -1
  131. package/src/pages-v2/account/orders/ordered-products.tsx +1 -1
  132. package/src/pages-v2/account/profile/user-info.tsx +1 -2
  133. package/src/pages-v2/account/wishlist/create-new-list.tsx +1 -0
  134. package/src/pages-v2/account/wishlist/wishlist-item.tsx +2 -1
  135. package/src/pages-v2/blog/blog-card.tsx +1 -1
  136. package/src/pages-v2/cart/__tests__/cart-item.test.tsx +0 -1
  137. package/src/pages-v2/cart/__tests__/checkout-form.test.tsx +0 -8
  138. package/src/pages-v2/cart/cart-item.tsx +86 -77
  139. package/src/pages-v2/cart/checkout-form.tsx +4 -4
  140. package/src/pages-v2/cart/coupon-entry.tsx +3 -3
  141. package/src/pages-v2/cart/estimate-shipping.tsx +6 -6
  142. package/src/pages-v2/checkout/checkout-alt-form/checkout-form.tsx +2 -2
  143. package/src/pages-v2/checkout/checkout-alt-form/checkout-step.tsx +2 -2
  144. package/src/pages-v2/checkout/checkout-alt-form/step-heading.tsx +1 -1
  145. package/src/pages-v2/checkout/checkout-alt-form/steps/address/delivery-address.tsx +12 -10
  146. package/src/pages-v2/checkout/checkout-alt-form/steps/address/new-address-form.tsx +5 -6
  147. package/src/pages-v2/checkout/checkout-alt-form/steps/customer-info/customer-information.tsx +8 -9
  148. package/src/pages-v2/checkout/checkout-alt-form/steps/payment/payment-details.tsx +17 -20
  149. package/src/pages-v2/checkout/checkout-alt-form/steps/shipping/delivery-date.tsx +1 -1
  150. package/src/pages-v2/checkout/checkout-alt-form/steps/shipping/delivery-options.tsx +14 -15
  151. package/src/pages-v2/confirmation/confirmation-summary.tsx +8 -7
  152. package/src/pages-v2/confirmation/ordered-products.tsx +3 -3
  153. package/src/pages-v2/product-details/bopis/pickup-option-select.tsx +1 -1
  154. package/src/pages-v2/product-details/bopis/store-card/shop-card.tsx +1 -1
  155. package/src/pages-v2/product-details/checkbox-label.tsx +1 -1
  156. package/src/pages-v2/product-details/frequently-bought.tsx +1 -1
  157. package/src/pages-v2/product-details/frequently-product-card.tsx +1 -1
  158. package/src/pages-v2/product-details/product-comment.tsx +1 -1
  159. package/src/pages-v2/product-details/product-description.tsx +2 -2
  160. package/src/pages-v2/product-details/product-filter-card.tsx +4 -1
  161. package/src/pages-v2/product-details/product-intro/compound/product-intro-images.tsx +36 -31
  162. package/src/pages-v2/product-details/product-intro/compound/product-intro.tsx +1 -1
  163. package/src/pages-v2/product-details/product-intro/compound/thumbnail-with-skeleton.tsx +1 -1
  164. package/src/pages-v2/product-details/product-intro/utils.ts +2 -4
  165. package/src/pages-v2/product-details/product-review.tsx +1 -1
  166. package/src/pages-v2/product-details/product-tabs.tsx +5 -2
  167. package/src/pages-v2/product-details/related-products.tsx +7 -4
  168. package/src/pages-v2/product-list/breadcrumbs.tsx +1 -1
  169. package/src/pages-v2/product-list/checkbox-label.tsx +1 -1
  170. package/src/pages-v2/product-list/facet-group.tsx +1 -1
  171. package/src/pages-v2/product-list/list-filter.tsx +2 -2
  172. package/src/pages-v2/product-list/product-list-context.tsx +5 -1
  173. package/src/pages-v2/product-list/product-list-view.tsx +4 -1
  174. package/src/pages-v2/product-list/product-rating.tsx +4 -1
  175. package/src/pages-v2/product-list/quick-view-dialog-content.tsx +2 -4
  176. package/src/pages-v2/product-list/quick-view-dialog.tsx +5 -1
  177. package/src/pages-v2/product-list/range-filter.tsx +0 -1
  178. package/src/pages-v2/product-list/scrollbar.tsx +1 -1
  179. package/src/pages-v2/product-list/side-nav.tsx +1 -1
  180. package/src/pages-v2/product-list/swatch.tsx +12 -7
  181. package/src/pages-v2/product-list/utils/getCategoryFilterFromSlug.ts +33 -68
  182. package/src/pages-v2/product-list/utils/product-list-helper.ts +1 -1
  183. package/src/pages-v2/product-list/utils/search-for-category.ts +2 -2
  184. package/src/pages-v2/quickorder/order-upload.tsx +90 -76
  185. package/src/pages-v2/quickorder/provider.tsx +6 -4
  186. package/src/pages-v2/quickorder/quick-order-row.tsx +1 -1
  187. package/src/pages-v2/quickorder/quick-order.tsx +28 -21
  188. package/src/providers/notifications/notification-context.tsx +0 -1
@@ -18,7 +18,7 @@ import { cloneElement } from "react";
18
18
  /**
19
19
  * Root component of the ProductsListView.
20
20
  */
21
- export default function ProductsListView(props: ProductsViewProps) {
21
+ export default function ProductsListView(props: Readonly<ProductsViewProps>) {
22
22
  const { pagination, products, productPrices, children } = props;
23
23
  console.log(props);
24
24
  return (
@@ -42,14 +42,14 @@ ProductsListView.List = ({ children }: { children: React.ReactElement }) => {
42
42
  const { products, productPrices } = useProductsView();
43
43
  return (
44
44
  <>
45
- {products.map((item: Product, i) => {
45
+ {products.map((item: Product) => {
46
46
  const matchingPrice = productPrices?.find(
47
47
  (price) => price.ProductId === item.RecordId,
48
48
  );
49
49
  // Legacy API, consider alternatives.
50
50
  // Using this to pass props to child.
51
51
  return cloneElement(children, {
52
- key: i,
52
+ key: item.RecordId ?? item.ItemId,
53
53
  product: item,
54
54
  price: matchingPrice,
55
55
  });
@@ -20,7 +20,7 @@ export interface Props {
20
20
  * TODO: Add Pagination to storybook
21
21
  *
22
22
  */
23
- export function ProductsGrid(props: Props) {
23
+ export function ProductsGrid(props: Readonly<Props>) {
24
24
  return (
25
25
  <ProductsGridView {...props}>
26
26
  <ProductsGridView.Grid>
@@ -35,7 +35,7 @@ export function ProductsGrid(props: Props) {
35
35
  * Pre-composed implementation of ProductList
36
36
  *
37
37
  */
38
- export function ProductsList(props: Props) {
38
+ export function ProductsList(props: Readonly<Props>) {
39
39
  return (
40
40
  <ProductsListView {...props}>
41
41
  <ProductsListView.List>
@@ -38,7 +38,7 @@ export default function ProgressBar() {
38
38
  const mutationObserver = new MutationObserver(handleMutation);
39
39
  mutationObserver.observe(document, { childList: true, subtree: true });
40
40
 
41
- window.history.pushState = new Proxy(window.history.pushState, {
41
+ globalThis.history.pushState = new Proxy(globalThis.history.pushState, {
42
42
  apply: (target, thisArg, argArray: PushStateInput) => {
43
43
  NProgress.done();
44
44
  return target.apply(thisArg, argArray);
@@ -18,7 +18,7 @@ export default function Scolbar({
18
18
  autoHide = true,
19
19
  sx,
20
20
  ...props
21
- }: ScrollbarProps) {
21
+ }: Readonly<ScrollbarProps>) {
22
22
  return (
23
23
  <StyledScrollBar sx={sx} autoHide={autoHide} {...props}>
24
24
  {children}
@@ -9,7 +9,6 @@ import ResultItemCardLg from "@evenicanpm/storefront-core/src/components-v2/sear
9
9
  import ResultItemCardSm from "@evenicanpm/storefront-core/src/components-v2/search-bar/compound/results-item-sm";
10
10
  import { SearchResultCard } from "@evenicanpm/storefront-core/src/components-v2/search-bar/styles/index";
11
11
  import { CircularProgress } from "@mui/material";
12
- import _ from "lodash";
13
12
  import type React from "react";
14
13
  import { Suspense } from "react";
15
14
 
@@ -24,7 +23,7 @@ import { Suspense } from "react";
24
23
  export default function SearchResultSuspense({
25
24
  children,
26
25
  }: {
27
- children: React.ReactNode;
26
+ readonly children: React.ReactNode;
28
27
  }) {
29
28
  const { state } = useSearchContext();
30
29
  return (
@@ -19,7 +19,7 @@ import type React from "react";
19
19
  export default function SearchResultsContainer({
20
20
  children,
21
21
  }: {
22
- children: React.ReactNode;
22
+ readonly children: React.ReactNode;
23
23
  }) {
24
24
  const t = useTranslations();
25
25
  const { state } = useSearchContext();
@@ -36,8 +36,11 @@ export default function SearchResultsContainer({
36
36
  return (
37
37
  <SearchResultCard>
38
38
  <Grid container>
39
- {results.map((item, i) => (
40
- <SearchResultItemContext.Provider value={item} key={i}>
39
+ {results.map((item) => (
40
+ <SearchResultItemContext.Provider
41
+ value={item}
42
+ key={item.RecordId ?? item.ItemId}
43
+ >
41
44
  {children}
42
45
  </SearchResultItemContext.Provider>
43
46
  ))}
@@ -12,7 +12,6 @@ import { useClickOutside } from "@evenicanpm/storefront-core/src/components-v2/s
12
12
  // local hooks
13
13
  import useSearch from "@evenicanpm/storefront-core/src/components-v2/search-bar/hooks/use-search";
14
14
  import Box from "@mui/material/Box";
15
- import _ from "lodash";
16
15
  import type React from "react";
17
16
  import { useRef } from "react";
18
17
 
@@ -33,7 +32,10 @@ interface Props {
33
32
  * </SearchBar>
34
33
  *
35
34
  */
36
- export default function SearchBarRoot({ handleCloseDrawer, children }: Props) {
35
+ export default function SearchBarRoot({
36
+ handleCloseDrawer,
37
+ children,
38
+ }: Readonly<Props>) {
37
39
  const { setters, handlers, state } = useSearch();
38
40
  const inputRef = useRef(null);
39
41
  useClickOutside(inputRef, () => setters.setResultsOpen(false));
@@ -51,33 +51,31 @@ const CategoryDropdown = ({
51
51
  const title = findCategoryNameById(selectedCategoryId, categories, t);
52
52
 
53
53
  return (
54
- <>
55
- <Menu
56
- direction="left"
57
- sx={{ zIndex: breakpoints.down("md") ? 99999 : 1502 }}
58
- handler={(e) => (
59
- <DropDownHandler as={TouchRipple} onClick={e}>
60
- {title}
61
- <KeyboardArrowDownOutlined fontSize="small" color="inherit" />
62
- </DropDownHandler>
63
- )}
64
- options={(onClose) => {
65
- return options
66
- ?.filter((current: DisplayCategory) => current.name !== title)
67
- .map((item: DisplayCategory) => (
68
- <MenuItem
69
- key={item.id}
70
- onClick={() => {
71
- handleChange(item.id);
72
- onClose();
73
- }}
74
- >
75
- {item.name}
76
- </MenuItem>
77
- ));
78
- }}
79
- />
80
- </>
54
+ <Menu
55
+ direction="left"
56
+ sx={{ zIndex: breakpoints.down("md") ? 99999 : 1502 }}
57
+ handler={(e) => (
58
+ <DropDownHandler as={TouchRipple} onClick={e}>
59
+ {title}
60
+ <KeyboardArrowDownOutlined fontSize="small" color="inherit" />
61
+ </DropDownHandler>
62
+ )}
63
+ options={(onClose) => {
64
+ return options
65
+ ?.filter((current: DisplayCategory) => current.name !== title)
66
+ .map((item: DisplayCategory) => (
67
+ <MenuItem
68
+ key={item.id}
69
+ onClick={() => {
70
+ handleChange(item.id);
71
+ onClose();
72
+ }}
73
+ >
74
+ {item.name}
75
+ </MenuItem>
76
+ ));
77
+ }}
78
+ />
81
79
  );
82
80
  };
83
81
 
@@ -9,7 +9,6 @@ import SearchIconAdornment from "@evenicanpm/storefront-core/src/components-v2/s
9
9
  import { INPUT_SX } from "@evenicanpm/storefront-core/src/components-v2/search-bar/styles/index";
10
10
  import { useMediaQuery, useTheme } from "@mui/material";
11
11
  import TextField from "@mui/material/TextField";
12
- import _ from "lodash";
13
12
  import { useTranslations } from "next-intl";
14
13
  import React from "react";
15
14
 
@@ -26,7 +26,7 @@ export default function useSearch() {
26
26
  if (searchText.trim() === "") {
27
27
  return;
28
28
  }
29
- const url = new URL(PageSlug.ProductList, window.location.origin);
29
+ const url = new URL(PageSlug.ProductList, globalThis.location.origin);
30
30
  url.searchParams.set(PageKey.SEARCH, searchText);
31
31
  router.push(url.toString());
32
32
  setResultsOpen(false);
@@ -60,7 +60,7 @@ export const LongContent: Story = {
60
60
  </Section.Header>
61
61
 
62
62
  {Array.from({ length: 5 }).map((_, i) => (
63
- <Typography key={i} paragraph>
63
+ <Typography key={`paragraph-${i + 1}`} paragraph>
64
64
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Paragraph{" "}
65
65
  {i + 1}.
66
66
  </Typography>
@@ -13,7 +13,7 @@ interface Props {
13
13
  handler: (event: () => void) => ReactNode;
14
14
  }
15
15
 
16
- export default function SideNav(props: Props) {
16
+ export default function SideNav(props: Readonly<Props>) {
17
17
  const {
18
18
  position = "left",
19
19
  open = false,
@@ -44,7 +44,7 @@ export default function AddToWishlistDialog({
44
44
  handleClose,
45
45
  productId,
46
46
  children,
47
- }: AddToWishlistDialogProps) {
47
+ }: Readonly<AddToWishlistDialogProps>) {
48
48
  const { data: wishlists } = getWishlists.useSuspenseData();
49
49
 
50
50
  const { data: session } = useSession();
@@ -33,8 +33,8 @@ const WishlistList = ({ children }: { children: React.ReactNode }) => {
33
33
  return <NoRecords message="Account.Wishlists.noWishlists" />;
34
34
  }
35
35
 
36
- return wishlists?.map((wishlist: Wishlist, i: number) => (
37
- <WishListItemContext.Provider value={{ wishlist }} key={i}>
36
+ return wishlists?.map((wishlist: Wishlist) => (
37
+ <WishListItemContext.Provider value={{ wishlist }} key={wishlist.Id}>
38
38
  {children}
39
39
  </WishListItemContext.Provider>
40
40
  ));
@@ -56,6 +56,7 @@ export default function UseWishlist() {
56
56
  message: t("wishlistLineAddFailed"),
57
57
  severity: "error",
58
58
  });
59
+ console.log(error);
59
60
  }
60
61
  };
61
62
 
@@ -89,6 +90,7 @@ export default function UseWishlist() {
89
90
  message: t("wishlistLineRemoveFailed"),
90
91
  severity: "error",
91
92
  });
93
+ console.log(error);
92
94
  }
93
95
  };
94
96
 
@@ -12,19 +12,17 @@ interface Props {
12
12
  */
13
13
  const AddToWishListDialog1 = ({ open, handleClose, productId }: Props) => {
14
14
  return (
15
- <>
16
- <AddToWishlistDialog
17
- open={open}
18
- handleClose={handleClose}
19
- productId={productId}
20
- >
21
- <AddToWishlistDialog.Header />
22
- <AddToWishlistDialog.List>
23
- <AddToWishlistDialog.List.Item />
24
- </AddToWishlistDialog.List>
25
- <AddToWishlistDialog.BottomUI />
26
- </AddToWishlistDialog>
27
- </>
15
+ <AddToWishlistDialog
16
+ open={open}
17
+ handleClose={handleClose}
18
+ productId={productId}
19
+ >
20
+ <AddToWishlistDialog.Header />
21
+ <AddToWishlistDialog.List>
22
+ <AddToWishlistDialog.List.Item />
23
+ </AddToWishlistDialog.List>
24
+ <AddToWishlistDialog.BottomUI />
25
+ </AddToWishlistDialog>
28
26
  );
29
27
  };
30
28
 
@@ -39,7 +39,7 @@ interface CreateNewWishlistContext {
39
39
  export const CreateNewWishlistContext =
40
40
  createContext<CreateNewWishlistContext | null>(null);
41
41
 
42
- export default function CreateNewList(props: Props) {
42
+ export default function CreateNewList(props: Readonly<Props>) {
43
43
  const { children } = props;
44
44
  const t = useTranslations("Account.Wishlists");
45
45
  const { setNotification } = useNotification();
@@ -59,6 +59,7 @@ export default function CreateNewList(props: Props) {
59
59
  message: t("wishlistFailed"),
60
60
  severity: "error",
61
61
  });
62
+ console.log(error);
62
63
  }
63
64
  };
64
65
 
@@ -51,7 +51,6 @@ export default function useVariants(product: ProductDetails) {
51
51
  const handleSelectDimension = async (
52
52
  dimensionValue: ProductDimensionValueInventoryAvailability,
53
53
  ) => {
54
- //prefetchPDPData(dimensionValue, queryClient);
55
54
  dispatch({
56
55
  type: "SELECT_DIMENSION",
57
56
  dimensionValue,
@@ -98,37 +97,36 @@ const prefetchPDPData = (
98
97
  * Reducer synchronizes selected dimensions and variant ID
99
98
  */
100
99
  const variantReducer = (state: VariantState, action: VariantAction) => {
101
- switch (action.type) {
102
- case "SELECT_DIMENSION": {
103
- const newDimensionsState: SelectedDimensions = {
104
- ...state.selectDimensions,
105
- [action.dimensionValue?.DimensionTypeValue ?? ""]:
106
- action.dimensionValue,
107
- };
108
-
109
- const allDimensionsSelected =
110
- Object.keys(newDimensionsState).length === action.totalDimensions;
111
-
112
- // We cannot select a variant until all dimensions are selected
113
- if (!allDimensionsSelected)
114
- return {
115
- ...state,
116
- selectDimensions: newDimensionsState,
117
- selectedVariantRecordId: undefined,
118
- };
119
-
120
- const dimensionsArray = Object.values(newDimensionsState);
100
+ if (action.type === "SELECT_DIMENSION") {
101
+ const newDimensionsState: SelectedDimensions = {
102
+ ...state.selectDimensions,
103
+ [action.dimensionValue?.DimensionTypeValue ?? ""]: action.dimensionValue,
104
+ };
121
105
 
122
- // Deduce product id from selected dimensions
123
- const intersectedVariantIds = dimensionsArray.reduce((ids, dimension) => {
124
- return ids.filter((id) => dimension.ProductIds?.includes(id));
125
- }, dimensionsArray[0]?.ProductIds || []);
106
+ const allDimensionsSelected =
107
+ Object.keys(newDimensionsState).length === action.totalDimensions;
126
108
 
109
+ // We cannot select a variant until all dimensions are selected
110
+ if (!allDimensionsSelected)
127
111
  return {
128
112
  ...state,
129
113
  selectDimensions: newDimensionsState,
130
- selectedVariantRecordId: intersectedVariantIds[0], // There can be only one!
114
+ selectedVariantRecordId: undefined,
131
115
  };
132
- }
116
+
117
+ const dimensionsArray = Object.values(newDimensionsState);
118
+
119
+ // Deduce product id from selected dimensions
120
+ const intersectedVariantIds = dimensionsArray.reduce((ids, dimension) => {
121
+ return ids.filter((id) => dimension.ProductIds?.includes(id));
122
+ }, dimensionsArray[0]?.ProductIds || []);
123
+
124
+ return {
125
+ ...state,
126
+ selectDimensions: newDimensionsState,
127
+ selectedVariantRecordId: intersectedVariantIds[0], // There can be only one!
128
+ };
133
129
  }
130
+
131
+ return state;
134
132
  };
@@ -4,6 +4,6 @@ const buildDetailUrl = (name: string, id: number) =>
4
4
  `/${PageSlug.ProductDetail}/${normalizeName(name)}/${id}`;
5
5
 
6
6
  const normalizeName = (name: string) =>
7
- name ? name.toLowerCase().replace(/ /g, "-") : "";
7
+ name ? name.toLowerCase().replaceAll(" ", "-") : "";
8
8
 
9
9
  export default buildDetailUrl;
@@ -67,7 +67,7 @@ const mapCategoryToHierarchy = (
67
67
  return categoryHierarchy;
68
68
  }
69
69
 
70
- return JSON.parse(JSON.stringify(rootCategory.Children)) ?? [];
70
+ return globalThis.structuredClone(rootCategory.Children) ?? [];
71
71
  };
72
72
 
73
73
  const generateUrl = (
@@ -86,7 +86,7 @@ const generateUrl = (
86
86
  );
87
87
  }
88
88
  categoryNames.unshift(currentCategory.RecordId.toString());
89
- return categoryNames.reverse().join("/");
89
+ return categoryNames.slice().reverse().join("/");
90
90
  };
91
91
 
92
92
  const getFriendlyName = (
@@ -99,7 +99,7 @@ const getFriendlyName = (
99
99
  (item) => item?.Language?.toLowerCase() === locale?.toLowerCase(),
100
100
  );
101
101
  }
102
- return nameTranslation && nameTranslation.Text;
102
+ return nameTranslation?.Text;
103
103
  };
104
104
 
105
105
  const normalizeCategoryName = (string_: string) =>
@@ -3,6 +3,36 @@ import type { Theme } from "@mui/material";
3
3
  // Define a union type for possible color values
4
4
  type ColorValue = string | number | (() => string);
5
5
 
6
+ // Helper to resolve possible function values
7
+ const resolveColorValue = (value: ColorValue): string => {
8
+ return typeof value === "function" ? value() : String(value);
9
+ };
10
+
11
+ // Helper to get main color if available
12
+ const getMainColor = (colorObj: Record<string, ColorValue>): string => {
13
+ if ("main" in colorObj) {
14
+ const mainValue = colorObj.main;
15
+ return resolveColorValue(mainValue);
16
+ }
17
+ return "";
18
+ };
19
+
20
+ // Helper to get shade color if available
21
+ const getShadeColor = (
22
+ colorObj: Record<string, ColorValue>,
23
+ shade: number | string,
24
+ ): string | undefined => {
25
+ const shadeKey = shade.toString();
26
+
27
+ // Try to access the shade
28
+ if (shadeKey in colorObj) {
29
+ const value = colorObj[shadeKey];
30
+ return resolveColorValue(value);
31
+ }
32
+
33
+ return undefined;
34
+ };
35
+
6
36
  // Type-safe color getter function
7
37
  const getPaletteColor = (
8
38
  theme: Theme,
@@ -21,30 +51,20 @@ const getPaletteColor = (
21
51
 
22
52
  // If shade is specified, try to get it
23
53
  if (shade !== undefined) {
24
- const shadeKey = shade.toString();
54
+ const shadeColor = getShadeColor(colorObj, shade);
25
55
 
26
- // Try to access the shade
27
- if (shadeKey in colorObj) {
28
- const value = colorObj[shadeKey];
29
- // Handle possible function values
30
- return typeof value === "function" ? value() : String(value);
56
+ if (shadeColor) {
57
+ return shadeColor;
31
58
  }
32
59
 
33
60
  // Check if this is a PaletteColor with main/dark/light properties
34
- if ("main" in colorObj) {
35
- const mainValue = colorObj.main;
36
- return typeof mainValue === "function" ? mainValue() : String(mainValue);
37
- }
61
+ return getMainColor(colorObj);
38
62
  }
39
63
 
40
64
  // If no shade specified but color has 'main' property
41
- if ("main" in colorObj) {
42
- const mainValue = colorObj.main;
43
- return typeof mainValue === "function" ? mainValue() : String(mainValue);
44
- }
65
+ return getMainColor(colorObj);
45
66
 
46
67
  // Last resort fallback
47
- return "";
48
68
  };
49
69
 
50
70
  export default getPaletteColor;
@@ -8,7 +8,7 @@ function sRGBtoLin(colorChannel: number): number {
8
8
  return ((colorChannel + 0.055) / 1.055) ** 2.4;
9
9
  }
10
10
  }
11
- 1;
11
+
12
12
  function YtoLstar(Y: number): number {
13
13
  // Send this function a luminance value between 0.0 and 1.0,
14
14
  // and it returns L* which is "perceptual lightness"
@@ -30,7 +30,7 @@ export const hexToLuma = (hex: string): number => {
30
30
  throw new Error("not a valid hex color code");
31
31
  }
32
32
 
33
- const number = Number.parseInt(hex[0] === "#" ? hex.slice(1) : hex, 16);
33
+ const number = Number.parseInt(hex.startsWith("#") ? hex.slice(1) : hex, 16);
34
34
  const red = number >> 16;
35
35
  const green = (number >> 8) & 255;
36
36
  const blue = number & 255;
@@ -46,7 +46,7 @@ export const secondsToTime = (
46
46
  let hours = Math.floor(seconds / (60 * 60));
47
47
  const ampm = hours >= 12 ? "pm" : "am";
48
48
  hours %= 12;
49
- hours = hours ? hours : 12;
49
+ hours = hours || 12;
50
50
  const divisorForMinutes = seconds % (60 * 60);
51
51
  const minutes =
52
52
  Math.floor(divisorForMinutes / 60) < 10
@@ -107,13 +107,13 @@ const buildHoursDisplayInfo = (
107
107
  hoursInfo: string,
108
108
  resources: IStoreSelectorLocationLineItemResources,
109
109
  ): IHoursDisplayInfo => {
110
+ const isSameDay = startDay === endDay;
111
+
110
112
  return {
111
113
  startDayShort: getShortTimeString(startDay, resources),
112
114
  startDayFull: getFullTimeString(startDay, resources),
113
- endDayShort:
114
- startDay !== endDay ? getShortTimeString(endDay, resources) : undefined,
115
- endDayFull:
116
- startDay !== endDay ? getFullTimeString(endDay, resources) : undefined,
115
+ endDayShort: isSameDay ? undefined : getShortTimeString(endDay, resources),
116
+ endDayFull: isSameDay ? undefined : getFullTimeString(endDay, resources),
117
117
  timeRange: hoursInfo,
118
118
  };
119
119
  };
@@ -43,7 +43,8 @@ interface RootProps {
43
43
  }
44
44
 
45
45
  const AddressForm = ({ address, children }: RootProps) => {
46
- const [tn, t] = ["Account.Addresses", "Address"].map(useTranslations);
46
+ const tn = useTranslations("Account.Addresses");
47
+ const t = useTranslations("Address");
47
48
  const { setNotification } = useNotification();
48
49
  const router = useRouter();
49
50
  const locale = useLocale();
@@ -118,6 +119,7 @@ const AddressForm = ({ address, children }: RootProps) => {
118
119
  message: tn("addressFailed"),
119
120
  severity: "error",
120
121
  });
122
+ console.log(error);
121
123
  }
122
124
  };
123
125
 
@@ -153,9 +155,9 @@ AddressForm.Fields = ({ children }: { children?: React.ReactNode }) => {
153
155
 
154
156
  AddressForm.Field = ({ name, label, required }: FieldProps) => {
155
157
  const ctx = useContext(FormContext);
158
+ const t = useTranslations("Address");
156
159
  if (!ctx) return null;
157
160
  const { formik } = ctx;
158
- const t = useTranslations("Address");
159
161
 
160
162
  return (
161
163
  <Grid size={{ sm: 6, xs: 12 }}>
@@ -180,9 +182,9 @@ AddressForm.Field = ({ name, label, required }: FieldProps) => {
180
182
 
181
183
  AddressForm.Country = () => {
182
184
  const ctx = useContext(FormContext);
185
+ const t = useTranslations("Address");
183
186
  if (!ctx) return null;
184
187
  const { formik, countries, setSelectedCountry } = ctx;
185
- const t = useTranslations("Address");
186
188
 
187
189
  return (
188
190
  <Grid size={{ sm: 6, xs: 12 }}>
@@ -210,8 +212,8 @@ AddressForm.Country = () => {
210
212
  }}
211
213
  >
212
214
  <MenuItem value="">Select Country</MenuItem>
213
- {countries?.map(({ ShortName, CountryRegionId }, i) => (
214
- <MenuItem key={i} value={CountryRegionId}>
215
+ {countries?.map(({ ShortName, CountryRegionId }) => (
216
+ <MenuItem key={CountryRegionId} value={CountryRegionId}>
215
217
  {ShortName}
216
218
  </MenuItem>
217
219
  ))}
@@ -230,9 +232,9 @@ AddressForm.Country = () => {
230
232
 
231
233
  AddressForm.State = () => {
232
234
  const ctx = useContext(FormContext);
235
+ const t = useTranslations("Address");
233
236
  if (!ctx) return null;
234
237
  const { formik, states } = ctx;
235
- const t = useTranslations("Address");
236
238
 
237
239
  return (
238
240
  <Grid size={{ sm: 6, xs: 12 }}>
@@ -253,8 +255,8 @@ AddressForm.State = () => {
253
255
  onBlur={formik.handleBlur}
254
256
  >
255
257
  <MenuItem value="">Select a state</MenuItem>
256
- {states?.map(({ StateId, StateName }, i) => (
257
- <MenuItem key={i} value={StateId}>
258
+ {states?.map(({ StateId, StateName }) => (
259
+ <MenuItem key={StateId} value={StateId}>
258
260
  {StateName}
259
261
  </MenuItem>
260
262
  ))}
@@ -114,9 +114,9 @@ AddressListItem.Actions = ({ children }: { children: ReactNode }) => {
114
114
 
115
115
  AddressListItem.Primary = () => {
116
116
  const ctx = useContext(AddressContext);
117
+ const t = useTranslations("Account.Addresses");
117
118
  if (!ctx) return null;
118
119
  const { address, setPrimaryAddress } = ctx;
119
- const t = useTranslations("Account.Addresses");
120
120
  const rid = address.RecordId?.toString();
121
121
  const addrId = address.Id ?? rid ?? "";
122
122
 
@@ -85,7 +85,7 @@ OrderProgress.Steps = () => {
85
85
  return (
86
86
  <StyledFlexbox>
87
87
  {stepIcons.map((Icon, index) => (
88
- <Fragment key={index}>
88
+ <Fragment key={`step-${index + 1}`}>
89
89
  <Box position="relative">
90
90
  <Avatar
91
91
  alt="step"
@@ -141,7 +141,7 @@ OrderedProducts.Dimensions = ({ item }: { item: SalesLine }) => {
141
141
  return (
142
142
  <Grid size={{ xs: 8, sm: 4 }}>
143
143
  {item.Product.Dimensions.map((dim, i) => (
144
- <Paragraph key={i} paddingLeft={"15px"}>
144
+ <Paragraph key={`product-dim-${i + 1}`} paddingLeft={"15px"}>
145
145
  <Span>{ProductDimensionType[dim.DimensionTypeValue || 0]}:</Span>
146
146
  <Span sx={{ ml: 1 }}>{dim.DimensionValue?.Value}</Span>
147
147
  </Paragraph>