@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
@@ -25,7 +25,7 @@ export default function DeliveryDate({
25
25
  handleChange,
26
26
  touched,
27
27
  values,
28
- }: Props) {
28
+ }: Readonly<Props>) {
29
29
  const [dateList, setDateList] = useState<{ label: string; value: string }[]>(
30
30
  [],
31
31
  );
@@ -155,21 +155,20 @@ const DeliveryOptions: DeliveryOptionsCompound = (props) => {
155
155
 
156
156
  return (
157
157
  <>
158
- {children ? (
159
- children
160
- ) : stepViewState === "preview" ? (
161
- <DeliveryOptions.Preview
162
- deliveryOptions={deliveryOptions}
163
- selectedOption={selectedOption}
164
- />
165
- ) : (
166
- <DeliveryOptions.Form
167
- deliveryOptions={deliveryOptions}
168
- deliveryUnavailable={deliveryUnavailable}
169
- selectedOption={selectedOption}
170
- onChange={handleOptionChange}
171
- />
172
- )}
158
+ {children ||
159
+ (stepViewState === "preview" ? (
160
+ <DeliveryOptions.Preview
161
+ deliveryOptions={deliveryOptions}
162
+ selectedOption={selectedOption}
163
+ />
164
+ ) : (
165
+ <DeliveryOptions.Form
166
+ deliveryOptions={deliveryOptions}
167
+ deliveryUnavailable={deliveryUnavailable}
168
+ selectedOption={selectedOption}
169
+ onChange={handleOptionChange}
170
+ />
171
+ ))}
173
172
  </>
174
173
  );
175
174
  };
@@ -68,16 +68,17 @@ OrderSummary.Title = () => {
68
68
 
69
69
  OrderSummary.Item = ({ label, field }: ItemProps) => {
70
70
  const ctx = useContext(SummaryContext);
71
- if (!ctx) return null;
72
71
  const t = useTranslations("Checkout.Summary");
72
+ if (!ctx) return null;
73
73
  const { formatCurrency, order } = ctx;
74
74
  const value = order[field];
75
- const numericValue =
76
- typeof value === "number"
77
- ? value
78
- : typeof value === "string"
79
- ? parseFloat(value)
80
- : 0;
75
+ let numericValue = 0;
76
+
77
+ if (typeof value === "number") {
78
+ numericValue = value;
79
+ } else if (typeof value === "string") {
80
+ numericValue = Number.parseFloat(value);
81
+ }
81
82
 
82
83
  return (
83
84
  <FlexBetween mb={1}>
@@ -35,10 +35,10 @@ export const OrderedProducts = ({ order, children }: Props) => {
35
35
 
36
36
  OrderedProducts.Header = () => {
37
37
  const ctx = useContext(OrderedProductsContext);
38
- if (!ctx) return null;
39
38
  const t = useTranslations("Confirmation");
40
- const order = ctx;
41
39
  const { dateTime } = useFormatter();
40
+ if (!ctx) return null;
41
+ const order = ctx;
42
42
 
43
43
  return (
44
44
  <FlexBetween
@@ -128,7 +128,7 @@ OrderedProducts.Dimensions = ({ line }: LineProps) => {
128
128
  return (
129
129
  <Grid size={{ xs: 8, sm: 4 }}>
130
130
  {line.Product.Dimensions.map((dim, i) => (
131
- <Paragraph key={i} paddingLeft="15px">
131
+ <Paragraph key={`dim-${i + 1}`} paddingLeft="15px">
132
132
  <Span>{ProductDimensionType[dim.DimensionTypeValue || 0]}:</Span>
133
133
  <Span sx={{ ml: 1 }}>{dim.DimensionValue?.Value}</Span>
134
134
  </Paragraph>
@@ -75,7 +75,7 @@ const PickupOptionSelect = ({
75
75
  );
76
76
 
77
77
  const handlePickupClick = () => {
78
- if (selectedOption && selectedOption.Code) {
78
+ if (selectedOption?.Code) {
79
79
  const bopisInput: AddToCartBopisInput = {
80
80
  warehouseId: storeId,
81
81
  deliveryMode: selectedOption.Code,
@@ -35,7 +35,7 @@ type Props = {
35
35
  inventoryRecord: ProductWarehouseInventoryAvailability | undefined;
36
36
  };
37
37
 
38
- export default function ShopCard(props: Props) {
38
+ export default function ShopCard(props: Readonly<Props>) {
39
39
  const { name, address, actionArea, openFrom, openTo, storeHours } =
40
40
  props || {};
41
41
 
@@ -9,7 +9,7 @@ interface Props extends CheckboxProps {
9
9
  }
10
10
  // ==============================================================
11
11
 
12
- export default function CheckboxLabel({ label, ...props }: Props) {
12
+ export default function CheckboxLabel({ label, ...props }: Readonly<Props>) {
13
13
  return (
14
14
  <FormControlLabel
15
15
  label={label}
@@ -32,7 +32,7 @@ const WrapperBox = styled(Box)(({ theme }) => ({
32
32
  type Props = { products: Product[] };
33
33
  // ============================================================
34
34
 
35
- export default function FrequentlyBought({ products }: Props) {
35
+ export default function FrequentlyBought({ products }: Readonly<Props>) {
36
36
  return (
37
37
  <WrapperBox mb={7.5}>
38
38
  <H3 mb={3}>Frequently Bought Together</H3>
@@ -25,7 +25,7 @@ interface Props {
25
25
  }
26
26
  // =======================================================
27
27
 
28
- export default function FrequentlyProductCard(props: Props) {
28
+ export default function FrequentlyProductCard(props: Readonly<Props>) {
29
29
  const {
30
30
  imgUrl = "/assets/images/products/Rectangle 116.png",
31
31
  price,
@@ -24,7 +24,7 @@ interface Props {
24
24
  }
25
25
  // ===========================================================
26
26
 
27
- export default function ProductComment(props: Props) {
27
+ export default function ProductComment(props: Readonly<Props>) {
28
28
  const { name, imgUrl, rating, date, comment } = props || {};
29
29
 
30
30
  return (
@@ -5,14 +5,14 @@ import type { AttributeValue } from "@msdyn365-commerce/retail-proxy";
5
5
 
6
6
  type Props = { attributes: AttributeValue[] };
7
7
 
8
- export default function ProductDescription({ attributes }: Props) {
8
+ export default function ProductDescription({ attributes }: Readonly<Props>) {
9
9
  return (
10
10
  <div>
11
11
  <H3 mb={2}>Specifications:</H3>
12
12
  {attributes?.map((attr, index) => {
13
13
  if (attr?.TextValue && attr?.Name)
14
14
  return (
15
- <div key={index}>
15
+ <div key={`attr-${index + 1}`}>
16
16
  {attr.Name}: {attr.TextValue}
17
17
  </div>
18
18
  );
@@ -71,7 +71,10 @@ interface Props {
71
71
  }
72
72
  // ============================================================================
73
73
 
74
- export default function ProductFilterCard({ filters, changeFilters }: Props) {
74
+ export default function ProductFilterCard({
75
+ filters,
76
+ changeFilters,
77
+ }: Readonly<Props>) {
75
78
  const [collapsed, setCollapsed] = useState(true);
76
79
 
77
80
  const handleChangePrice = (values: number[]) => {
@@ -21,7 +21,7 @@ type Props = {
21
21
  /**
22
22
  * @category Compound Component
23
23
  */
24
- export default function ProductImages({ children }: Props) {
24
+ export default function ProductImages({ children }: Readonly<Props>) {
25
25
  const [selectedImageIndex, setSelectedImageIndex] = useState<number>(0);
26
26
 
27
27
  const ctx = useContext(ProductIntroContext);
@@ -34,12 +34,19 @@ export default function ProductImages({ children }: Props) {
34
34
  * VARIANT SELECTION - IF VARIANT HAS IMAGES, USE THOSE
35
35
  * IF NOT USE masterProduct
36
36
  */
37
- const images =
38
- Array.isArray(selectedVariant?.Images) && selectedVariant?.Images.length > 0
39
- ? selectedVariant?.Images
40
- : Array.isArray(masterProduct?.Images) && masterProduct?.Images.length > 0
41
- ? masterProduct?.Images
42
- : [];
37
+ let images: string[] = [];
38
+
39
+ if (
40
+ Array.isArray(selectedVariant?.Images) &&
41
+ selectedVariant.Images.length > 0
42
+ ) {
43
+ images = selectedVariant.Images;
44
+ } else if (
45
+ Array.isArray(masterProduct?.Images) &&
46
+ masterProduct.Images.length > 0
47
+ ) {
48
+ images = masterProduct.Images;
49
+ }
43
50
 
44
51
  const primaryImageUrl =
45
52
  selectedVariant?.PrimaryImageUrl || masterProduct?.PrimaryImageUrl || "";
@@ -80,30 +87,28 @@ ProductImages.Thumbnails = () => {
80
87
  const { images, handleImageClick, selectedImageIndex } = ctx;
81
88
 
82
89
  return (
83
- <>
84
- <FlexBox overflow="auto" gap={1} justifyContent="center">
85
- {images?.map((url: string, ind: number) => {
86
- return (
87
- <FlexRowCenter
88
- key={ind}
89
- width={64}
90
- height={64}
91
- minWidth={64}
92
- bgcolor="white"
93
- border="1px solid"
94
- borderRadius="10px"
95
- style={{ cursor: "pointer" }}
96
- onClick={handleImageClick(ind)}
97
- borderColor={
98
- selectedImageIndex === ind ? "primary.main" : "grey.400"
99
- }
100
- >
101
- <ThumbnailWithSkeleton src={url} />
102
- </FlexRowCenter>
103
- );
104
- })}
105
- </FlexBox>
106
- </>
90
+ <FlexBox overflow="auto" gap={1} justifyContent="center">
91
+ {images?.map((url: string, ind: number) => {
92
+ return (
93
+ <FlexRowCenter
94
+ key={`thumbnail-${ind + 1}`}
95
+ width={64}
96
+ height={64}
97
+ minWidth={64}
98
+ bgcolor="white"
99
+ border="1px solid"
100
+ borderRadius="10px"
101
+ style={{ cursor: "pointer" }}
102
+ onClick={handleImageClick(ind)}
103
+ borderColor={
104
+ selectedImageIndex === ind ? "primary.main" : "grey.400"
105
+ }
106
+ >
107
+ <ThumbnailWithSkeleton src={url} />
108
+ </FlexRowCenter>
109
+ );
110
+ })}
111
+ </FlexBox>
107
112
  );
108
113
  };
109
114
 
@@ -14,7 +14,7 @@ import type React from "react";
14
14
  */
15
15
  type Props = { product: ProductDetails; children: React.ReactNode };
16
16
 
17
- export default function ProductIntro({ product, children }: Props) {
17
+ export default function ProductIntro({ product, children }: Readonly<Props>) {
18
18
  // HOOKS
19
19
  const {
20
20
  selectedVariant,
@@ -5,7 +5,7 @@ import { useState } from "react";
5
5
  * Shows a skeleton until the image loads
6
6
  * @category Sub-Component
7
7
  */
8
- function ThumbnailWithSkeleton({ src }: { src: string }) {
8
+ function ThumbnailWithSkeleton({ src }: Readonly<{ src: string }>) {
9
9
  const [loaded, setLoaded] = useState(false);
10
10
 
11
11
  return (
@@ -4,8 +4,7 @@ export const getInventoryLabel = (
4
4
  shippingInventoryData?: ProductWarehouseInventoryInformation,
5
5
  ): string | null => {
6
6
  const aggregate =
7
- shippingInventoryData?.AggregatedProductInventoryAvailabilities &&
8
- shippingInventoryData?.AggregatedProductInventoryAvailabilities[0];
7
+ shippingInventoryData?.AggregatedProductInventoryAvailabilities?.[0];
9
8
  if (aggregate) {
10
9
  const { TotalAvailableInventoryLevelLabel } = aggregate;
11
10
  return TotalAvailableInventoryLevelLabel || null;
@@ -19,8 +18,7 @@ export const checkProductOOS = (
19
18
  //TODO: Incorporate global inventory enabled flag.
20
19
  const OOSCode = "OOS"; // Always means out of stock
21
20
  const aggregate =
22
- shippingInventoryData?.AggregatedProductInventoryAvailabilities &&
23
- shippingInventoryData?.AggregatedProductInventoryAvailabilities[0];
21
+ shippingInventoryData?.AggregatedProductInventoryAvailabilities?.[0];
24
22
  if (aggregate) {
25
23
  const { TotalAvailableInventoryLevelCode } = aggregate;
26
24
  return TotalAvailableInventoryLevelCode === OOSCode;
@@ -48,7 +48,7 @@ export default function ProductReview() {
48
48
  return (
49
49
  <div>
50
50
  {commentList.map((item, ind) => (
51
- <ProductComment {...item} key={ind} />
51
+ <ProductComment {...item} key={`comment-${ind + 1}`} />
52
52
  ))}
53
53
 
54
54
  <H2 fontWeight="600" mt={7} mb={2.5}>
@@ -37,7 +37,7 @@ interface TabPanelProps {
37
37
  value: number;
38
38
  }
39
39
 
40
- function CustomTabPanel(props: TabPanelProps) {
40
+ function CustomTabPanel(props: Readonly<TabPanelProps>) {
41
41
  const { children, value, index, ...other } = props;
42
42
 
43
43
  return (
@@ -52,7 +52,10 @@ const TabsContext = createContext<TabsContext | null>(null);
52
52
  /**
53
53
  * @category Compound Component
54
54
  */
55
- export default function ProductTabs({ productAttributes, children }: Props) {
55
+ export default function ProductTabs({
56
+ productAttributes,
57
+ children,
58
+ }: Readonly<Props>) {
56
59
  const [selectedOption, setSelectedOption] = useState(0);
57
60
  const handleOptionClick = (_: React.SyntheticEvent, value: number) =>
58
61
  setSelectedOption(value);
@@ -12,7 +12,7 @@ import Grid from "@mui/material/Grid2";
12
12
  type Props = { RecordId: number };
13
13
  // ==============================================================
14
14
 
15
- export default function RelatedProducts({ RecordId }: Props) {
15
+ export default function RelatedProducts({ RecordId }: Readonly<Props>) {
16
16
  const { data: products } = GetRelatedProductsDataFetcher.useData({
17
17
  id: RecordId,
18
18
  });
@@ -21,12 +21,15 @@ export default function RelatedProducts({ RecordId }: Props) {
21
21
  <H3 mb={3}>Related Products</H3>
22
22
 
23
23
  <Grid container spacing={3}>
24
- {products?.map((item, ind) => (
25
- <Grid size={{ lg: 3, md: 4, sm: 6, xs: 12 }} key={ind}>
24
+ {products?.map((item) => (
25
+ <Grid
26
+ size={{ lg: 3, md: 4, sm: 6, xs: 12 }}
27
+ key={item.RecordId ?? item.ItemId}
28
+ >
26
29
  <ProductCard
27
30
  product={{
28
31
  id: item.ItemId ?? "",
29
- slug: String(item?.RecordId) ?? "",
32
+ slug: String(item?.RecordId ?? ""),
30
33
  title: item.Name ?? "",
31
34
  price: item.Price ?? 0,
32
35
  imgUrl: item.PrimaryImageUrl ?? "",
@@ -17,7 +17,7 @@ export default function CategoryBreadcrumbs({
17
17
  breadcrumbs,
18
18
  locale,
19
19
  productName,
20
- }: Props) {
20
+ }: Readonly<Props>) {
21
21
  return (
22
22
  <Breadcrumbs>
23
23
  {breadcrumbs.map((bc, index) =>
@@ -9,7 +9,7 @@ interface Props extends CheckboxProps {
9
9
  }
10
10
  // ==============================================================
11
11
 
12
- export default function CheckboxLabel({ label, ...props }: Props) {
12
+ export default function CheckboxLabel({ label, ...props }: Readonly<Props>) {
13
13
  return (
14
14
  <FormControlLabel
15
15
  label={label}
@@ -31,7 +31,7 @@ export default function FacetGroup({
31
31
  facet,
32
32
  selectedRefiners,
33
33
  handleRefinerSelect,
34
- }: Props) {
34
+ }: Readonly<Props>) {
35
35
  const isAnyRefinerFromFacetSelected = () =>
36
36
  facet.Values?.some((v) => isRefinerSelected(v));
37
37
  const isRefinerSelected = (r1: ProductRefinerValue) =>
@@ -8,7 +8,7 @@ import React from "react";
8
8
  import CheckboxLabel from "./checkbox-label";
9
9
  import type { RenderedFacetProps } from "./facet-group";
10
10
 
11
- type Props = RenderedFacetProps & NonNullable<unknown>;
11
+ type Props = RenderedFacetProps;
12
12
 
13
13
  const generateKey = (f: ProductRefinerValue) => {
14
14
  return `${f.LeftValueBoundString}-${f.RefinerRecordId}`;
@@ -18,7 +18,7 @@ export default function ListFilter({
18
18
  facet,
19
19
  handleRefinerSelect,
20
20
  isRefinerSelected,
21
- }: Props) {
21
+ }: Readonly<Props>) {
22
22
  const createFacetLabel = (f: ProductRefinerValue) => {
23
23
  const label = f.LeftValueBoundLocalizedString || f.LeftValueBoundString;
24
24
  return (
@@ -117,8 +117,10 @@ const ProductListProvider = ({ children }: { children: React.ReactNode }) => {
117
117
  const refiners = newInputParams.searchState.refinement;
118
118
  const priceIndex = ProductRefinerSource.Price;
119
119
  const idx = refiners.findIndex((r) => areRefinersEqual(r, refiner));
120
+
120
121
  if (refiner.RefinerSourceValue === priceIndex) {
121
122
  const priceRefiner = refiners[idx];
123
+
122
124
  if (idx > -1) {
123
125
  if (
124
126
  priceRefiner.LeftValueBoundString ===
@@ -133,7 +135,9 @@ const ProductListProvider = ({ children }: { children: React.ReactNode }) => {
133
135
  } else {
134
136
  refiners.push(refiner);
135
137
  }
136
- } else {
138
+ }
139
+
140
+ if (refiner.RefinerSourceValue !== priceIndex) {
137
141
  if (idx > -1) {
138
142
  refiners.splice(idx, 1);
139
143
  } else {
@@ -32,7 +32,10 @@ const usePLV = () => {
32
32
  };
33
33
 
34
34
  type RootProps = { categoryId: number; children?: ReactNode };
35
- export default function ProductListView({ categoryId, children }: RootProps) {
35
+ export default function ProductListView({
36
+ categoryId,
37
+ children,
38
+ }: Readonly<RootProps>) {
36
39
  return (
37
40
  <ProductListViewContext.Provider value={{ categoryId }}>
38
41
  {children}
@@ -6,7 +6,10 @@ interface Props extends BoxProps {
6
6
  rating: number;
7
7
  }
8
8
 
9
- export default function ProductRating({ rating = 0, ...props }: Props) {
9
+ export default function ProductRating({
10
+ rating = 0,
11
+ ...props
12
+ }: Readonly<Props>) {
10
13
  return (
11
14
  <Box display="flex" gap={1} alignItems="center" {...props}>
12
15
  <Rating size="small" value={rating} color="warn" readOnly />
@@ -5,7 +5,6 @@ import type {
5
5
  } from "@evenicanpm/storefront-core/src/api-manager/schemas/product.schema";
6
6
  import getProductAvailability from "@evenicanpm/storefront-core/src/api-manager/services/product/queries/get-product-availability";
7
7
  import { FlexBox } from "@evenicanpm/storefront-core/src/components-v2/flex-box";
8
- // import ImageWithFallback from "@app/_shared/ImageWithFallback";
9
8
  import ImageWithFallback from "@evenicanpm/storefront-core/src/components-v2/ImageWithFallback";
10
9
  import ProductDimensions from "@evenicanpm/storefront-core/src/components-v2/product-dimensions";
11
10
  import QuantityButtons from "@evenicanpm/storefront-core/src/components-v2/product-quantity-buttons";
@@ -46,7 +45,7 @@ export default function QuickViewContent({
46
45
  cart,
47
46
  productDetails,
48
47
  handleClose,
49
- }: Props) {
48
+ }: Readonly<Props>) {
50
49
  const [showDimensionError, setShowDimensionError] = useState(false);
51
50
  const {
52
51
  selectedVariant,
@@ -106,8 +105,7 @@ export default function QuickViewContent({
106
105
 
107
106
  const getInventoryLabel = (): string | null => {
108
107
  const aggregate =
109
- shippingInventoryData?.AggregatedProductInventoryAvailabilities &&
110
- shippingInventoryData?.AggregatedProductInventoryAvailabilities[0];
108
+ shippingInventoryData?.AggregatedProductInventoryAvailabilities?.[0];
111
109
  if (aggregate) {
112
110
  const { TotalAvailableInventoryLevelLabel } = aggregate;
113
111
  return TotalAvailableInventoryLevelLabel || null;
@@ -10,7 +10,11 @@ interface Props {
10
10
  product: ProductSearchResult;
11
11
  }
12
12
 
13
- export default function QuickView({ open, handleClose, product }: Props) {
13
+ export default function QuickView({
14
+ open,
15
+ handleClose,
16
+ product,
17
+ }: Readonly<Props>) {
14
18
  if (!open) {
15
19
  return;
16
20
  }
@@ -44,7 +44,6 @@ export default function RangeFilter({
44
44
  setMaxVal(Number(selectedValues.RightValueBoundString));
45
45
  setTextMin(Number(selectedValues.LeftValueBoundString));
46
46
  setTextMax(Number(selectedValues.RightValueBoundString));
47
- } else {
48
47
  }
49
48
  }, [selectedValues]);
50
49
 
@@ -29,7 +29,7 @@ export default function Scrollbar({
29
29
  autoHide = true,
30
30
  sx,
31
31
  ...props
32
- }: ScrollbarProps) {
32
+ }: Readonly<ScrollbarProps>) {
33
33
  return (
34
34
  <StyledScrollBar sx={sx} autoHide={autoHide} {...props}>
35
35
  {children}
@@ -14,7 +14,7 @@ interface Props {
14
14
  }
15
15
  // ================================================================
16
16
 
17
- export default function SideNav(props: Props) {
17
+ export default function SideNav(props: Readonly<Props>) {
18
18
  const {
19
19
  position = "left",
20
20
  open = false,
@@ -4,7 +4,7 @@ import type { ProductRefinerValue } from "@msdyn365-commerce/retail-proxy";
4
4
  import { Box, Chip, useTheme } from "@mui/material";
5
5
  import type { RenderedFacetProps } from "./facet-group";
6
6
 
7
- type Props = RenderedFacetProps & NonNullable<unknown>;
7
+ type Props = RenderedFacetProps;
8
8
 
9
9
  const cssColorName = (color: string | undefined) => {
10
10
  if (!color) return false;
@@ -21,12 +21,21 @@ export default function Swatch({
21
21
  facet,
22
22
  handleRefinerSelect,
23
23
  isRefinerSelected,
24
- }: Props) {
24
+ }: Readonly<Props>) {
25
25
  const theme = useTheme();
26
26
 
27
27
  return (
28
28
  <Box mb={3}>
29
29
  {facet.Values?.map((colorItem: ProductRefinerValue) => {
30
+ const borderStyle = (() => {
31
+ if (checkWhite(colorItem.LeftValueBoundString)) {
32
+ return "1px solid black";
33
+ }
34
+ if (isRefinerSelected(colorItem)) {
35
+ return "2px solid";
36
+ }
37
+ return "2px solid transparent";
38
+ })();
30
39
  return (
31
40
  <Box
32
41
  key={colorItem.LeftValueBoundString}
@@ -48,11 +57,7 @@ export default function Swatch({
48
57
  : theme.palette.grey[300]),
49
58
  width: 32,
50
59
  height: 32,
51
- border: checkWhite(colorItem.LeftValueBoundString)
52
- ? "1px solid black"
53
- : isRefinerSelected(colorItem)
54
- ? "2px solid"
55
- : "2px solid transparent",
60
+ border: borderStyle,
56
61
  "&:hover": {
57
62
  backgroundColor:
58
63
  colorItem.SwatchColorHexCode ||