@evenicanpm/storefront-core 1.0.0-alpha

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 (475) hide show
  1. package/README.md +40 -0
  2. package/package.json +36 -0
  3. package/src/api-manager/README.md +38 -0
  4. package/src/api-manager/api-manager.config.json +12 -0
  5. package/src/api-manager/datasources/README.md +17 -0
  6. package/src/api-manager/datasources/d365/d365-address.datasource.ts +141 -0
  7. package/src/api-manager/datasources/d365/d365-base.datasource.ts +8 -0
  8. package/src/api-manager/datasources/d365/d365-cart.datasource.ts +374 -0
  9. package/src/api-manager/datasources/d365/d365-categories.datasource.ts +40 -0
  10. package/src/api-manager/datasources/d365/d365-order.datasource.ts +69 -0
  11. package/src/api-manager/datasources/d365/d365-organization.datasource.ts +92 -0
  12. package/src/api-manager/datasources/d365/d365-product.datasource.ts +272 -0
  13. package/src/api-manager/datasources/d365/d365-session.datasource.ts +25 -0
  14. package/src/api-manager/datasources/d365/d365-user.datasource.ts +132 -0
  15. package/src/api-manager/datasources/d365/d365.datasource.ts +45 -0
  16. package/src/api-manager/datasources/d365/index.ts +4 -0
  17. package/src/api-manager/datasources/d365/test-context.ts +30 -0
  18. package/src/api-manager/datasources/d365/utils/create-search-criteria.ts +17 -0
  19. package/src/api-manager/datasources/d365/utils/decode-jwt.ts +11 -0
  20. package/src/api-manager/datasources/d365/utils/get-context-cookie.ts +37 -0
  21. package/src/api-manager/datasources/d365/utils/parse-object.ts +9 -0
  22. package/src/api-manager/datasources/d365/utils/product-images-utils.ts +43 -0
  23. package/src/api-manager/datasources/d365/utils/product-inventory-utils.ts +37 -0
  24. package/src/api-manager/datasources/e4/e4-address.datasource.ts +107 -0
  25. package/src/api-manager/datasources/e4/e4-cart.datasource.ts +248 -0
  26. package/src/api-manager/datasources/e4/e4-order.datasource.ts +43 -0
  27. package/src/api-manager/datasources/e4/e4-organization.datasource.ts +19 -0
  28. package/src/api-manager/datasources/e4/e4-product.datasource.ts +157 -0
  29. package/src/api-manager/datasources/e4/e4-session.datasource.ts +43 -0
  30. package/src/api-manager/datasources/e4/e4-user.datasource.ts +118 -0
  31. package/src/api-manager/datasources/e4/e4.datasource.ts +55 -0
  32. package/src/api-manager/datasources/e4/e4.remaps.ts +331 -0
  33. package/src/api-manager/datasources/e4/e4.translator.test.ts +202 -0
  34. package/src/api-manager/datasources/e4/e4.translator.ts +648 -0
  35. package/src/api-manager/datasources/e4/graphqlRequestSdk.ts +43515 -0
  36. package/src/api-manager/datasources/e4/utils/unwrap-e4-variants.ts +65 -0
  37. package/src/api-manager/index.ts +71 -0
  38. package/src/api-manager/lib/cart-cookie-handler.ts +14 -0
  39. package/src/api-manager/lib/category-helpers.ts +113 -0
  40. package/src/api-manager/lib/get-dynamics-context.ts +34 -0
  41. package/src/api-manager/lib/get-graphql-client.test.ts +106 -0
  42. package/src/api-manager/lib/get-graphql-client.ts +53 -0
  43. package/src/api-manager/schemas/README.md +12 -0
  44. package/src/api-manager/schemas/address.schema.ts +46 -0
  45. package/src/api-manager/schemas/cart.schema.ts +92 -0
  46. package/src/api-manager/schemas/d365.schema.ts +7727 -0
  47. package/src/api-manager/schemas/order.schema.ts +30 -0
  48. package/src/api-manager/schemas/organization.schema.ts +32 -0
  49. package/src/api-manager/schemas/product.schema.ts +140 -0
  50. package/src/api-manager/schemas/session.schema.ts +17 -0
  51. package/src/api-manager/schemas/user.schema.ts +14 -0
  52. package/src/api-manager/services/address/mutations/create-address.ts +22 -0
  53. package/src/api-manager/services/address/mutations/delete-address.ts +21 -0
  54. package/src/api-manager/services/address/mutations/get-delivery-options.ts +22 -0
  55. package/src/api-manager/services/address/mutations/update-address.ts +21 -0
  56. package/src/api-manager/services/address/queries/get-countries.ts +16 -0
  57. package/src/api-manager/services/address/queries/get-states.ts +16 -0
  58. package/src/api-manager/services/cart/mutations/add-discount-code.ts +21 -0
  59. package/src/api-manager/services/cart/mutations/add-to-cart.ts +53 -0
  60. package/src/api-manager/services/cart/mutations/checkout.ts +11 -0
  61. package/src/api-manager/services/cart/mutations/delete-cart-line.ts +18 -0
  62. package/src/api-manager/services/cart/mutations/get-payment-accept-result.ts +20 -0
  63. package/src/api-manager/services/cart/mutations/remove-cart-line-delivery-mode.ts +24 -0
  64. package/src/api-manager/services/cart/mutations/remove-discount-code.ts +21 -0
  65. package/src/api-manager/services/cart/mutations/update-cart-line-delivery-mode.ts +24 -0
  66. package/src/api-manager/services/cart/mutations/update-cart-lines.ts +21 -0
  67. package/src/api-manager/services/cart/mutations/update-cart.ts +21 -0
  68. package/src/api-manager/services/cart/queries/get-cart.ts +12 -0
  69. package/src/api-manager/services/cart/queries/get-payment-accept-point.ts +18 -0
  70. package/src/api-manager/services/categories/queries/get-categories.ts +8 -0
  71. package/src/api-manager/services/create-mutation.ts +65 -0
  72. package/src/api-manager/services/create-query.ts +305 -0
  73. package/src/api-manager/services/get-query-client.ts +40 -0
  74. package/src/api-manager/services/order/queries/get-order-details.ts +17 -0
  75. package/src/api-manager/services/order/queries/get-orders.ts +14 -0
  76. package/src/api-manager/services/organization/queries/get-channel-configuration.ts +14 -0
  77. package/src/api-manager/services/organization/queries/get-stores.ts +17 -0
  78. package/src/api-manager/services/product/mutations/search-products.ts +23 -0
  79. package/src/api-manager/services/product/queries/get-product-availability.ts +15 -0
  80. package/src/api-manager/services/product/queries/get-product-by-id.ts +17 -0
  81. package/src/api-manager/services/product/queries/get-product-by-ids.ts +14 -0
  82. package/src/api-manager/services/product/queries/get-product-list.ts +16 -0
  83. package/src/api-manager/services/product/queries/get-related-products.ts +14 -0
  84. package/src/api-manager/services/product/queries/search-products.ts +10 -0
  85. package/src/api-manager/services/product/server/product.server.ts +13 -0
  86. package/src/api-manager/services/session/mutations/session-init.ts +22 -0
  87. package/src/api-manager/services/session/mutations/session-logout.ts +18 -0
  88. package/src/api-manager/services/session/queries/get-session.ts +10 -0
  89. package/src/api-manager/services/user/mutations/create-wishlist.ts +21 -0
  90. package/src/api-manager/services/user/mutations/delete-wishlist.ts +17 -0
  91. package/src/api-manager/services/user/mutations/update-user.ts +18 -0
  92. package/src/api-manager/services/user/queries/get-user-counts.ts +10 -0
  93. package/src/api-manager/services/user/queries/get-user.ts +10 -0
  94. package/src/api-manager/services/user/queries/get-wishlist-details.ts +10 -0
  95. package/src/api-manager/services/user/queries/get-wishlists.ts +10 -0
  96. package/src/api-manager/types/Datasource.ts +197 -0
  97. package/src/auth/auth-options.test.ts +127 -0
  98. package/src/auth/auth-options.ts +68 -0
  99. package/src/auth/msal.ts +65 -0
  100. package/src/auth/next-auth-cookie-manager.ts +86 -0
  101. package/src/auth/providers/aadb2c-provider.ts +33 -0
  102. package/src/auth/providers/authentik-provider.ts +24 -0
  103. package/src/auth/providers/index.ts +9 -0
  104. package/src/auth/providers/keycloak-provider.ts +22 -0
  105. package/src/auth/refresh-token-url-keys.ts +6 -0
  106. package/src/auth/refresh-token.ts +134 -0
  107. package/src/auth/signout.ts +46 -0
  108. package/src/auth/types/next-auth.d.ts +38 -0
  109. package/src/cms/blog.ts +229 -0
  110. package/src/cms/endpoints.ts +76 -0
  111. package/src/cms/interfaces/navigation.ts +52 -0
  112. package/src/cms/interfaces/productData.ts +83 -0
  113. package/src/cms/pages.ts +149 -0
  114. package/src/components/Blocks/BlockManager.tsx +67 -0
  115. package/src/components/Blocks/Components/BrandLogosScroller.tsx +72 -0
  116. package/src/components/Blocks/Components/CategoryCard.tsx +47 -0
  117. package/src/components/Blocks/Components/CategoryCarousel/index.tsx +60 -0
  118. package/src/components/Blocks/Components/FeaturePill.tsx +99 -0
  119. package/src/components/Blocks/Components/FeaturedCategories.tsx +41 -0
  120. package/src/components/Blocks/Components/FeaturedProducts.tsx +41 -0
  121. package/src/components/Blocks/Components/Footer.tsx +77 -0
  122. package/src/components/Blocks/Components/Hero.tsx +73 -0
  123. package/src/components/Blocks/Components/HeroCarousel/index.tsx +42 -0
  124. package/src/components/Blocks/Components/Image.tsx +39 -0
  125. package/src/components/Blocks/Components/MediaCard.tsx +41 -0
  126. package/src/components/Blocks/Components/ProductCarousel/index.tsx +82 -0
  127. package/src/components/Blocks/Components/ProductSectionFullWidth/index.tsx +103 -0
  128. package/src/components/Blocks/Components/RichText.tsx +19 -0
  129. package/src/components/Blocks/Components/Seo/index.tsx +48 -0
  130. package/src/components/Blocks/Components/Services/index.tsx +21 -0
  131. package/src/components/Blocks/Components/Services/service-card.tsx +70 -0
  132. package/src/components/Blocks/Components/shared/featured-product-card.tsx +29 -0
  133. package/src/components/Blocks/Components/shared/product-category-item.tsx +49 -0
  134. package/src/components/Blocks/Components/shared/product-grid.tsx +48 -0
  135. package/src/components/Blocks/Components/shared/top-categories-card.tsx +66 -0
  136. package/src/components/Blocks/Components/shared/top-rating-product-card.tsx +63 -0
  137. package/src/components/Blocks/Icons/Components/Category.tsx +14 -0
  138. package/src/components/Blocks/Icons/Components/DottedStar.tsx +40 -0
  139. package/src/components/Blocks/Icons/Components/FallbackIcon.tsx +33 -0
  140. package/src/components/Blocks/Icons/Components/GiftBox.tsx +18 -0
  141. package/src/components/Blocks/Icons/Components/Light.tsx +13 -0
  142. package/src/components/Blocks/Icons/Components/NewArrival.tsx +18 -0
  143. package/src/components/Blocks/Icons/Components/RankBadge.tsx +39 -0
  144. package/src/components/Blocks/Icons/index.ts +32 -0
  145. package/src/components/Blocks/index.tsx +16 -0
  146. package/src/components/Blocks/interfaces.ts +240 -0
  147. package/src/components/BoxShadowCard.tsx +16 -0
  148. package/src/components/Footer/data/index.ts +32 -0
  149. package/src/components/Footer/index.tsx +88 -0
  150. package/src/components/Footer/interfaces.ts +37 -0
  151. package/src/components/Footer/sections/FooterAppStore.tsx +45 -0
  152. package/src/components/Footer/sections/FooterContact.tsx +36 -0
  153. package/src/components/Footer/sections/FooterLinks.tsx +30 -0
  154. package/src/components/Footer/sections/FooterLogo.tsx +26 -0
  155. package/src/components/Footer/sections/FooterSocialLinks.tsx +70 -0
  156. package/src/components/Footer/styles/index.ts +39 -0
  157. package/src/components/GlobalLoading/index.tsx +102 -0
  158. package/src/components/ImageWithFallback.tsx +51 -0
  159. package/src/components/Loading/index.tsx +36 -0
  160. package/src/components/NavProvider/index.tsx +59 -0
  161. package/src/components/NavProvider/utils/createLink.ts +15 -0
  162. package/src/components/Notifications/README.md +15 -0
  163. package/src/components/Notifications/notification-context.tsx +82 -0
  164. package/src/components/Notifications/use-notification.ts +12 -0
  165. package/src/components/README.md +9 -0
  166. package/src/components/ReactQueryProvider/index.tsx +12 -0
  167. package/src/components/Shared/Image.tsx +5 -0
  168. package/src/components/T/index.tsx +15 -0
  169. package/src/components/_components/BazaarCard.tsx +21 -0
  170. package/src/components/_components/BazaarImage.tsx +12 -0
  171. package/src/components/_components/BazaarMenu.tsx +47 -0
  172. package/src/components/_components/BazaarSwitch.tsx +37 -0
  173. package/src/components/_components/BazaarTextField.tsx +73 -0
  174. package/src/components/_components/DropZone.tsx +86 -0
  175. package/src/components/_components/HoverBox.tsx +22 -0
  176. package/src/components/_components/LazyImage.tsx +9 -0
  177. package/src/components/_components/MiniCartClient.tsx +65 -0
  178. package/src/components/_components/SearchInput.tsx +28 -0
  179. package/src/components/_components/SnackbarProvider.tsx +32 -0
  180. package/src/components/_components/Typography.tsx +227 -0
  181. package/src/components/_components/WhiteButton.tsx +20 -0
  182. package/src/components/_components/accordion/accordion-header.tsx +43 -0
  183. package/src/components/_components/accordion/index.ts +1 -0
  184. package/src/components/_components/bazaar-types.ts +84 -0
  185. package/src/components/_components/carousel/carousel.tsx +72 -0
  186. package/src/components/_components/carousel/components/carousel-arrows.tsx +60 -0
  187. package/src/components/_components/carousel/components/carousel-dots.tsx +21 -0
  188. package/src/components/_components/carousel/index.ts +3 -0
  189. package/src/components/_components/carousel/styles/index.ts +93 -0
  190. package/src/components/_components/carousel-cards/carousel-card-1/carousel-card-1.tsx +64 -0
  191. package/src/components/_components/carousel-cards/carousel-card-1/index.ts +1 -0
  192. package/src/components/_components/carousel-cards/carousel-card-1/styles.ts +34 -0
  193. package/src/components/_components/carousel-cards/carousel-card-2/carousel-card-2.tsx +73 -0
  194. package/src/components/_components/carousel-cards/carousel-card-2/index.ts +1 -0
  195. package/src/components/_components/carousel-cards/carousel-card-2/styles.ts +26 -0
  196. package/src/components/_components/carousel-cards/carousel-card-3/carousel-card-3.tsx +34 -0
  197. package/src/components/_components/carousel-cards/carousel-card-3/index.ts +1 -0
  198. package/src/components/_components/carousel-cards/carousel-card-3/styles.ts +28 -0
  199. package/src/components/_components/carousel-cards/carousel-card-4/carousel-card-4.tsx +76 -0
  200. package/src/components/_components/carousel-cards/carousel-card-4/index.ts +1 -0
  201. package/src/components/_components/carousel-cards/carousel-card-4/styles.ts +27 -0
  202. package/src/components/_components/categories/category-list/category-list.tsx +59 -0
  203. package/src/components/_components/categories/category-list/index.ts +1 -0
  204. package/src/components/_components/categories/category-list/styles.ts +29 -0
  205. package/src/components/_components/categories/category-list/types.ts +4 -0
  206. package/src/components/_components/categories/category-list-item/category-menu-item.tsx +37 -0
  207. package/src/components/_components/categories/category-list-item/index.ts +1 -0
  208. package/src/components/_components/categories/category-list-item/styles.ts +35 -0
  209. package/src/components/_components/categories/category-menu.tsx +51 -0
  210. package/src/components/_components/categories/mega-menu/banner.tsx +56 -0
  211. package/src/components/_components/categories/mega-menu/column-list.tsx +70 -0
  212. package/src/components/_components/categories/mega-menu/mega-menu-1.tsx +37 -0
  213. package/src/components/_components/categories/mega-menu/mega-menu-2.tsx +37 -0
  214. package/src/components/_components/categories/mega-menu/styles.ts +25 -0
  215. package/src/components/_components/categories/types.ts +16 -0
  216. package/src/components/_components/category-cards/category-card-1/category-card-1.tsx +21 -0
  217. package/src/components/_components/category-cards/category-card-1/index.ts +1 -0
  218. package/src/components/_components/category-cards/category-card-1/styles.ts +37 -0
  219. package/src/components/_components/countdown/count-box.tsx +16 -0
  220. package/src/components/_components/countdown/count-down.tsx +24 -0
  221. package/src/components/_components/countdown/index.tsx +2 -0
  222. package/src/components/_components/countdown/useCountDown.ts +41 -0
  223. package/src/components/_components/data-table/index.ts +2 -0
  224. package/src/components/_components/data-table/table-header.tsx +91 -0
  225. package/src/components/_components/data-table/table-pagination.tsx +36 -0
  226. package/src/components/_components/flex-box/flex-between.tsx +14 -0
  227. package/src/components/_components/flex-box/flex-box.tsx +9 -0
  228. package/src/components/_components/flex-box/flex-row-center.tsx +9 -0
  229. package/src/components/_components/flex-box/index.ts +5 -0
  230. package/src/components/_components/footer/components/about-links.tsx +23 -0
  231. package/src/components/_components/footer/components/app-store.tsx +38 -0
  232. package/src/components/_components/footer/components/customer-care-links.tsx +21 -0
  233. package/src/components/_components/footer/components/logo.tsx +23 -0
  234. package/src/components/_components/footer/components/social-links.tsx +43 -0
  235. package/src/components/_components/footer/data/index.ts +54 -0
  236. package/src/components/_components/footer/footer-1.tsx +62 -0
  237. package/src/components/_components/footer/footer-2.tsx +57 -0
  238. package/src/components/_components/footer/footer-3.tsx +53 -0
  239. package/src/components/_components/footer/footer-4.tsx +71 -0
  240. package/src/components/_components/footer/index.ts +4 -0
  241. package/src/components/_components/footer/styles/index.ts +42 -0
  242. package/src/components/_components/header/components/categories-menu.tsx +23 -0
  243. package/src/components/_components/header/components/mobile-header.tsx +72 -0
  244. package/src/components/_components/header/components/user.test.tsx +200 -0
  245. package/src/components/_components/header/components/user.tsx +205 -0
  246. package/src/components/_components/header/header.tsx +63 -0
  247. package/src/components/_components/header/hooks/use-header.ts +13 -0
  248. package/src/components/_components/header/index.ts +1 -0
  249. package/src/components/_components/header/sticky-header.tsx +17 -0
  250. package/src/components/_components/header/styles/index.ts +24 -0
  251. package/src/components/_components/hooks/useOverflowDetect.ts +34 -0
  252. package/src/components/_components/hooks/useSettings.ts +16 -0
  253. package/src/components/_components/icons/cart-bag.tsx +13 -0
  254. package/src/components/_components/icons/category-outline.tsx +29 -0
  255. package/src/components/_components/icons/category.tsx +12 -0
  256. package/src/components/_components/icons/home.tsx +19 -0
  257. package/src/components/_components/icons/search.tsx +13 -0
  258. package/src/components/_components/icons/shopping-bag-outlined.tsx +13 -0
  259. package/src/components/_components/icons/up-down.tsx +21 -0
  260. package/src/components/_components/icons/user.tsx +13 -0
  261. package/src/components/_components/icons/user2.tsx +14 -0
  262. package/src/components/_components/mini-cart/__tests__/cart-item.test.tsx +174 -0
  263. package/src/components/_components/mini-cart/__tests__/mini-cart.test.tsx +121 -0
  264. package/src/components/_components/mini-cart/__tests__/test-cart-empty.json +84 -0
  265. package/src/components/_components/mini-cart/__tests__/test-cart-with-item.json +244 -0
  266. package/src/components/_components/mini-cart/components/bottom-actions.tsx +27 -0
  267. package/src/components/_components/mini-cart/components/cart-item.tsx +144 -0
  268. package/src/components/_components/mini-cart/components/empty-view.tsx +29 -0
  269. package/src/components/_components/mini-cart/components/top-header.tsx +34 -0
  270. package/src/components/_components/mini-cart/index.ts +1 -0
  271. package/src/components/_components/mini-cart/mini-cart.tsx +107 -0
  272. package/src/components/_components/mobile-navigation/index.ts +3 -0
  273. package/src/components/_components/mobile-navigation/mobile-navigation-bar.tsx +73 -0
  274. package/src/components/_components/mobile-navigation/styles/index.ts +63 -0
  275. package/src/components/_components/nav-link/index.ts +5 -0
  276. package/src/components/_components/nav-link/nav-link-2.tsx +32 -0
  277. package/src/components/_components/nav-link/nav-link-3.tsx +67 -0
  278. package/src/components/_components/nav-link/nav-link.tsx +53 -0
  279. package/src/components/_components/navbar/categories.tsx +27 -0
  280. package/src/components/_components/navbar/category-based-menu/category-based-menu.tsx +52 -0
  281. package/src/components/_components/navbar/category-based-menu/components/categories.tsx +44 -0
  282. package/src/components/_components/navbar/category-based-menu/components/category-item.tsx +31 -0
  283. package/src/components/_components/navbar/category-based-menu/components/child-categories.tsx +38 -0
  284. package/src/components/_components/navbar/category-based-menu/index.ts +1 -0
  285. package/src/components/_components/navbar/category-based-menu/styles.ts +81 -0
  286. package/src/components/_components/navbar/category-based-menu/types.ts +18 -0
  287. package/src/components/_components/navbar/index.ts +1 -0
  288. package/src/components/_components/navbar/mega-menu/category-list.tsx +29 -0
  289. package/src/components/_components/navbar/mega-menu/index.ts +1 -0
  290. package/src/components/_components/navbar/mega-menu/mega-menu.tsx +71 -0
  291. package/src/components/_components/navbar/mega-menu/styles.ts +43 -0
  292. package/src/components/_components/navbar/mobile-menu/index.ts +1 -0
  293. package/src/components/_components/navbar/mobile-menu/mobile-menu.tsx +70 -0
  294. package/src/components/_components/navbar/mobile-menu/render-levels.test.tsx +71 -0
  295. package/src/components/_components/navbar/mobile-menu/render-levels.tsx +62 -0
  296. package/src/components/_components/navbar/nav-list/cms-nav.test.tsx +84 -0
  297. package/src/components/_components/navbar/nav-list/index.ts +1 -0
  298. package/src/components/_components/navbar/nav-list/nav-item-child.tsx +66 -0
  299. package/src/components/_components/navbar/nav-list/nav-list.tsx +119 -0
  300. package/src/components/_components/navbar/navbar.tsx +43 -0
  301. package/src/components/_components/navbar/styles.ts +90 -0
  302. package/src/components/_components/navbar/utils/transform-nav.test.ts +209 -0
  303. package/src/components/_components/navbar/utils/transform-nav.ts +43 -0
  304. package/src/components/_components/newsletter/index.ts +1 -0
  305. package/src/components/_components/newsletter/newsletter.tsx +108 -0
  306. package/src/components/_components/newsletter/social-icons.tsx +35 -0
  307. package/src/components/_components/newsletter/styles.ts +65 -0
  308. package/src/components/_components/page-sidenav/grocery-side-nav/components/link-item.tsx +21 -0
  309. package/src/components/_components/page-sidenav/grocery-side-nav/components/list-item.tsx +27 -0
  310. package/src/components/_components/page-sidenav/grocery-side-nav/components/nav-accordion.tsx +36 -0
  311. package/src/components/_components/page-sidenav/grocery-side-nav/components/render-child.tsx +26 -0
  312. package/src/components/_components/page-sidenav/grocery-side-nav/grocery-side-nav.tsx +32 -0
  313. package/src/components/_components/page-sidenav/grocery-side-nav/index.ts +1 -0
  314. package/src/components/_components/page-sidenav/grocery-side-nav/styles/index.ts +11 -0
  315. package/src/components/_components/page-sidenav/health-beauty-side-nav/components/list-item.tsx +27 -0
  316. package/src/components/_components/page-sidenav/health-beauty-side-nav/components/nav-accordion.tsx +44 -0
  317. package/src/components/_components/page-sidenav/health-beauty-side-nav/components/render-child.tsx +20 -0
  318. package/src/components/_components/page-sidenav/health-beauty-side-nav/health-beauty-side-nav.tsx +43 -0
  319. package/src/components/_components/page-sidenav/health-beauty-side-nav/index.ts +1 -0
  320. package/src/components/_components/page-sidenav/health-beauty-side-nav/styles/index.ts +27 -0
  321. package/src/components/_components/page-sidenav/side-navbar/components/list-item.tsx +25 -0
  322. package/src/components/_components/page-sidenav/side-navbar/components/nav-accordion.tsx +46 -0
  323. package/src/components/_components/page-sidenav/side-navbar/components/render-child.tsx +20 -0
  324. package/src/components/_components/page-sidenav/side-navbar/index.ts +1 -0
  325. package/src/components/_components/page-sidenav/side-navbar/side-nav-bar.tsx +77 -0
  326. package/src/components/_components/page-sidenav/side-navbar/styles/index.ts +73 -0
  327. package/src/components/_components/page-sidenav/side-navbar-2/components/button-content.tsx +32 -0
  328. package/src/components/_components/page-sidenav/side-navbar-2/components/sidebar-accordion.tsx +66 -0
  329. package/src/components/_components/page-sidenav/side-navbar-2/index.ts +1 -0
  330. package/src/components/_components/page-sidenav/side-navbar-2/side-navbar-2.tsx +63 -0
  331. package/src/components/_components/page-sidenav/side-navbar-2/styles/index.ts +68 -0
  332. package/src/components/_components/product-cards/discount-chip.tsx +43 -0
  333. package/src/components/_components/product-cards/product-card-1/components/hover-actions.tsx +37 -0
  334. package/src/components/_components/product-cards/product-card-1/components/quantity-buttons.tsx +56 -0
  335. package/src/components/_components/product-cards/product-card-1/index.ts +1 -0
  336. package/src/components/_components/product-cards/product-card-1/product-card.tsx +146 -0
  337. package/src/components/_components/product-cards/product-card-1/styles/index.ts +46 -0
  338. package/src/components/_components/product-cards/product-card-10/index.ts +1 -0
  339. package/src/components/_components/product-cards/product-card-10/product-card.tsx +124 -0
  340. package/src/components/_components/product-cards/product-card-10/styles/index.ts +38 -0
  341. package/src/components/_components/product-cards/product-card-11/index.ts +1 -0
  342. package/src/components/_components/product-cards/product-card-11/product-card.tsx +63 -0
  343. package/src/components/_components/product-cards/product-card-11/styles/index.ts +16 -0
  344. package/src/components/_components/product-cards/product-card-12/index.ts +1 -0
  345. package/src/components/_components/product-cards/product-card-12/product-card.tsx +42 -0
  346. package/src/components/_components/product-cards/product-card-12/styles/index.ts +16 -0
  347. package/src/components/_components/product-cards/product-card-13/index.ts +1 -0
  348. package/src/components/_components/product-cards/product-card-13/product-card.tsx +45 -0
  349. package/src/components/_components/product-cards/product-card-13/styles/index.ts +25 -0
  350. package/src/components/_components/product-cards/product-card-14/index.ts +1 -0
  351. package/src/components/_components/product-cards/product-card-14/product-card.tsx +122 -0
  352. package/src/components/_components/product-cards/product-card-14/styles/index.ts +40 -0
  353. package/src/components/_components/product-cards/product-card-15/index.ts +1 -0
  354. package/src/components/_components/product-cards/product-card-15/product-card.tsx +118 -0
  355. package/src/components/_components/product-cards/product-card-15/styles/index.ts +57 -0
  356. package/src/components/_components/product-cards/product-card-16/components/quantity-buttons.tsx +56 -0
  357. package/src/components/_components/product-cards/product-card-16/index.ts +1 -0
  358. package/src/components/_components/product-cards/product-card-16/product-card.tsx +114 -0
  359. package/src/components/_components/product-cards/product-card-16/styles/index.ts +18 -0
  360. package/src/components/_components/product-cards/product-card-2/components/favorite-button.tsx +29 -0
  361. package/src/components/_components/product-cards/product-card-2/components/product-price.tsx +26 -0
  362. package/src/components/_components/product-cards/product-card-2/index.ts +1 -0
  363. package/src/components/_components/product-cards/product-card-2/product-card.tsx +70 -0
  364. package/src/components/_components/product-cards/product-card-3/components/hover-actions.tsx +83 -0
  365. package/src/components/_components/product-cards/product-card-3/index.ts +1 -0
  366. package/src/components/_components/product-cards/product-card-3/product-card.tsx +110 -0
  367. package/src/components/_components/product-cards/product-card-3/styles/index.ts +89 -0
  368. package/src/components/_components/product-cards/product-card-4/components/hover-actions.tsx +50 -0
  369. package/src/components/_components/product-cards/product-card-4/index.ts +1 -0
  370. package/src/components/_components/product-cards/product-card-4/product-card.tsx +128 -0
  371. package/src/components/_components/product-cards/product-card-4/styles/index.ts +66 -0
  372. package/src/components/_components/product-cards/product-card-5/components/button-actions.tsx +49 -0
  373. package/src/components/_components/product-cards/product-card-5/components/hover-actions.tsx +50 -0
  374. package/src/components/_components/product-cards/product-card-5/index.ts +1 -0
  375. package/src/components/_components/product-cards/product-card-5/product-card.tsx +137 -0
  376. package/src/components/_components/product-cards/product-card-5/styles/index.ts +94 -0
  377. package/src/components/_components/product-cards/product-card-6/components/hover-actions.tsx +50 -0
  378. package/src/components/_components/product-cards/product-card-6/index.ts +1 -0
  379. package/src/components/_components/product-cards/product-card-6/product-card.tsx +121 -0
  380. package/src/components/_components/product-cards/product-card-6/styles/index.ts +63 -0
  381. package/src/components/_components/product-cards/product-card-7/components/product-status.tsx +18 -0
  382. package/src/components/_components/product-cards/product-card-7/components/quantity-buttons.tsx +47 -0
  383. package/src/components/_components/product-cards/product-card-7/index.ts +1 -0
  384. package/src/components/_components/product-cards/product-card-7/product-card.tsx +136 -0
  385. package/src/components/_components/product-cards/product-card-7/styles/index.ts +98 -0
  386. package/src/components/_components/product-cards/product-card-8/index.ts +1 -0
  387. package/src/components/_components/product-cards/product-card-8/product-card.tsx +133 -0
  388. package/src/components/_components/product-cards/product-card-8/styles/index.ts +51 -0
  389. package/src/components/_components/product-cards/product-card-9/components/add-to-cart.tsx +60 -0
  390. package/src/components/_components/product-cards/product-card-9/components/favorite-button.tsx +27 -0
  391. package/src/components/_components/product-cards/product-card-9/components/tags.tsx +33 -0
  392. package/src/components/_components/product-cards/product-card-9/index.ts +1 -0
  393. package/src/components/_components/product-cards/product-card-9/product-card.tsx +169 -0
  394. package/src/components/_components/product-cards/product-price.tsx +26 -0
  395. package/src/components/_components/product-cards/product-rating.tsx +28 -0
  396. package/src/components/_components/product-cards/product-title.tsx +24 -0
  397. package/src/components/_components/product-cards/use-product.ts +35 -0
  398. package/src/components/_components/products-view/product-view-dialog.tsx +180 -0
  399. package/src/components/_components/products-view/products-grid-view.tsx +39 -0
  400. package/src/components/_components/products-view/products-list-view.tsx +35 -0
  401. package/src/components/_components/progress/index.ts +1 -0
  402. package/src/components/_components/progress/progress.tsx +77 -0
  403. package/src/components/_components/scrollbar/index.ts +1 -0
  404. package/src/components/_components/scrollbar/scrollbar.tsx +27 -0
  405. package/src/components/_components/scrollbar/styles.ts +15 -0
  406. package/src/components/_components/search-box/components/category-dropdown.tsx +61 -0
  407. package/src/components/_components/search-box/components/search-result.tsx +29 -0
  408. package/src/components/_components/search-box/hooks/use-search.ts +63 -0
  409. package/src/components/_components/search-box/index.ts +2 -0
  410. package/src/components/_components/search-box/search-input-category.test.tsx +110 -0
  411. package/src/components/_components/search-box/search-input-category.tsx +104 -0
  412. package/src/components/_components/search-box/search-input.test.tsx +41 -0
  413. package/src/components/_components/search-box/search-input.tsx +64 -0
  414. package/src/components/_components/search-box/styles/index.ts +45 -0
  415. package/src/components/_components/section-header/index.ts +2 -0
  416. package/src/components/_components/section-header/section-creator.tsx +28 -0
  417. package/src/components/_components/section-header/section-header.tsx +44 -0
  418. package/src/components/_components/service-cards/icon-component.tsx +18 -0
  419. package/src/components/_components/service-cards/service-card-1/index.ts +1 -0
  420. package/src/components/_components/service-cards/service-card-1/service-card-1.tsx +39 -0
  421. package/src/components/_components/service-cards/service-card-2/index.ts +1 -0
  422. package/src/components/_components/service-cards/service-card-2/service-card-2.tsx +34 -0
  423. package/src/components/_components/service-cards/service-card-3/index.ts +1 -0
  424. package/src/components/_components/service-cards/service-card-3/service-card-3.tsx +25 -0
  425. package/src/components/_components/service-cards/service-card-3/styles.ts +23 -0
  426. package/src/components/_components/settings/index.ts +1 -0
  427. package/src/components/_components/settings/setting.tsx +141 -0
  428. package/src/components/_components/settings/styles.ts +57 -0
  429. package/src/components/_components/shop-card/index.ts +1 -0
  430. package/src/components/_components/shop-card/shop-card.tsx +152 -0
  431. package/src/components/_components/shop-card/styles.ts +33 -0
  432. package/src/components/_components/side-nav/index.ts +1 -0
  433. package/src/components/_components/side-nav/side-nav.tsx +49 -0
  434. package/src/components/_components/site-logo.tsx +17 -0
  435. package/src/components/_components/sticky/Sticky.tsx +62 -0
  436. package/src/components/_components/sticky/index.ts +1 -0
  437. package/src/components/_components/sticky/styles.ts +38 -0
  438. package/src/components/_components/sticky-wrapper/index.ts +1 -0
  439. package/src/components/_components/sticky-wrapper/sticky-wrapper.tsx +21 -0
  440. package/src/components/_components/sticky-wrapper/styles.ts +25 -0
  441. package/src/components/_components/stories/story-content/index.ts +1 -0
  442. package/src/components/_components/stories/story-content/story-content.tsx +28 -0
  443. package/src/components/_components/stories/story-content/styles.ts +22 -0
  444. package/src/components/_components/stories/story-item/index.ts +1 -0
  445. package/src/components/_components/stories/story-item/story-item.tsx +24 -0
  446. package/src/components/_components/stories/story-item/styles.ts +11 -0
  447. package/src/components/_components/stories/story-viewer/index.ts +1 -0
  448. package/src/components/_components/stories/story-viewer/story-viewer.tsx +44 -0
  449. package/src/components/_components/stories/story-viewer/styles.ts +15 -0
  450. package/src/components/_components/subscribe-input/index.ts +1 -0
  451. package/src/components/_components/subscribe-input/styles.ts +14 -0
  452. package/src/components/_components/subscribe-input/subscribe-input.tsx +43 -0
  453. package/src/components/_components/topbar/index.ts +1 -0
  454. package/src/components/_components/topbar/styles.ts +55 -0
  455. package/src/components/_components/topbar/top-bar.tsx +112 -0
  456. package/src/components/_components/utils/constants.ts +8 -0
  457. package/src/components/countries-input.tsx +78 -0
  458. package/src/config.ts +47 -0
  459. package/src/lib/build-detail-url.ts +8 -0
  460. package/src/lib/build-product-detail-url.ts +12 -0
  461. package/src/lib/cart-cookie-client-handler.ts +12 -0
  462. package/src/lib/cart-cookie-handler.ts +14 -0
  463. package/src/lib/category-helpers.ts +113 -0
  464. package/src/lib/create-graphql-client.ts +32 -0
  465. package/src/lib/currency-formatter.ts +31 -0
  466. package/src/lib/get-palette-color.ts +50 -0
  467. package/src/lib/graphqlRequestSdk.ts +41234 -0
  468. package/src/lib/hexToLuma.ts +55 -0
  469. package/src/lib/lib.ts +61 -0
  470. package/src/lib/map-helper.ts +71 -0
  471. package/src/lib/page-slugs.ts +10 -0
  472. package/src/lib/refiner-utils.ts +32 -0
  473. package/src/lib/store-hours-helper.ts +274 -0
  474. package/src/lib/test-media.ts +23 -0
  475. package/tsconfig.json +27 -0
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # @evenicanpm/storefront-core
2
+
3
+ ## Overview
4
+
5
+ - this package should contain the internals of the storefront
6
+ - the storefront should be a shell that implements all of the code in this package
7
+ - there should be an exstensibility layer on the key components
8
+ - api-manager
9
+ - components
10
+ - etc
11
+
12
+ ## ApiManager Config
13
+
14
+ - This package cannot depend on storefront, so config will live in
15
+ this package until we find a better/different solution for injecting the config from storefront dir
16
+
17
+ ## Build and Dependencies
18
+
19
+ - this package is consumed and built by webpack as part of storefront build
20
+ - it does not have it's own compile/build step
21
+ - must have this package listed under `transpilePackages` in the storefront next.config.mjs
22
+ - using `transpilePackages` keeps the @evenicanpm packages very lightweight and portable
23
+ - during product dev this package is installed via local file url (symlink)
24
+ - this means this packages dependencies are NOT installed, everything should be a peerDep
25
+ and then added to the storefront package.json as a dependency
26
+ - there is a step in the `init.sh` script that will symlink the storefront node_modules to
27
+ the top-level of client packages - this ensures that the same versions of packages are used
28
+ - this is required for packages such as `@tanstack/react-query` that require the same package
29
+ location to be used across the entire codebase
30
+
31
+ ## Misc
32
+
33
+ - if at some point we want to start installing packages in this repo we will have to run an npm
34
+ install step in the `init.sh` of storefront
35
+
36
+ ## Next Steps
37
+
38
+ - [ ] Remove dead packages from shared/studio
39
+ - [ ] Clean up package.json in top-level client-packages
40
+ - [ ] Clean up tests
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@evenicanpm/storefront-core",
3
+ "version": "1.0.0-alpha",
4
+ "description": "Core module for D365/e4 Headless Storefront",
5
+ "scripts": {
6
+ "test": "echo \"Error: no test specified\" && exit 1"
7
+ },
8
+ "exports": {
9
+ ".": "./index.js",
10
+ "./*": "./*"
11
+ },
12
+ "author": "Evenica",
13
+ "license": "ISC",
14
+ "dependencies": {
15
+ "@msdyn365-commerce/retail-proxy": "9.50",
16
+ "graphql": "^16.11.0",
17
+ "graphql-request": "^7.1.2",
18
+ "jsonwebtoken": "^9.0.2",
19
+ "lodash": "^4.17.21",
20
+ "object-mapper": "^6.2.0",
21
+ "zod": "^3.25.25"
22
+ },
23
+ "devDependencies": {
24
+ "@strapi/blocks-react-renderer": "^1.0.1",
25
+ "@types/jsonwebtoken": "^9.0.9",
26
+ "@types/lodash": "^4.17.17",
27
+ "@types/node": "^22.15.20",
28
+ "@types/object-mapper": "^6.2.2"
29
+ },
30
+ "peerDependencies": {
31
+ "@tanstack/react-query": "^5.76.1",
32
+ "next": "^15.2.1",
33
+ "next-auth": "^4.24.11",
34
+ "typescript": "^5.8.3"
35
+ }
36
+ }
@@ -0,0 +1,38 @@
1
+ # Api Manager Package
2
+
3
+ - All data fetching will originate from this layer
4
+ - Eg. a server action will call the ApiManager to interact with external systems, api, etc.
5
+
6
+ # Folders
7
+
8
+ ## Datasources
9
+
10
+ - Datasource interface implementations - api manager loads multiple of these and then switches between
11
+
12
+ ## Schemas
13
+
14
+ - input/output types for all datasource
15
+ - D365 is base type, all other datasources should translate to this model
16
+
17
+ ## Core
18
+
19
+ - Base classes and interfaces
20
+
21
+ ## Lib
22
+
23
+ - Utilities and helpers that instantiate api manager etc.
24
+
25
+ ## Services
26
+
27
+ - layer on top of react-query
28
+ - a series of hooks used for react client components
29
+
30
+ # Guide
31
+
32
+ ## Add a new method to the `ApiManager`
33
+
34
+ 1. If the entity does not have a `entity.model.ts` file in `src/app/data-access/models`, add one and create schemas for input types eg. `addToCartInput`
35
+ 2. Add usecase to `data-access/Datasource.ts` interface
36
+ 3. Add the same usecase to `data-access/ApiManager.ts` class methods
37
+ 4. Finally, add method to the relevant data source, eg. `/src/app/data-access/datasources/E4.datasource.ts`
38
+ 5. You are now able to call the method from the `ApiManager.`
@@ -0,0 +1,12 @@
1
+ {
2
+ "primary": "e4",
3
+ "secondary": [],
4
+ "overrides": {},
5
+ "d365": {
6
+ "baseUrl": "https://scui1e8d9zn85030208-rs.su.retail.dynamics.com/",
7
+ "catalogId": 0,
8
+ "oun": "128",
9
+ "baseImageUrl": "https://images-us-prod.cms.commerce.dynamics.com/cms/api/lmrndcmtsl/imageFileData/search?fileName=/",
10
+ "channelId": 68719478279
11
+ }
12
+ }
@@ -0,0 +1,17 @@
1
+ # Data Sources
2
+
3
+ - Contains all data sources, translators and interfaces that are consumed by the ApiManager
4
+ - Currently the datasource implementation is responsible for translation and validation before handing data back to the ApiManager
5
+
6
+ ## File Naming
7
+
8
+ - `<datasourceName>.datasource.ts` is used for datasources.
9
+ - `<datasourceName>.translator.ts` is used for translation layers.
10
+
11
+ ## Data Access Layer Nextjs
12
+
13
+ https://nextjs.org/blog/security-nextjs-server-components-actions#data-access-layer
14
+
15
+ - NextJS recommends doing auth inside the data access layer as well as on routes
16
+ - This provides optimal data security.
17
+ - We should extend the Datasources or the Apimanager to check auth/access during data retrieval.
@@ -0,0 +1,141 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { AddressApi } from "@/api-manager/types/Datasource";
3
+ import {
4
+ CountryRegionInfo,
5
+ DeliveryOption,
6
+ FilterDeliveryModeOption,
7
+ StateProvinceInfo,
8
+ } from "@msdyn365-commerce/retail-proxy";
9
+ import { getDeliveryOptionsAsync } from "@msdyn365-commerce/retail-proxy/dist/DataActions/CartsDataActions.g";
10
+ import {
11
+ getCountryRegionsByLanguageIdAsync,
12
+ getStateProvincesAsync,
13
+ } from "@msdyn365-commerce/retail-proxy/dist/DataActions/StoreOperationsDataActions.g";
14
+ import {
15
+ Address,
16
+ GetCountriesInput,
17
+ GetDeliveryOptionsInput,
18
+ GetStatesInput,
19
+ } from "@/schemas/address.schema";
20
+ import { getContextFromCookie } from "./utils/get-context-cookie";
21
+ import {
22
+ readAsync,
23
+ updateAsync,
24
+ } from "@msdyn365-commerce/retail-proxy/dist/DataActions/CustomersDataActions.g";
25
+ import { D365DatasourceBase } from "./d365-base.datasource";
26
+ class D365AddressDatasource extends D365DatasourceBase implements AddressApi {
27
+ async createAddress(address: Address): Promise<Address> {
28
+ const context = await getContextFromCookie();
29
+ const customer = await readAsync(context as any, "");
30
+ const accountNumber = customer.AccountNumber;
31
+
32
+ const prevAddresses = customer.Addresses ?? [];
33
+ customer.Addresses = [...prevAddresses, address as any];
34
+
35
+ const updatedCustomer = await updateAsync(context as any, {
36
+ ...customer,
37
+ AccountNumber: accountNumber,
38
+ });
39
+
40
+ const added = updatedCustomer.Addresses?.find((a) =>
41
+ prevAddresses.every((old) => old.RecordId !== a.RecordId),
42
+ );
43
+ if (!added || added.RecordId == null) {
44
+ throw new Error("Failed to create new address");
45
+ }
46
+
47
+ return {
48
+ ...added,
49
+ Id: added.RecordId.toString(),
50
+ };
51
+ }
52
+
53
+ async updateAddress(address: Address): Promise<Address> {
54
+ const context = await getContextFromCookie();
55
+ const customer = await readAsync(context as any, "");
56
+ customer.Addresses = customer.Addresses ?? [];
57
+
58
+ const idx = customer.Addresses.findIndex(
59
+ (a) => a.RecordId?.toString() === address.Id,
60
+ );
61
+ const updatedRecord = { ...(address as any) };
62
+
63
+ if (idx >= 0) {
64
+ customer.Addresses[idx] = {
65
+ ...customer.Addresses[idx],
66
+ ...updatedRecord,
67
+ };
68
+ } else {
69
+ customer.Addresses.push(updatedRecord);
70
+ }
71
+
72
+ const updatedCustomer = await updateAsync(context as any, customer);
73
+ const rec = updatedCustomer.Addresses?.find(
74
+ (a) => a.RecordId?.toString() === address.Id,
75
+ );
76
+ if (!rec || rec.RecordId == null) {
77
+ throw new Error(`Failed to update address Id=${address.Id}`);
78
+ }
79
+
80
+ return {
81
+ ...rec,
82
+ Id: rec.RecordId.toString(),
83
+ };
84
+ }
85
+
86
+ async deleteAddress(addressId: string): Promise<string> {
87
+ const context = await getContextFromCookie();
88
+ const customer = await readAsync(context as any, "");
89
+ customer.Addresses = customer.Addresses ?? [];
90
+
91
+ const rec = customer.Addresses.find(
92
+ (a) => a.RecordId?.toString() === addressId,
93
+ );
94
+ if (rec) {
95
+ rec.Deactivate = true;
96
+ await updateAsync(context as any, customer);
97
+ }
98
+
99
+ return addressId;
100
+ }
101
+
102
+ async getCountries(input: GetCountriesInput): Promise<CountryRegionInfo[]> {
103
+ const context = await getContextFromCookie();
104
+ const locale = input.locale ?? context.requestContext.locale;
105
+ if (!locale) {
106
+ throw new Error("Locale is required to fetch countries");
107
+ }
108
+
109
+ return getCountryRegionsByLanguageIdAsync(context as any, locale);
110
+ }
111
+
112
+ async getStates(input: GetStatesInput): Promise<StateProvinceInfo[]> {
113
+ const context = await getContextFromCookie();
114
+ if (!input.countryId) {
115
+ throw new Error("countryId is required to fetch states");
116
+ }
117
+
118
+ return getStateProvincesAsync(context as any, input.countryId);
119
+ }
120
+
121
+ async getDeliveryOptions(
122
+ input: GetDeliveryOptionsInput,
123
+ ): Promise<DeliveryOption[]> {
124
+ const context = await getContextFromCookie();
125
+ try {
126
+ return getDeliveryOptionsAsync(
127
+ context as any,
128
+ input.cartId,
129
+ input.shippingAddress,
130
+ input.cartLineIds,
131
+ FilterDeliveryModeOption.FilterOutNonCarrierDeliveryMode,
132
+ false,
133
+ );
134
+ } catch (err) {
135
+ console.error("getDeliveryOptions error:", err);
136
+ return [];
137
+ }
138
+ }
139
+ }
140
+
141
+ export default D365AddressDatasource;
@@ -0,0 +1,8 @@
1
+ import { ICallerContext } from "@msdyn365-commerce/retail-proxy";
2
+
3
+ export abstract class D365DatasourceBase {
4
+ context: ICallerContext;
5
+ constructor(context: ICallerContext) {
6
+ this.context = context;
7
+ }
8
+ }
@@ -0,0 +1,374 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ import { CartApi } from "@/api-manager/types/Datasource";
4
+ import {
5
+ CartType,
6
+ Cart as DynCart,
7
+ CardPaymentAcceptPoint,
8
+ CardPaymentAcceptSettings,
9
+ CardPaymentAcceptResult,
10
+ // SalesOrder,
11
+ CartTenderLine,
12
+ QueryResultSettings,
13
+ CartSearchCriteria,
14
+ ICallerContext,
15
+ CartLine,
16
+ } from "@msdyn365-commerce/retail-proxy";
17
+ import {
18
+ addCartLinesAsync,
19
+ createCartAsync,
20
+ readAsync,
21
+ removeCartLinesAsync,
22
+ updateCartLinesAsync,
23
+ updateAsync,
24
+ addDiscountCodeAsync,
25
+ removeDiscountCodesAsync,
26
+ updateLineDeliverySpecificationsAsync,
27
+ getCardPaymentAcceptPointAsync,
28
+ retrieveCardPaymentAcceptResultAsync,
29
+ checkoutAsync,
30
+ searchAsync,
31
+ } from "@msdyn365-commerce/retail-proxy/dist/DataActions/CartsDataActions.g";
32
+ import {
33
+ ManageDiscountCodeInput,
34
+ AddToCartInput,
35
+ Cart,
36
+ DeleteCartLineInput,
37
+ UpdateCartInput,
38
+ UpdateCartLineInput,
39
+ UpdateCartLineDeliveryModeInput,
40
+ RemoveCartLineDeliveryModeInput,
41
+ GetCardPaymentAcceptPointInput,
42
+ RetrieveCardPaymentAcceptResultInput,
43
+ CheckoutInput,
44
+ } from "@/schemas/cart.schema";
45
+ import { uniq, omit } from "lodash";
46
+ import { D365ProductDatasource } from "./d365-product.datasource";
47
+ import pojo from "./utils/parse-object";
48
+ import { getCartCookie } from "@/lib/cart-cookie-handler";
49
+ import { SalesOrder } from "@/schemas/order.schema";
50
+ import { D365DatasourceBase } from "./d365-base.datasource";
51
+
52
+ export class D365CartDatasource extends D365DatasourceBase implements CartApi {
53
+ async checkout(input: CheckoutInput): Promise<SalesOrder> {
54
+ const context = this.context;
55
+ const { currency, amount, tokenizedPaymentCard } = input;
56
+ const cartTenderLine: CartTenderLine = {
57
+ Currency: currency,
58
+ Amount: amount,
59
+ TenderTypeId: tokenizedPaymentCard.TenderType,
60
+ CardTypeId: tokenizedPaymentCard.CardTypeId,
61
+ TokenizedPaymentCard: tokenizedPaymentCard,
62
+ };
63
+ return await checkoutAsync(
64
+ context as any,
65
+ input.id,
66
+ input.receiptEmail,
67
+ undefined,
68
+ undefined,
69
+ [cartTenderLine],
70
+ );
71
+ }
72
+ async retrieveCardPaymentAcceptResult(
73
+ input: RetrieveCardPaymentAcceptResultInput,
74
+ ): Promise<CardPaymentAcceptResult> {
75
+ const context = this.context;
76
+ const { cartId, resultAccessCode, settings } = input;
77
+ return pojo(
78
+ retrieveCardPaymentAcceptResultAsync(
79
+ context as any,
80
+ resultAccessCode,
81
+ [],
82
+ cartId,
83
+ settings,
84
+ ),
85
+ );
86
+ }
87
+ async getCardAcceptPoint(
88
+ input: GetCardPaymentAcceptPointInput,
89
+ ): Promise<CardPaymentAcceptPoint> {
90
+ const context = this.context;
91
+ const { totalAmount, hideBillingAddress, origin } = input;
92
+ const paymentAcceptSettings: CardPaymentAcceptSettings = {
93
+ AdaptorPath:
94
+ (typeof window !== "undefined" && `${origin}/Connectors`) || undefined,
95
+ CardPaymentEnabled: true,
96
+ CardTokenizationEnabled: true,
97
+ HideBillingAddress: hideBillingAddress || false,
98
+ HostPageOrigin: origin || "",
99
+ PaymentAmount: totalAmount,
100
+ };
101
+ try {
102
+ const data = await getCardPaymentAcceptPointAsync(
103
+ context as any,
104
+ input.cartId,
105
+ paymentAcceptSettings,
106
+ );
107
+
108
+ return pojo(data);
109
+ } catch (error) {
110
+ console.warn(error);
111
+ return {};
112
+ }
113
+ }
114
+ async updateLineDeliveryMode(
115
+ input: UpdateCartLineDeliveryModeInput,
116
+ ): Promise<Cart> {
117
+ const context = this.context;
118
+ const { cartId, cartLineDeliverySpecification } = input;
119
+ const cart = await updateLineDeliverySpecificationsAsync(
120
+ context as any,
121
+ cartId,
122
+ cartLineDeliverySpecification,
123
+ );
124
+ return await mergeCartWithProducts(cart, this.context);
125
+ }
126
+ async removeLineDeliveryMode(
127
+ input: RemoveCartLineDeliveryModeInput,
128
+ ): Promise<Cart> {
129
+ const context = this.context;
130
+ // Get Address from cart input
131
+ const newCart = { ...input.cart };
132
+ // Remove Address and ShippingMethodId from cart lines
133
+ newCart.CartLines?.forEach((line) => {
134
+ line.DeliveryMode = "";
135
+ line.ShippingAddress = {};
136
+ line.Product = undefined;
137
+ });
138
+
139
+ // Update cartlines to remove the delivery mode
140
+ const cartWithoutDeliveryMode = await updateCartLinesAsync(
141
+ context as any,
142
+ String(newCart?.Id),
143
+ newCart?.CartLines,
144
+ newCart?.Version,
145
+ );
146
+
147
+ //Call update cart from this class with the address.
148
+ return this.updateCart({
149
+ cart: {
150
+ ...cartWithoutDeliveryMode,
151
+ ShippingAddress: newCart.ShippingAddress,
152
+ },
153
+ });
154
+ }
155
+
156
+ async removeDiscountcode(input: ManageDiscountCodeInput) {
157
+ const context = this.context;
158
+ if (!input.cartId) {
159
+ throw new Error("CartId is required to remove a discount code");
160
+ }
161
+ const cart = await removeDiscountCodesAsync(context as any, input.cartId, [
162
+ input.discountCode,
163
+ ]);
164
+ return await mergeCartWithProducts(cart, this.context);
165
+ }
166
+ async addDiscountCode(input: ManageDiscountCodeInput): Promise<Cart> {
167
+ const context = this.context;
168
+ const { discountCode, cartId } = input;
169
+ if (!cartId) {
170
+ throw new Error("CartId is required to add a discount code");
171
+ }
172
+ const cart = await addDiscountCodeAsync(
173
+ context as any,
174
+ cartId,
175
+ discountCode,
176
+ );
177
+ return await mergeCartWithProducts(cart, this.context);
178
+ }
179
+ async updateCartLine(input: UpdateCartLineInput): Promise<Cart> {
180
+ const context = this.context;
181
+ const { cartId, cartLine, version } = input;
182
+ if (!version || !cartId) {
183
+ throw new Error("CartId and Version are required to update a cart line");
184
+ }
185
+ const cartLinesWithoutProduct = cartLine.map((line) =>
186
+ omit(line, "Product"),
187
+ );
188
+ const cart = await updateCartLinesAsync(
189
+ context as any,
190
+ cartId,
191
+ cartLinesWithoutProduct,
192
+ version,
193
+ );
194
+ return await mergeCartWithProducts(cart, this.context);
195
+ }
196
+ async addToCart(input: AddToCartInput): Promise<Cart> {
197
+ const context = this.context;
198
+ const { cartId, cartLine, version } = input;
199
+ if (!version || !cartId) {
200
+ throw new Error("CartId and Version are required to add a cart line");
201
+ }
202
+ const _cartLines = cartLine.map((line) => omit(line, "Product"));
203
+ try {
204
+ const updatedCart = await addCartLinesAsync(
205
+ context as any,
206
+ cartId,
207
+ _cartLines,
208
+ version,
209
+ );
210
+ return await mergeCartWithProducts(updatedCart, this.context);
211
+ } catch (err) {
212
+ console.error(err);
213
+ throw new Error("Error adding to cart: " + JSON.stringify(err));
214
+ }
215
+ }
216
+ async updateCart(input: UpdateCartInput): Promise<Cart> {
217
+ const context = this.context;
218
+ const { cart } = input;
219
+ if (cart.CartLines) {
220
+ cart.CartLines.map((cl) => omit(cl, "Product"));
221
+ }
222
+ const updatedCart = await updateAsync(context as any, <DynCart>cart);
223
+ return await mergeCartWithProducts(updatedCart, this.context);
224
+ }
225
+ async deleteCartLine(input: DeleteCartLineInput): Promise<Cart> {
226
+ const context = this.context;
227
+ const { cartLine, cartId } = input;
228
+ const cartLineIds = cartLine
229
+ .map((line) => line.LineId)
230
+ .filter((id) => id !== undefined);
231
+ if (!cartId) {
232
+ throw new Error("CartId and Version are required to delete a cart line");
233
+ }
234
+ const cart = await removeCartLinesAsync(
235
+ context as any,
236
+ cartId,
237
+ cartLineIds,
238
+ );
239
+ return await mergeCartWithProducts(cart, this.context);
240
+ }
241
+
242
+ async getCart(input: { cartId: string }): Promise<Cart> {
243
+ const context = this.context;
244
+ const id = input?.cartId ?? (await getCartCookie());
245
+ let cart: DynCart;
246
+
247
+ if (!id) {
248
+ return this.createCart(context);
249
+ } else {
250
+ cart = (await readAsync(context as any, id)) as DynCart;
251
+ if (!cart) {
252
+ return this.createCart(context);
253
+ }
254
+ return await mergeCartWithProducts(cart, this.context);
255
+ }
256
+ }
257
+
258
+ async updateCartLines(input: UpdateCartLineInput): Promise<Cart> {
259
+ const context = this.context;
260
+ const { cartId, cartLine, version } = input;
261
+ if (!version || !cartId) {
262
+ throw new Error("CartId and Version are required to update a cart line");
263
+ }
264
+ const cartLinesWithoutProduct = cartLine.map((line) =>
265
+ omit(line, "Product"),
266
+ );
267
+ const cart = await updateCartLinesAsync(
268
+ context as any,
269
+ cartId,
270
+ cartLinesWithoutProduct,
271
+ version,
272
+ );
273
+ await mergeCartWithProducts(cart, this.context);
274
+ return <Cart>cart;
275
+ }
276
+
277
+ /**
278
+ * Merges guest and user carts, only needs to be done if authenticated
279
+ * @returns A cart object with products attached
280
+ */
281
+ async initCart(): Promise<Cart> {
282
+ const context = this.context;
283
+ const cartId = await getCartCookie();
284
+
285
+ const isAuthenticated =
286
+ context.requestContext.user.isAuthenticated &&
287
+ !!context.requestContext.user.token;
288
+
289
+ if (isAuthenticated) {
290
+ // Attempt to find the user's existing cart
291
+ const foundCart = await this.getUsersCart(context);
292
+ if (foundCart) {
293
+ // If the cookie cart differs from the found cart, remerge lines
294
+ if (cartId && foundCart.Id !== cartId) {
295
+ // Retrieve the old (guest) cart using the provided cartId
296
+ const oldCart = await this.getCart({ cartId });
297
+ if (oldCart && oldCart.CartLines?.length > 0) {
298
+ const cartLines: CartLine[] =
299
+ oldCart.CartLines.map((line) => ({
300
+ Quantity: line.Quantity,
301
+ ProductId: line.ProductId,
302
+ UnitOfMeasureSymbol: line.UnitOfMeasureSymbol,
303
+ })) || [];
304
+ await this.addToCart({
305
+ cartId: foundCart.Id,
306
+ cartLine: cartLines,
307
+ version: foundCart.Version,
308
+ });
309
+ }
310
+ }
311
+ return mergeCartWithProducts(foundCart, this.context);
312
+ }
313
+ }
314
+
315
+ // If not authenticated or no found cart, fall back to reading/creating the cookie cart
316
+ return await this.getCart({ cartId: cartId || "" });
317
+ }
318
+
319
+ async createCart(context: ICallerContext): Promise<Cart> {
320
+ return (await createCartAsync(context as any, <DynCart>{
321
+ CartTypeValue: CartType.Checkout,
322
+ })) as Cart;
323
+ }
324
+
325
+ async getUsersCart(context: ICallerContext): Promise<DynCart | undefined> {
326
+ const queryResultSettings: QueryResultSettings = {
327
+ Paging: { Top: 1, Skip: 0 },
328
+ Sorting: {
329
+ Columns: [
330
+ {
331
+ ColumnName: "ModifiedDateTime",
332
+ IsDescending: true,
333
+ },
334
+ ],
335
+ },
336
+ };
337
+ const searchCriteria: CartSearchCriteria = {
338
+ CartTypeValue: CartType.Checkout,
339
+ IncludeAnonymous: false,
340
+ };
341
+ const ctx = { ...context } as any;
342
+ ctx.queryResultSettings = queryResultSettings;
343
+ const cartResult = await searchAsync(ctx, searchCriteria);
344
+ return cartResult[0];
345
+ }
346
+ }
347
+
348
+ const mergeCartWithProducts = async (
349
+ cart: DynCart,
350
+ context: ICallerContext,
351
+ ): Promise<Cart> => {
352
+ const _cart = { ...cart } as Cart;
353
+ if (_cart.CartLines?.length) {
354
+ //Get products
355
+ const productIds = _cart.CartLines.map((line) => line.ProductId).filter(
356
+ (p) => p !== undefined,
357
+ );
358
+ if (productIds.length) {
359
+ const productDataSource = new D365ProductDatasource(context);
360
+ const products = await productDataSource.getProductByIds({
361
+ id: uniq(productIds),
362
+ });
363
+ if (products) {
364
+ _cart.CartLines.forEach((line) => {
365
+ const product = products.find((p) => p.RecordId === line.ProductId);
366
+ if (product) {
367
+ line.Product = product;
368
+ }
369
+ });
370
+ }
371
+ }
372
+ }
373
+ return cart as Cart;
374
+ };