@evenicanpm/storefront-core 1.0.6 → 1.1.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 (305) hide show
  1. package/.storybook/main.ts +37 -0
  2. package/.storybook/preview.ts +14 -0
  3. package/README.md +17 -2
  4. package/__mocks__/next-font.js +4 -0
  5. package/package.json +19 -13
  6. package/src/api-manager/datasources/e4/graphqlRequestSdk.ts +265 -5
  7. package/src/api-manager/schemas/product.schema.ts +2 -2
  8. package/src/api-manager/services/cart/mutations/add-discount-code.ts +11 -0
  9. package/src/api-manager/services/cart/mutations/checkout.ts +1 -1
  10. package/src/api-manager/services/create-query.ts +11 -4
  11. package/src/api-manager/services/product/queries/get-product-availability.ts +1 -2
  12. package/src/api-manager/services/user/mutations/add-to-wishlist.ts +2 -2
  13. package/src/api-manager/services/user/mutations/copy-cart-to-wishlist.ts +2 -1
  14. package/src/api-manager/services/user/mutations/remove-from-wishlist.ts +4 -4
  15. package/src/api-manager/services/user/mutations/update-wishlist.ts +2 -1
  16. package/src/api-manager/services/user/queries/get-wishlist-details.ts +2 -2
  17. package/src/cms/blocks/components/product-carousel/index.tsx +6 -3
  18. package/src/cms/blocks/components/product-section-fullwidth/index.tsx +2 -2
  19. package/src/cms/blocks/components/shared/product-grid.tsx +5 -2
  20. package/src/cms/interfaces/navigation.ts +9 -9
  21. package/src/components/Blocks/Components/CategoryCarousel/index.tsx +3 -3
  22. package/src/components/Blocks/Components/HeroCarousel/index.tsx +2 -2
  23. package/src/components/Blocks/Components/ProductCarousel/index.tsx +5 -5
  24. package/src/components/Blocks/Components/ProductSectionFullWidth/index.tsx +6 -6
  25. package/src/components/Blocks/Components/Services/service-card.tsx +4 -1
  26. package/src/components/Blocks/Components/shared/featured-product-card.tsx +2 -2
  27. package/src/components/Blocks/Components/shared/product-category-item.tsx +3 -3
  28. package/src/components/Blocks/Components/shared/product-grid.tsx +2 -2
  29. package/src/components/Blocks/Components/shared/top-categories-card.tsx +1 -1
  30. package/src/components/Blocks/Components/shared/top-rating-product-card.tsx +6 -3
  31. package/src/components/Footer/sections/FooterAppStore.tsx +1 -1
  32. package/src/components/Footer/sections/FooterContact.tsx +1 -1
  33. package/src/components/Footer/sections/FooterLogo.tsx +2 -2
  34. package/src/components/Footer/sections/FooterSocialLinks.tsx +1 -1
  35. package/src/components/_components/MiniCartClient.tsx +2 -2
  36. package/src/components/_components/accordion/accordion-header.tsx +1 -1
  37. package/src/components/_components/carousel-cards/carousel-card-1/carousel-card-1.tsx +2 -2
  38. package/src/components/_components/carousel-cards/carousel-card-2/carousel-card-2.tsx +9 -4
  39. package/src/components/_components/carousel-cards/carousel-card-3/carousel-card-3.tsx +6 -3
  40. package/src/components/_components/carousel-cards/carousel-card-4/carousel-card-4.tsx +6 -1
  41. package/src/components/_components/categories/category-list/category-list.tsx +3 -3
  42. package/src/components/_components/categories/mega-menu/banner.tsx +7 -3
  43. package/src/components/_components/categories/mega-menu/column-list.tsx +3 -3
  44. package/src/components/_components/categories/mega-menu/mega-menu-1.tsx +2 -2
  45. package/src/components/_components/category-cards/category-card-1/category-card-1.tsx +2 -2
  46. package/src/components/_components/countdown/count-box.tsx +4 -1
  47. package/src/components/_components/countdown/count-down.tsx +1 -1
  48. package/src/components/_components/data-table/table-header.tsx +1 -1
  49. package/src/components/_components/footer/components/app-store.tsx +1 -1
  50. package/src/components/_components/footer/components/logo.tsx +2 -2
  51. package/src/components/_components/footer/components/social-links.tsx +1 -1
  52. package/src/components/_components/footer/footer-1.tsx +1 -1
  53. package/src/components/_components/footer/footer-2.tsx +2 -2
  54. package/src/components/_components/footer/footer-3.tsx +2 -2
  55. package/src/components/_components/footer/footer-4.tsx +3 -3
  56. package/src/components/_components/header/components/categories-menu.tsx +3 -3
  57. package/src/components/_components/header/components/mobile-header.tsx +9 -6
  58. package/src/components/_components/header/components/user.tsx +5 -5
  59. package/src/components/_components/header/header.tsx +2 -2
  60. package/src/components/_components/header/sticky-header.tsx +3 -3
  61. package/src/components/_components/mini-cart/components/cart-item.tsx +5 -2
  62. package/src/components/_components/mini-cart/components/empty-view.tsx +2 -2
  63. package/src/components/_components/mini-cart/components/top-header.tsx +5 -2
  64. package/src/components/_components/mini-cart/mini-cart.tsx +3 -3
  65. package/src/components/_components/mobile-navigation/mobile-navigation-bar.tsx +5 -5
  66. package/src/components/_components/nav-link/nav-link-2.tsx +1 -1
  67. package/src/components/_components/nav-link/nav-link-3.tsx +1 -1
  68. package/src/components/_components/navbar/categories.tsx +3 -3
  69. package/src/components/_components/navbar/category-based-menu/category-based-menu.tsx +1 -1
  70. package/src/components/_components/navbar/category-based-menu/components/child-categories.tsx +2 -2
  71. package/src/components/_components/navbar/mega-menu/category-list.tsx +1 -1
  72. package/src/components/_components/navbar/mega-menu/mega-menu.tsx +1 -1
  73. package/src/components/_components/navbar/mobile-menu/mobile-menu.tsx +2 -2
  74. package/src/components/_components/navbar/mobile-menu/render-levels.tsx +3 -3
  75. package/src/components/_components/navbar/nav-list/nav-item-child.tsx +3 -3
  76. package/src/components/_components/navbar/nav-list/nav-list.tsx +4 -4
  77. package/src/components/_components/newsletter/newsletter.tsx +5 -1
  78. package/src/components/_components/newsletter/social-icons.tsx +1 -1
  79. package/src/components/_components/page-sidenav/grocery-side-nav/components/link-item.tsx +2 -2
  80. package/src/components/_components/page-sidenav/grocery-side-nav/components/list-item.tsx +2 -2
  81. package/src/components/_components/page-sidenav/grocery-side-nav/components/nav-accordion.tsx +2 -2
  82. package/src/components/_components/page-sidenav/grocery-side-nav/grocery-side-nav.tsx +3 -3
  83. package/src/components/_components/page-sidenav/health-beauty-side-nav/components/list-item.tsx +2 -2
  84. package/src/components/_components/page-sidenav/health-beauty-side-nav/components/nav-accordion.tsx +2 -2
  85. package/src/components/_components/page-sidenav/health-beauty-side-nav/components/render-child.tsx +2 -2
  86. package/src/components/_components/page-sidenav/health-beauty-side-nav/health-beauty-side-nav.tsx +5 -5
  87. package/src/components/_components/page-sidenav/side-navbar/components/list-item.tsx +1 -1
  88. package/src/components/_components/page-sidenav/side-navbar/components/nav-accordion.tsx +3 -3
  89. package/src/components/_components/page-sidenav/side-navbar/components/render-child.tsx +1 -1
  90. package/src/components/_components/page-sidenav/side-navbar/side-nav-bar.tsx +4 -4
  91. package/src/components/_components/page-sidenav/side-navbar-2/components/sidebar-accordion.tsx +1 -1
  92. package/src/components/_components/page-sidenav/side-navbar-2/side-navbar-2.tsx +2 -2
  93. package/src/components/_components/product-cards/product-card-1/components/quantity-buttons.tsx +2 -2
  94. package/src/components/_components/product-cards/product-card-1/product-card.tsx +2 -2
  95. package/src/components/_components/product-cards/product-card-10/product-card.tsx +9 -5
  96. package/src/components/_components/product-cards/product-card-11/product-card.tsx +6 -3
  97. package/src/components/_components/product-cards/product-card-12/product-card.tsx +4 -4
  98. package/src/components/_components/product-cards/product-card-13/product-card.tsx +6 -3
  99. package/src/components/_components/product-cards/product-card-14/product-card.tsx +7 -4
  100. package/src/components/_components/product-cards/product-card-15/product-card.tsx +6 -3
  101. package/src/components/_components/product-cards/product-card-16/components/quantity-buttons.tsx +2 -2
  102. package/src/components/_components/product-cards/product-card-16/product-card.tsx +5 -2
  103. package/src/components/_components/product-cards/product-card-2/components/product-price.tsx +2 -2
  104. package/src/components/_components/product-cards/product-card-2/product-card.tsx +4 -4
  105. package/src/components/_components/product-cards/product-card-3/components/hover-actions.tsx +1 -1
  106. package/src/components/_components/product-cards/product-card-3/product-card.tsx +2 -2
  107. package/src/components/_components/product-cards/product-card-4/components/hover-actions.tsx +1 -1
  108. package/src/components/_components/product-cards/product-card-4/product-card.tsx +2 -2
  109. package/src/components/_components/product-cards/product-card-5/components/hover-actions.tsx +1 -1
  110. package/src/components/_components/product-cards/product-card-5/product-card.tsx +2 -2
  111. package/src/components/_components/product-cards/product-card-6/components/hover-actions.tsx +1 -1
  112. package/src/components/_components/product-cards/product-card-6/product-card.tsx +3 -3
  113. package/src/components/_components/product-cards/product-card-7/components/quantity-buttons.tsx +2 -2
  114. package/src/components/_components/product-cards/product-card-7/product-card.tsx +5 -2
  115. package/src/components/_components/product-cards/product-card-8/product-card.tsx +9 -5
  116. package/src/components/_components/product-cards/product-card-9/components/add-to-cart.tsx +5 -2
  117. package/src/components/_components/product-cards/product-card-9/product-card.tsx +1 -1
  118. package/src/components/_components/product-cards/product-price.tsx +2 -2
  119. package/src/components/_components/product-cards/product-rating.tsx +2 -2
  120. package/src/components/_components/product-cards/product-title.tsx +1 -1
  121. package/src/components/_components/product-cards/use-product.ts +1 -1
  122. package/src/components/_components/product-dimensions/product-dimensions.tsx +1 -1
  123. package/src/components/_components/product-quantity-buttons/product-quantity-buttons.tsx +2 -2
  124. package/src/components/_components/products-view/products-grid-view.tsx +2 -2
  125. package/src/components/_components/products-view/products-list-view.tsx +2 -2
  126. package/src/components/_components/search-box/components/category-dropdown.tsx +1 -1
  127. package/src/components/_components/search-box/components/search-result.tsx +1 -1
  128. package/src/components/_components/search-box/hooks/use-search.ts +1 -1
  129. package/src/components/_components/search-box/search-input-category.tsx +3 -3
  130. package/src/components/_components/service-cards/service-card-1/service-card-1.tsx +5 -2
  131. package/src/components/_components/service-cards/service-card-2/service-card-2.tsx +5 -2
  132. package/src/components/_components/service-cards/service-card-3/service-card-3.tsx +4 -1
  133. package/src/components/_components/settings/setting.tsx +3 -3
  134. package/src/components/_components/side-nav/side-nav.tsx +1 -1
  135. package/src/components/_components/stories/story-content/story-content.tsx +1 -1
  136. package/src/components/_components/stories/story-item/story-item.tsx +1 -1
  137. package/src/components/_components/topbar/top-bar.tsx +6 -3
  138. package/src/components/_components/wishlist-modal/wishlist-modal-item.tsx +1 -1
  139. package/src/components-v2/accordion/accordion-header.stories.tsx +28 -0
  140. package/src/components-v2/categories/category-list/category-list.tsx +2 -2
  141. package/src/components-v2/categories/category-list/styles.ts +3 -2
  142. package/src/components-v2/categories/mega-menu/column-list.tsx +1 -1
  143. package/src/components-v2/categories/mega-menu/mega-menu-1.tsx +6 -3
  144. package/src/components-v2/categories/mega-menu/mega-menu-2.tsx +2 -2
  145. package/src/components-v2/header/__tests__/user.test.tsx +12 -12
  146. package/src/components-v2/header/components/user.tsx +12 -11
  147. package/src/components-v2/mini-cart/mini-cart.tsx +9 -14
  148. package/src/components-v2/mobile-navigation/mobile-navigation-bar.tsx +1 -1
  149. package/src/components-v2/navbar/mobile-menu/mobile-menu.tsx +2 -2
  150. package/src/components-v2/product-cards/favorite-button.tsx +52 -0
  151. package/src/components-v2/product-cards/product-card/product-card.tsx +87 -47
  152. package/src/components-v2/product-cards/product-card-plp/product-card.tsx +140 -51
  153. package/src/components-v2/product-cards/product-card-plp/styles/index.ts +17 -0
  154. package/src/components-v2/product-cards/product-card-plp-list/product-card.tsx +76 -42
  155. package/src/components-v2/product-cards/product-card-search/product-card.tsx +50 -21
  156. package/src/components-v2/product-cards/product-card-search/styles/index.ts +0 -10
  157. package/src/components-v2/product-dialog/compound/product-dialog.tsx +39 -15
  158. package/src/components-v2/product-quantity-buttons/compound/quantity-buttons-root.tsx +22 -7
  159. package/src/components-v2/product-quantity-variants/index.tsx +1 -1
  160. package/src/components-v2/products-view/compound/context.ts +46 -1
  161. package/src/components-v2/products-view/compound/products-grid-view.tsx +23 -14
  162. package/src/components-v2/products-view/compound/products-list-view.tsx +12 -3
  163. package/src/components-v2/search-bar/compound/context.ts +24 -3
  164. package/src/components-v2/search-bar/compound/results-item-lg.tsx +14 -13
  165. package/src/components-v2/search-bar/compound/results-item-sm.tsx +5 -5
  166. package/src/components-v2/search-bar/compound/results-suspense.tsx +3 -3
  167. package/src/components-v2/search-bar/compound/results.tsx +4 -4
  168. package/src/components-v2/search-bar/compound/textfield-adornment-category.tsx +1 -1
  169. package/src/components-v2/search-bar/compound/textfield.tsx +3 -3
  170. package/src/components-v2/search-bar/hooks/use-click-outside.ts +1 -1
  171. package/src/components-v2/wishlist-dialogs/add-to-wishlist/add-to-wishlist-button.tsx +2 -6
  172. package/src/components-v2/wishlist-dialogs/add-to-wishlist/compound/add-to-wishlist-bottom-ui.tsx +6 -1
  173. package/src/components-v2/wishlist-dialogs/add-to-wishlist/compound/add-to-wishlist-dialog.tsx +22 -15
  174. package/src/components-v2/wishlist-dialogs/add-to-wishlist/compound/add-to-wishlist-list.tsx +8 -7
  175. package/src/components-v2/wishlist-dialogs/add-to-wishlist/compound/context.ts +8 -8
  176. package/src/components-v2/wishlist-dialogs/add-to-wishlist/compound/wishlist-dialog-item.tsx +29 -19
  177. package/src/components-v2/wishlist-dialogs/add-to-wishlist/hooks/use-add-to-wishlist.ts +27 -77
  178. package/src/components-v2/wishlist-dialogs/add-to-wishlist/index.tsx +1 -9
  179. package/src/components-v2/wishlist-dialogs/create-wishlist/compound/create-wishlist-bottom-ui.tsx +7 -2
  180. package/src/components-v2/wishlist-dialogs/create-wishlist/compound/create-wishlist-dialog.tsx +20 -12
  181. package/src/components-v2/wishlist-dialogs/create-wishlist/compound/create-wishlist-form.tsx +25 -5
  182. package/src/hooks/use-cart.ts +11 -14
  183. package/src/hooks/use-favorite.ts +17 -0
  184. package/src/hooks/use-variants.ts +4 -3
  185. package/src/pages/account/addresses/address-item.tsx +1 -1
  186. package/src/pages/account/dashboard-header.tsx +3 -3
  187. package/src/pages/account/navigation.tsx +5 -2
  188. package/src/pages/account/no-records.tsx +1 -1
  189. package/src/pages/account/orders/order-progress.tsx +5 -2
  190. package/src/pages/account/orders/order-row.tsx +4 -1
  191. package/src/pages/account/orders/order-summary.tsx +6 -2
  192. package/src/pages/account/orders/ordered-products.tsx +9 -2
  193. package/src/pages/account/profile/user-info.tsx +5 -2
  194. package/src/pages/account/wishlist/create-new-list.tsx +1 -1
  195. package/src/pages/account/wishlist/wishlist-item.tsx +2 -2
  196. package/src/pages/checkout/checkout-alt-form/address-card.tsx +5 -2
  197. package/src/pages/checkout/checkout-alt-form/checkout-step.tsx +3 -3
  198. package/src/pages/checkout/checkout-alt-form/customer-information.tsx +1 -1
  199. package/src/pages/checkout/checkout-alt-form/delivery-address.tsx +5 -1
  200. package/src/pages/checkout/checkout-alt-form/delivery-options.tsx +6 -2
  201. package/src/pages/checkout/checkout-alt-form/edit-address-form.tsx +1 -1
  202. package/src/pages/checkout/checkout-alt-form/heading.tsx +2 -2
  203. package/src/pages/checkout/checkout-alt-form/new-address-form.tsx +9 -4
  204. package/src/pages/checkout/checkout-alt-form/payment-details.tsx +6 -3
  205. package/src/pages/checkout/checkout-alt-summary/cart-item.tsx +5 -2
  206. package/src/pages/checkout/checkout-alt-summary/checkout-alt-summary.tsx +4 -2
  207. package/src/pages/checkout/checkout-alt-summary/list-item.tsx +2 -2
  208. package/src/pages/confirmation/address.tsx +4 -1
  209. package/src/pages/confirmation/confirmation-summary.tsx +6 -3
  210. package/src/pages/confirmation/ordered-products.tsx +9 -2
  211. package/src/pages/product-details/available-shops.tsx +5 -2
  212. package/src/pages/product-details/bopis/find-in-store-modal.tsx +1 -1
  213. package/src/pages/product-details/bopis/pickup-option-select.tsx +1 -1
  214. package/src/pages/product-details/frequently-bought.tsx +9 -2
  215. package/src/pages/product-details/frequently-product-card.tsx +8 -5
  216. package/src/pages/product-details/product-comment.tsx +7 -2
  217. package/src/pages/product-details/product-description.tsx +1 -1
  218. package/src/pages/product-details/product-filter-card.tsx +11 -3
  219. package/src/pages/product-details/product-intro/product-intro-images.tsx +4 -1
  220. package/src/pages/product-details/product-intro/product-intro.tsx +8 -5
  221. package/src/pages/product-details/product-review.tsx +5 -2
  222. package/src/pages/product-details/related-products.tsx +2 -2
  223. package/src/pages/product-list/facet-group.tsx +1 -1
  224. package/src/pages/product-list/list-filter.tsx +5 -2
  225. package/src/pages/product-list/pagination.tsx +1 -1
  226. package/src/pages/product-list/quick-view-dialog-content.tsx +2 -2
  227. package/src/pages/product-list/selected-facets.tsx +1 -1
  228. package/src/pages/quickorder/order-upload.tsx +1 -1
  229. package/src/pages/quickorder/quick-order-form.tsx +6 -3
  230. package/src/pages/quickorder/quick-order-row.tsx +1 -1
  231. package/src/pages-v2/account/account-navigation.tsx +1 -1
  232. package/src/pages-v2/account/orders/order-summary.tsx +5 -2
  233. package/src/pages-v2/account/profile/user-info.tsx +6 -3
  234. package/src/pages-v2/account/wishlist/wishlist-item.tsx +1 -1
  235. package/src/pages-v2/cart/__tests__/checkout-form.test.tsx +1 -1
  236. package/src/pages-v2/cart/estimate-shipping.tsx +3 -0
  237. package/src/pages-v2/checkout/checkout-alt-form/checkout-step.tsx +4 -4
  238. package/src/pages-v2/checkout/checkout-alt-form/steps/address/address-card.tsx +1 -1
  239. package/src/pages-v2/checkout/checkout-alt-form/steps/address/delivery-address.tsx +12 -5
  240. package/src/pages-v2/checkout/checkout-alt-form/steps/address/new-address-form.tsx +27 -5
  241. package/src/pages-v2/checkout/checkout-alt-form/steps/address/styles.ts +2 -1
  242. package/src/pages-v2/checkout/checkout-alt-form/steps/customer-info/customer-information.tsx +27 -7
  243. package/src/pages-v2/checkout/checkout-alt-form/steps/shipping/delivery-options.tsx +8 -1
  244. package/src/pages-v2/confirmation/address.tsx +5 -1
  245. package/src/pages-v2/product-details/available-shops.tsx +4 -1
  246. package/src/pages-v2/product-details/bopis/find-in-store-button.tsx +1 -1
  247. package/src/pages-v2/product-details/bopis/find-in-store-modal.tsx +3 -5
  248. package/src/pages-v2/product-details/product-intro/compound/context.ts +69 -12
  249. package/src/pages-v2/product-details/product-intro/compound/product-info.tsx +73 -27
  250. package/src/pages-v2/product-details/product-intro/compound/product-intro-images.tsx +19 -6
  251. package/src/pages-v2/product-details/product-intro/utils.ts +2 -2
  252. package/src/pages-v2/product-details/product-tabs.tsx +19 -4
  253. package/src/pages-v2/product-details/related-products.tsx +3 -3
  254. package/src/pages-v2/quickorder/context.ts +2 -2
  255. package/src/pages-v2/quickorder/order-upload.tsx +6 -2
  256. package/src/pages-v2/quickorder/provider.tsx +24 -9
  257. package/src/pages-v2/quickorder/quick-order-header.tsx +4 -1
  258. package/src/pages-v2/quickorder/quick-order-row.tsx +1 -1
  259. package/src/pages-v2/quickorder/quick-order-table.tsx +9 -3
  260. package/src/stories/Button.stories.ts +54 -0
  261. package/src/stories/Button.tsx +35 -0
  262. package/src/stories/Configure.mdx +364 -0
  263. package/src/stories/Header.stories.ts +34 -0
  264. package/src/stories/Header.tsx +54 -0
  265. package/src/stories/Page.stories.ts +33 -0
  266. package/src/stories/Page.tsx +73 -0
  267. package/src/stories/assets/accessibility.png +0 -0
  268. package/src/stories/assets/accessibility.svg +1 -0
  269. package/src/stories/assets/addon-library.png +0 -0
  270. package/src/stories/assets/assets.png +0 -0
  271. package/src/stories/assets/avif-test-image.avif +0 -0
  272. package/src/stories/assets/context.png +0 -0
  273. package/src/stories/assets/discord.svg +1 -0
  274. package/src/stories/assets/docs.png +0 -0
  275. package/src/stories/assets/figma-plugin.png +0 -0
  276. package/src/stories/assets/github.svg +1 -0
  277. package/src/stories/assets/share.png +0 -0
  278. package/src/stories/assets/styling.png +0 -0
  279. package/src/stories/assets/testing.png +0 -0
  280. package/src/stories/assets/theming.png +0 -0
  281. package/src/stories/assets/tutorials.svg +1 -0
  282. package/src/stories/assets/youtube.svg +1 -0
  283. package/src/stories/button.css +30 -0
  284. package/src/stories/header.css +32 -0
  285. package/src/stories/page.css +68 -0
  286. package/src/theme/build-mui-theme.ts +104 -0
  287. package/src/theme/components.ts +163 -0
  288. package/src/theme/emotion-cache.tsx +101 -0
  289. package/src/theme/theme-colors.ts +205 -0
  290. package/src/theme/theme-options-sample.ts +69 -0
  291. package/src/theme/theme-options.ts +172 -0
  292. package/src/theme/theme-provider.tsx +44 -0
  293. package/src/theme/typography.ts +22 -0
  294. package/src/theme/utils.ts +17 -0
  295. package/tsconfig.json +3 -1
  296. package/src/api-manager/lib/cart-cookie-handler.ts +0 -14
  297. package/src/components-v2/product-cards/product-card/components/hover-actions.tsx +0 -37
  298. package/src/components-v2/product-cards/product-card-plp/components/quantity-buttons.tsx +0 -54
  299. package/src/components-v2/product-cards/product-card-plp-list/components/add-to-cart.tsx +0 -63
  300. package/src/components-v2/product-cards/product-card-plp-list/components/favorite-button.tsx +0 -27
  301. package/src/components-v2/product-cards/use-product.ts +0 -35
  302. package/src/components-v2/products-view/products-grid-view.tsx +0 -65
  303. package/src/components-v2/products-view/products-list-view.tsx +0 -66
  304. package/src/components-v2/wishlist-dialogs/create-wishlist/compound/context.ts +0 -2
  305. /package/src/components-v2/product-cards/{product-card/components/quantity-buttons.tsx → quantity-buttons.tsx} +0 -0
@@ -1,21 +1,25 @@
1
- import { createContext, useContext, ReactNode } from "react";
1
+ import { createContext, useContext, ReactNode, useState } from "react";
2
2
  import Link from "next/link";
3
3
  import Card from "@mui/material/Card";
4
4
  import Rating from "@mui/material/Rating";
5
5
  import styled from "@mui/material/styles/styled";
6
+ import IconButton from "@mui/material/IconButton";
7
+ import RemoveRedEye from "@mui/icons-material/RemoveRedEye";
6
8
  // GLOBAL CUSTOM COMPONENTS
7
9
  import { H5 } from "@evenicanpm/storefront-core/src/components-v2/Typography";
8
10
  import ImageWithFallback from "@evenicanpm/storefront-core/src/components-v2/ImageWithFallback";
9
- // LOCAL CUSTOM HOOK
10
- import useProduct from "@evenicanpm/storefront-core/src/components-v2/product-cards/use-product";
11
+ import AddToWishlistDialog from "@evenicanpm/storefront-core/src/components-v2/wishlist-dialogs/add-to-wishlist";
12
+ import ProductViewDialog from "@evenicanpm/storefront-core/src/components-v2/product-dialog";
11
13
  // LOCAL CUSTOM COMPONENTS
12
14
  import DiscountChip from "@evenicanpm/storefront-core/src/components-v2/product-cards/discount-chip";
13
15
  import ProductPrice from "@evenicanpm/storefront-core/src/components-v2/product-cards/product-price";
14
- import AddToCartButton from "@evenicanpm/storefront-core/src/components-v2/product-cards/product-card-plp-list/components/add-to-cart";
15
- import FavoriteButton from "@evenicanpm/storefront-core/src/components-v2/product-cards/product-card-plp-list/components/favorite-button";
16
+ import QuantityButtons from "@evenicanpm/storefront-core/src/components-v2/product-cards/quantity-buttons";
17
+ import FavoriteButton from "@evenicanpm/storefront-core/src/components-v2/product-cards/favorite-button";
16
18
  import ProductTags from "@evenicanpm/storefront-core/src/components-v2/product-cards/product-card-plp-list/components/tags";
17
-
19
+ // LIBRARY AND HOOKS
18
20
  import buildDetailUrl from "@/lib/build-detail-url";
21
+ import useCart from "@/hooks/use-cart";
22
+ import useFavorite from "@/hooks/use-favorite";
19
23
 
20
24
  // STYLED COMPONENT
21
25
  const Wrapper = styled(Card)({
@@ -65,9 +69,11 @@ type Product = {
65
69
  tags?: Array<string>;
66
70
  };
67
71
 
68
- const ProductCardPlpListContext = createContext<{ product: Product } | null>(
69
- null,
70
- );
72
+ const ProductCardPlpListContext = createContext<{
73
+ product: Product;
74
+ setOpenAddToWishlistDialog: (open: boolean) => void;
75
+ setOpenProductModal: (open: boolean) => void;
76
+ } | null>(null);
71
77
 
72
78
  type ProductCardPlpListProps = {
73
79
  product: Product;
@@ -75,23 +81,44 @@ type ProductCardPlpListProps = {
75
81
  };
76
82
 
77
83
  const ProductCardPlpList = ({ product, children }: ProductCardPlpListProps) => {
84
+ const [openAddToWishlistDialog, setOpenAddToWishlistDialog] = useState(false);
85
+ const [openProductModal, setOpenProductModal] = useState(false);
78
86
  return (
79
- <ProductCardPlpListContext.Provider value={{ product }}>
87
+ <ProductCardPlpListContext.Provider
88
+ value={{ product, setOpenAddToWishlistDialog, setOpenProductModal }}
89
+ >
80
90
  <Wrapper>{children}</Wrapper>
91
+ {openProductModal && (
92
+ <ProductViewDialog
93
+ openDialog={openProductModal}
94
+ handleCloseDialog={() => setOpenProductModal(false)}
95
+ productId={Number(product.id)}
96
+ />
97
+ )}
98
+ {openAddToWishlistDialog && (
99
+ <AddToWishlistDialog
100
+ open={openAddToWishlistDialog}
101
+ handleClose={() => setOpenAddToWishlistDialog(false)}
102
+ productId={Number(product.id)}
103
+ />
104
+ )}
81
105
  </ProductCardPlpListContext.Provider>
82
106
  );
83
107
  };
84
108
 
85
- ProductCardPlpList.FavoriteButton = () => {
109
+ ProductCardPlpList.QuickViewButton = () => {
86
110
  const ctx = useContext(ProductCardPlpListContext);
87
111
  if (!ctx) return null;
88
112
 
89
- const { slug } = ctx.product;
90
-
91
- const { isFavorite, toggleFavorite } = useProduct(slug);
92
-
93
113
  return (
94
- <FavoriteButton isFavorite={isFavorite} toggleFavorite={toggleFavorite} />
114
+ <IconButton
115
+ sx={{ position: "absolute", top: 10, right: 15, zIndex: 1 }}
116
+ onClick={() => {
117
+ ctx.setOpenProductModal(true);
118
+ }}
119
+ >
120
+ <RemoveRedEye color="disabled" fontSize="small" />
121
+ </IconButton>
95
122
  );
96
123
  };
97
124
 
@@ -172,45 +199,52 @@ ProductCardPlpList.Price = () => {
172
199
  return <ProductPrice price={price} discount={discount ?? 0} />;
173
200
  };
174
201
 
175
- ProductCardPlpList.QuantityButtons = () => {
202
+ ProductCardPlpList.FavoriteButton = () => {
176
203
  const ctx = useContext(ProductCardPlpListContext);
177
204
  if (!ctx) return null;
178
205
 
179
- const { slug, id, price, imgUrl, title } = ctx.product;
206
+ const { id } = ctx.product;
207
+ const isFavorite = useFavorite(id);
208
+
209
+ return (
210
+ <FavoriteButton
211
+ isFavorite={isFavorite}
212
+ onToggle={() => ctx.setOpenAddToWishlistDialog(true)}
213
+ size="small"
214
+ sx={{ position: "absolute", bottom: 10, right: 15, zIndex: 1 }}
215
+ />
216
+ );
217
+ };
218
+
219
+ // Using quantity buttons (addtocart) doesn't make sense when we have product variants to select.
220
+ // So hide them for now, implement based on client requirements.
221
+ ProductCardPlpList.QuantityButtons = () => {
222
+ const ctx = useContext(ProductCardPlpListContext);
223
+ if (!ctx) return null;
180
224
 
181
- const { cartItem, handleCartAmountChange } = useProduct(slug);
225
+ const { id } = ctx.product;
226
+ const { currentCartLine, handleCartAmountChange, loading } = useCart(id);
227
+ const [quantity, setQuantity] = useState(currentCartLine?.Quantity || 0);
182
228
 
183
229
  const handleIncrementQuantity = () => {
184
- const product = {
185
- id,
186
- slug,
187
- price,
188
- imgUrl,
189
- name: title,
190
- qty: (cartItem?.Quantity || 0) + 1,
191
- };
192
- product;
193
- handleCartAmountChange();
230
+ const qty = quantity + 1;
231
+ handleCartAmountChange(qty);
232
+ setQuantity(qty);
194
233
  };
195
234
 
196
235
  const handleDecrementQuantity = () => {
197
- const product = {
198
- id,
199
- slug,
200
- price,
201
- imgUrl,
202
- name: title,
203
- qty: (cartItem?.Quantity || 0) - 1,
204
- };
205
- product;
206
- handleCartAmountChange("remove");
236
+ if (quantity <= 0) return;
237
+ const qty = quantity - 1;
238
+ handleCartAmountChange(qty);
239
+ setQuantity(qty);
207
240
  };
208
241
 
209
242
  return (
210
- <AddToCartButton
211
- quantity={cartItem?.Quantity ?? 0}
212
- handleDecrement={handleDecrementQuantity}
243
+ <QuantityButtons
244
+ quantity={quantity}
213
245
  handleIncrement={handleIncrementQuantity}
246
+ handleDecrement={handleDecrementQuantity}
247
+ isLineUpdating={loading}
214
248
  />
215
249
  );
216
250
  };
@@ -1,15 +1,11 @@
1
1
  "use client";
2
2
 
3
- import { createContext, useContext, ReactNode } from "react";
3
+ import { createContext, useContext, ReactNode, useState } from "react";
4
4
  import Link from "next/link";
5
5
  import Box from "@mui/material/Box";
6
6
  import Rating from "@mui/material/Rating";
7
7
  // MUI ICON COMPONENTS
8
8
  import { RemoveRedEye } from "@mui/icons-material";
9
- import Favorite from "@mui/icons-material/Favorite";
10
- import FavoriteBorder from "@mui/icons-material/FavoriteBorder";
11
- // LOCAL CUSTOM HOOK
12
- import useProduct from "@evenicanpm/storefront-core/src/components-v2/product-cards/use-product";
13
9
  // GLOBAL CUSTOM COMPONENTS
14
10
  import LazyImage from "@evenicanpm/storefront-core/src/components-v2/LazyImage";
15
11
  import { FlexRowCenter } from "@evenicanpm/storefront-core/src/components-v2/flex-box";
@@ -18,14 +14,17 @@ import {
18
14
  Paragraph,
19
15
  Small,
20
16
  } from "@evenicanpm/storefront-core/src/components-v2/Typography";
21
- // UTILS LIBRARY FUNCTION
17
+ import ProductViewDialog from "@evenicanpm/storefront-core/src/components-v2/product-dialog";
18
+ import AddToWishlistDialog from "@evenicanpm/storefront-core/src/components-v2/wishlist-dialogs/add-to-wishlist";
19
+ import FavoriteButton from "@evenicanpm/storefront-core/src/components-v2/product-cards/favorite-button";
20
+ // LIBRARY AND HOOKS
22
21
  import buildDetailUrl from "@/lib/build-detail-url";
23
22
  import { currency } from "@/lib/lib";
23
+ import useFavorite from "@/hooks/use-favorite";
24
24
  // STYLED COMPONENTS
25
25
  import {
26
26
  Card,
27
27
  CardMedia,
28
- FavoriteButton,
29
28
  QuickViewSmallButton,
30
29
  } from "@evenicanpm/storefront-core/src/components-v2/product-cards/product-card-search/styles/index";
31
30
 
@@ -47,12 +46,35 @@ type ProductCardSearchProps = {
47
46
 
48
47
  const ProductCardSearchContext = createContext<{
49
48
  product: Product;
49
+ handleToggleProductModal: () => void;
50
+ setOpenAddToWishlistDialog: (open: boolean) => void;
50
51
  } | null>(null);
51
52
 
52
53
  const ProductCardSearch = ({ product, children }: ProductCardSearchProps) => {
54
+ const [openProductModal, setOpenProductModal] = useState(false);
55
+ const [openAddToWishlistDialog, setOpenAddToWishlistDialog] = useState(false);
56
+ const handleToggleProductModal = () => {
57
+ setOpenProductModal((prev) => !prev);
58
+ };
53
59
  return (
54
- <ProductCardSearchContext.Provider value={{ product }}>
60
+ <ProductCardSearchContext.Provider
61
+ value={{ product, handleToggleProductModal, setOpenAddToWishlistDialog }}
62
+ >
55
63
  <Card>{children}</Card>
64
+ {openProductModal && (
65
+ <ProductViewDialog
66
+ openDialog={openProductModal}
67
+ handleCloseDialog={handleToggleProductModal}
68
+ productId={Number(product.id)}
69
+ />
70
+ )}
71
+ {openAddToWishlistDialog && (
72
+ <AddToWishlistDialog
73
+ open={openAddToWishlistDialog}
74
+ handleClose={() => setOpenAddToWishlistDialog(false)}
75
+ productId={Number(product.id)}
76
+ />
77
+ )}
56
78
  </ProductCardSearchContext.Provider>
57
79
  );
58
80
  };
@@ -136,30 +158,37 @@ ProductCardSearch.Rating = () => {
136
158
  ProductCardSearch.QuickViewButton = () => {
137
159
  const ctx = useContext(ProductCardSearchContext);
138
160
  if (!ctx) return null;
139
- const { product } = ctx;
140
- const { id, title, thumbnail, price, slug } = product;
141
161
 
142
162
  return (
143
- <QuickViewSmallButton className="product-actions">
163
+ <QuickViewSmallButton
164
+ className="product-actions"
165
+ onClick={ctx.handleToggleProductModal}
166
+ >
144
167
  <RemoveRedEye className="icon" fontSize="small" />
145
168
  </QuickViewSmallButton>
146
169
  );
147
170
  };
148
171
 
149
- ProductCardSearch.WishlistButton = () => {
172
+ ProductCardSearch.FavoriteButton = () => {
150
173
  const ctx = useContext(ProductCardSearchContext);
151
174
  if (!ctx) return null;
152
- const { product } = ctx;
153
- const { isFavorite } = useProduct(product?.slug);
175
+ const { id } = ctx.product;
176
+ const isFavorite = useFavorite(Number(id));
154
177
 
155
178
  return (
156
- <FavoriteButton className="product-actions" onClick={() => {}}>
157
- {isFavorite ? (
158
- <Favorite className="icon" fontSize="small" color="primary" />
159
- ) : (
160
- <FavoriteBorder className="icon" fontSize="small" />
161
- )}
162
- </FavoriteButton>
179
+ <FavoriteButton
180
+ className="product-actions"
181
+ isFavorite={isFavorite}
182
+ onToggle={() => ctx.setOpenAddToWishlistDialog(true)}
183
+ sx={{
184
+ top: 55,
185
+ right: -40,
186
+ position: "absolute",
187
+ backgroundColor: "white",
188
+ transition: "right 0.3s .2s",
189
+ }}
190
+ customIconSize={16}
191
+ />
163
192
  );
164
193
  };
165
194
 
@@ -31,16 +31,6 @@ export const AddToCartButton = styled(IconButton)(({ theme }) => ({
31
31
  ".icon": { fontSize: 16 },
32
32
  }));
33
33
 
34
- export const FavoriteButton = styled(IconButton)(({ theme }) => ({
35
- top: 55,
36
- right: -40,
37
- position: "absolute",
38
- backgroundColor: "white",
39
- transition: "right 0.3s .2s",
40
- color: theme.palette.text.primary,
41
- ".icon": { fontSize: 16 },
42
- }));
43
-
44
34
  export const QuickViewButton = styled(Button)({
45
35
  left: 0,
46
36
  bottom: 12,
@@ -50,7 +50,26 @@ interface ProductDialogContext {
50
50
  /**
51
51
  * @internal
52
52
  */
53
- export const ProductDialogContext = createContext(null);
53
+ export const ProductDialogContext = createContext<ProductDialogContext | null>(
54
+ null,
55
+ );
56
+
57
+ /**
58
+ * Hook to safely access ProductDialogContext
59
+ * @throws When used outside of ProductDialogProvider
60
+ * @returns The product dialog context value
61
+ */
62
+ export const useProductDialog = () => {
63
+ const context = useContext(ProductDialogContext);
64
+
65
+ if (context === null) {
66
+ throw new Error(
67
+ "useProductDialog must be used within a ProductDialogProvider",
68
+ );
69
+ }
70
+
71
+ return context;
72
+ };
54
73
 
55
74
  /**
56
75
  * @category Compound Component
@@ -70,10 +89,10 @@ export const ProductDialogContext = createContext(null);
70
89
  */
71
90
  export default function ProductDialog(props: Props) {
72
91
  const { children, openDialog, handleCloseDialog } = props;
73
- const { data: product, isPending } = getProductById.useData({
92
+ const { data: product } = getProductById.useSuspenseData({
74
93
  id: Number(props.productId),
75
94
  });
76
- if (isPending) return null;
95
+ if (!product) return null;
77
96
  return (
78
97
  <ProductDialogContext.Provider
79
98
  value={{ product, openDialog, handleCloseDialog }}
@@ -84,9 +103,7 @@ export default function ProductDialog(props: Props) {
84
103
  onClose={handleCloseDialog}
85
104
  sx={{ zIndex: 1501 }}
86
105
  >
87
- <DialogContent sx={{ maxWidth: 900, width: "100%" }}>
88
- {children}
89
- </DialogContent>
106
+ {children}
90
107
  </Dialog>
91
108
  </ProductDialogContext.Provider>
92
109
  );
@@ -100,10 +117,13 @@ export const ProductDialogContent = ({
100
117
  }: {
101
118
  children: React.ReactNode;
102
119
  }) => {
103
- const { handleCloseDialog } = useContext(ProductDialogContext);
120
+ const { handleCloseDialog } = useProductDialog();
104
121
 
105
122
  return (
106
- <DialogContent sx={{ maxWidth: 900, width: "100%" }}>
123
+ <DialogContent
124
+ sx={{ maxWidth: 900, width: "100%" }}
125
+ onClick={(e) => e.stopPropagation()}
126
+ >
107
127
  <div>
108
128
  <Grid container spacing={3}>
109
129
  {children}
@@ -111,7 +131,10 @@ export const ProductDialogContent = ({
111
131
  </div>
112
132
  <IconButton
113
133
  sx={{ position: "absolute", top: 3, right: 3 }}
114
- onClick={handleCloseDialog}
134
+ onClick={(e) => {
135
+ e.stopPropagation();
136
+ handleCloseDialog?.();
137
+ }}
115
138
  >
116
139
  <Close fontSize="small" color="secondary" />
117
140
  </IconButton>
@@ -123,19 +146,20 @@ export const ProductDialogContent = ({
123
146
  * @category Sub-Component
124
147
  */
125
148
  export const ProductDialogContentImages = () => {
126
- const { product } = useContext(ProductDialogContext);
149
+ const { product } = useProductDialog();
127
150
 
128
151
  return (
129
152
  <Grid size={{ md: 6, xs: 12 }}>
130
153
  <Carousel
131
154
  slidesToShow={1}
155
+ infinite={false}
132
156
  arrowStyles={{
133
157
  boxShadow: 0,
134
158
  color: "primary.main",
135
159
  backgroundColor: "transparent",
136
160
  }}
137
161
  >
138
- {product?.Images.map((item: string, index: number) => (
162
+ {product?.Images?.map((item: string, index: number) => (
139
163
  <BazaarImage
140
164
  key={index}
141
165
  src={item}
@@ -172,7 +196,7 @@ export const ProductDialogContentInfo = ({
172
196
  * @category Sub-Component
173
197
  */
174
198
  export const InfoName = () => {
175
- const { product } = useContext(ProductDialogContext);
199
+ const { product } = useProductDialog();
176
200
  return <H2>{product?.Name}</H2>;
177
201
  };
178
202
 
@@ -191,7 +215,7 @@ export const InfoCategory = () => {
191
215
  * @category Sub-Component
192
216
  */
193
217
  export const InfoPrice = () => {
194
- const { product } = useContext(ProductDialogContext);
218
+ const { product } = useProductDialog();
195
219
  return <H1 color="primary.main">{currency(product?.Price)}</H1>;
196
220
  };
197
221
 
@@ -199,7 +223,7 @@ export const InfoPrice = () => {
199
223
  * @category Sub-Component
200
224
  */
201
225
  export const InfoDescription = () => {
202
- const { product } = useContext(ProductDialogContext);
226
+ const { product } = useProductDialog();
203
227
  return <Paragraph my={2}>{product?.Description}</Paragraph>;
204
228
  };
205
229
 
@@ -219,7 +243,7 @@ export const InfoRating = () => {
219
243
  * @category Sub-Component
220
244
  */
221
245
  export const InfoAddToCart = () => {
222
- const { product } = useContext(ProductDialogContext);
246
+ const { product } = useProductDialog();
223
247
  return (
224
248
  <>
225
249
  <Divider sx={{ mb: 2 }} />
@@ -37,12 +37,27 @@ export const QuantityContext = createContext<QuantityContextType | undefined>(
37
37
  undefined,
38
38
  );
39
39
 
40
+ /**
41
+ * Hook to safely access QuantityContext
42
+ * @throws {Error} When used outside of QuantityProvider
43
+ * @returns {QuantityContextType} The quantity context value
44
+ */
45
+ export const useQuantity = () => {
46
+ const context = useContext(QuantityContext);
47
+
48
+ if (context === undefined) {
49
+ throw new Error("useQuantity must be used within a QuantityProvider");
50
+ }
51
+
52
+ return context;
53
+ };
54
+
40
55
  /**
41
56
  * @category Props
42
57
  */
43
58
  export interface QuantityButtonProps {
44
59
  /** The cartline that this component will display the quantity of */
45
- productId: number;
60
+ productId: number | undefined;
46
61
  /** Is the item out of stock? */
47
62
  isOOS?: boolean;
48
63
  /** React children */
@@ -90,6 +105,8 @@ export function QuantityButtons({
90
105
  );
91
106
  }
92
107
 
108
+ if (!currentCartLine?.Quantity) return null;
109
+
93
110
  const value: QuantityContextType = {
94
111
  loading,
95
112
  quantity: currentCartLine?.Quantity,
@@ -110,8 +127,7 @@ export function QuantityButtons({
110
127
  * @category Sub-Component
111
128
  */
112
129
  QuantityButtons.Remove = () => {
113
- const { handleCartAmountChange, loading, productCartLine } =
114
- useContext(QuantityContext);
130
+ const { handleCartAmountChange, loading, productCartLine } = useQuantity();
115
131
 
116
132
  return (
117
133
  <Button
@@ -137,8 +153,7 @@ QuantityButtons.Remove = () => {
137
153
  * @category Sub-Component
138
154
  */
139
155
  QuantityButtons.Add = () => {
140
- const { handleCartAmountChange, loading, productCartLine } =
141
- useContext(QuantityContext);
156
+ const { handleCartAmountChange, loading, productCartLine } = useQuantity();
142
157
 
143
158
  return (
144
159
  <Button
@@ -164,7 +179,7 @@ QuantityButtons.Add = () => {
164
179
  * @category Sub-Component
165
180
  */
166
181
  QuantityButtons.Quantity = () => {
167
- const { loading, productCartLine } = useContext(QuantityContext);
182
+ const { loading, productCartLine } = useQuantity();
168
183
  return (
169
184
  <H3
170
185
  fontWeight="600"
@@ -174,7 +189,7 @@ QuantityButtons.Quantity = () => {
174
189
  {loading ? (
175
190
  <CircularProgress size={"10px"} />
176
191
  ) : (
177
- productCartLine?.Quantity.toString().padStart(2, "0")
192
+ productCartLine?.Quantity?.toString().padStart(2, "0")
178
193
  )}
179
194
  </H3>
180
195
  );
@@ -33,7 +33,7 @@ export default function QuantityVariantsSelect({ product }: Props) {
33
33
  allDimensionsSelected,
34
34
  } = useVariants(product);
35
35
 
36
- const { handleAddToCart } = useCart(RecordId, selectedVariant.RecordId);
36
+ const { handleAddToCart } = useCart(selectedVariant?.RecordId);
37
37
 
38
38
  const searchCriteria = {
39
39
  searchCriteria: {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @module ProductsView
3
3
  */
4
- import { createContext } from "react";
4
+ import { createContext, useContext } from "react";
5
5
  // DATA MODEL
6
6
  import { ProductSearchResult as Product } from "@msdyn365-commerce/retail-proxy";
7
7
  import { ProductPrice } from "@/api-manager/schemas/product.schema";
@@ -17,9 +17,54 @@ export interface ProductsViewContext {
17
17
  productPrices?: ProductPrice[];
18
18
  }
19
19
 
20
+ export interface ProductsViewCardContext {
21
+ product: Product;
22
+ price?: ProductPrice;
23
+ }
24
+
20
25
  /**
21
26
  * @internal
22
27
  */
23
28
  export const ProductsViewContext = createContext<null | ProductsViewContext>(
24
29
  null,
25
30
  );
31
+
32
+ /**
33
+ * @internal
34
+ */
35
+ export const ProductsViewCardContext =
36
+ createContext<null | ProductsViewCardContext>(null);
37
+
38
+ /**
39
+ * Hook to safely access ProductsViewContext
40
+ * @throws When used outside of ProductsViewProvider
41
+ * @returns The products view context value
42
+ */
43
+ export const useProductsView = () => {
44
+ const context = useContext(ProductsViewContext);
45
+
46
+ if (context === null) {
47
+ throw new Error(
48
+ "useProductsView must be used within a ProductsViewProvider",
49
+ );
50
+ }
51
+
52
+ return context;
53
+ };
54
+
55
+ /**
56
+ * Hook to safely access ProductsViewCardContext
57
+ * @throws When used outside of ProductsViewCardProvider
58
+ * @returns The product card context value
59
+ */
60
+ export const useProductsViewCard = () => {
61
+ const context = useContext(ProductsViewCardContext);
62
+
63
+ if (context === null) {
64
+ throw new Error(
65
+ "useProductsViewCard must be used within a ProductsViewCardProvider",
66
+ );
67
+ }
68
+
69
+ return context;
70
+ };