@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.
- package/README.md +40 -0
- package/package.json +36 -0
- package/src/api-manager/README.md +38 -0
- package/src/api-manager/api-manager.config.json +12 -0
- package/src/api-manager/datasources/README.md +17 -0
- package/src/api-manager/datasources/d365/d365-address.datasource.ts +141 -0
- package/src/api-manager/datasources/d365/d365-base.datasource.ts +8 -0
- package/src/api-manager/datasources/d365/d365-cart.datasource.ts +374 -0
- package/src/api-manager/datasources/d365/d365-categories.datasource.ts +40 -0
- package/src/api-manager/datasources/d365/d365-order.datasource.ts +69 -0
- package/src/api-manager/datasources/d365/d365-organization.datasource.ts +92 -0
- package/src/api-manager/datasources/d365/d365-product.datasource.ts +272 -0
- package/src/api-manager/datasources/d365/d365-session.datasource.ts +25 -0
- package/src/api-manager/datasources/d365/d365-user.datasource.ts +132 -0
- package/src/api-manager/datasources/d365/d365.datasource.ts +45 -0
- package/src/api-manager/datasources/d365/index.ts +4 -0
- package/src/api-manager/datasources/d365/test-context.ts +30 -0
- package/src/api-manager/datasources/d365/utils/create-search-criteria.ts +17 -0
- package/src/api-manager/datasources/d365/utils/decode-jwt.ts +11 -0
- package/src/api-manager/datasources/d365/utils/get-context-cookie.ts +37 -0
- package/src/api-manager/datasources/d365/utils/parse-object.ts +9 -0
- package/src/api-manager/datasources/d365/utils/product-images-utils.ts +43 -0
- package/src/api-manager/datasources/d365/utils/product-inventory-utils.ts +37 -0
- package/src/api-manager/datasources/e4/e4-address.datasource.ts +107 -0
- package/src/api-manager/datasources/e4/e4-cart.datasource.ts +248 -0
- package/src/api-manager/datasources/e4/e4-order.datasource.ts +43 -0
- package/src/api-manager/datasources/e4/e4-organization.datasource.ts +19 -0
- package/src/api-manager/datasources/e4/e4-product.datasource.ts +157 -0
- package/src/api-manager/datasources/e4/e4-session.datasource.ts +43 -0
- package/src/api-manager/datasources/e4/e4-user.datasource.ts +118 -0
- package/src/api-manager/datasources/e4/e4.datasource.ts +55 -0
- package/src/api-manager/datasources/e4/e4.remaps.ts +331 -0
- package/src/api-manager/datasources/e4/e4.translator.test.ts +202 -0
- package/src/api-manager/datasources/e4/e4.translator.ts +648 -0
- package/src/api-manager/datasources/e4/graphqlRequestSdk.ts +43515 -0
- package/src/api-manager/datasources/e4/utils/unwrap-e4-variants.ts +65 -0
- package/src/api-manager/index.ts +71 -0
- package/src/api-manager/lib/cart-cookie-handler.ts +14 -0
- package/src/api-manager/lib/category-helpers.ts +113 -0
- package/src/api-manager/lib/get-dynamics-context.ts +34 -0
- package/src/api-manager/lib/get-graphql-client.test.ts +106 -0
- package/src/api-manager/lib/get-graphql-client.ts +53 -0
- package/src/api-manager/schemas/README.md +12 -0
- package/src/api-manager/schemas/address.schema.ts +46 -0
- package/src/api-manager/schemas/cart.schema.ts +92 -0
- package/src/api-manager/schemas/d365.schema.ts +7727 -0
- package/src/api-manager/schemas/order.schema.ts +30 -0
- package/src/api-manager/schemas/organization.schema.ts +32 -0
- package/src/api-manager/schemas/product.schema.ts +140 -0
- package/src/api-manager/schemas/session.schema.ts +17 -0
- package/src/api-manager/schemas/user.schema.ts +14 -0
- package/src/api-manager/services/address/mutations/create-address.ts +22 -0
- package/src/api-manager/services/address/mutations/delete-address.ts +21 -0
- package/src/api-manager/services/address/mutations/get-delivery-options.ts +22 -0
- package/src/api-manager/services/address/mutations/update-address.ts +21 -0
- package/src/api-manager/services/address/queries/get-countries.ts +16 -0
- package/src/api-manager/services/address/queries/get-states.ts +16 -0
- package/src/api-manager/services/cart/mutations/add-discount-code.ts +21 -0
- package/src/api-manager/services/cart/mutations/add-to-cart.ts +53 -0
- package/src/api-manager/services/cart/mutations/checkout.ts +11 -0
- package/src/api-manager/services/cart/mutations/delete-cart-line.ts +18 -0
- package/src/api-manager/services/cart/mutations/get-payment-accept-result.ts +20 -0
- package/src/api-manager/services/cart/mutations/remove-cart-line-delivery-mode.ts +24 -0
- package/src/api-manager/services/cart/mutations/remove-discount-code.ts +21 -0
- package/src/api-manager/services/cart/mutations/update-cart-line-delivery-mode.ts +24 -0
- package/src/api-manager/services/cart/mutations/update-cart-lines.ts +21 -0
- package/src/api-manager/services/cart/mutations/update-cart.ts +21 -0
- package/src/api-manager/services/cart/queries/get-cart.ts +12 -0
- package/src/api-manager/services/cart/queries/get-payment-accept-point.ts +18 -0
- package/src/api-manager/services/categories/queries/get-categories.ts +8 -0
- package/src/api-manager/services/create-mutation.ts +65 -0
- package/src/api-manager/services/create-query.ts +305 -0
- package/src/api-manager/services/get-query-client.ts +40 -0
- package/src/api-manager/services/order/queries/get-order-details.ts +17 -0
- package/src/api-manager/services/order/queries/get-orders.ts +14 -0
- package/src/api-manager/services/organization/queries/get-channel-configuration.ts +14 -0
- package/src/api-manager/services/organization/queries/get-stores.ts +17 -0
- package/src/api-manager/services/product/mutations/search-products.ts +23 -0
- package/src/api-manager/services/product/queries/get-product-availability.ts +15 -0
- package/src/api-manager/services/product/queries/get-product-by-id.ts +17 -0
- package/src/api-manager/services/product/queries/get-product-by-ids.ts +14 -0
- package/src/api-manager/services/product/queries/get-product-list.ts +16 -0
- package/src/api-manager/services/product/queries/get-related-products.ts +14 -0
- package/src/api-manager/services/product/queries/search-products.ts +10 -0
- package/src/api-manager/services/product/server/product.server.ts +13 -0
- package/src/api-manager/services/session/mutations/session-init.ts +22 -0
- package/src/api-manager/services/session/mutations/session-logout.ts +18 -0
- package/src/api-manager/services/session/queries/get-session.ts +10 -0
- package/src/api-manager/services/user/mutations/create-wishlist.ts +21 -0
- package/src/api-manager/services/user/mutations/delete-wishlist.ts +17 -0
- package/src/api-manager/services/user/mutations/update-user.ts +18 -0
- package/src/api-manager/services/user/queries/get-user-counts.ts +10 -0
- package/src/api-manager/services/user/queries/get-user.ts +10 -0
- package/src/api-manager/services/user/queries/get-wishlist-details.ts +10 -0
- package/src/api-manager/services/user/queries/get-wishlists.ts +10 -0
- package/src/api-manager/types/Datasource.ts +197 -0
- package/src/auth/auth-options.test.ts +127 -0
- package/src/auth/auth-options.ts +68 -0
- package/src/auth/msal.ts +65 -0
- package/src/auth/next-auth-cookie-manager.ts +86 -0
- package/src/auth/providers/aadb2c-provider.ts +33 -0
- package/src/auth/providers/authentik-provider.ts +24 -0
- package/src/auth/providers/index.ts +9 -0
- package/src/auth/providers/keycloak-provider.ts +22 -0
- package/src/auth/refresh-token-url-keys.ts +6 -0
- package/src/auth/refresh-token.ts +134 -0
- package/src/auth/signout.ts +46 -0
- package/src/auth/types/next-auth.d.ts +38 -0
- package/src/cms/blog.ts +229 -0
- package/src/cms/endpoints.ts +76 -0
- package/src/cms/interfaces/navigation.ts +52 -0
- package/src/cms/interfaces/productData.ts +83 -0
- package/src/cms/pages.ts +149 -0
- package/src/components/Blocks/BlockManager.tsx +67 -0
- package/src/components/Blocks/Components/BrandLogosScroller.tsx +72 -0
- package/src/components/Blocks/Components/CategoryCard.tsx +47 -0
- package/src/components/Blocks/Components/CategoryCarousel/index.tsx +60 -0
- package/src/components/Blocks/Components/FeaturePill.tsx +99 -0
- package/src/components/Blocks/Components/FeaturedCategories.tsx +41 -0
- package/src/components/Blocks/Components/FeaturedProducts.tsx +41 -0
- package/src/components/Blocks/Components/Footer.tsx +77 -0
- package/src/components/Blocks/Components/Hero.tsx +73 -0
- package/src/components/Blocks/Components/HeroCarousel/index.tsx +42 -0
- package/src/components/Blocks/Components/Image.tsx +39 -0
- package/src/components/Blocks/Components/MediaCard.tsx +41 -0
- package/src/components/Blocks/Components/ProductCarousel/index.tsx +82 -0
- package/src/components/Blocks/Components/ProductSectionFullWidth/index.tsx +103 -0
- package/src/components/Blocks/Components/RichText.tsx +19 -0
- package/src/components/Blocks/Components/Seo/index.tsx +48 -0
- package/src/components/Blocks/Components/Services/index.tsx +21 -0
- package/src/components/Blocks/Components/Services/service-card.tsx +70 -0
- package/src/components/Blocks/Components/shared/featured-product-card.tsx +29 -0
- package/src/components/Blocks/Components/shared/product-category-item.tsx +49 -0
- package/src/components/Blocks/Components/shared/product-grid.tsx +48 -0
- package/src/components/Blocks/Components/shared/top-categories-card.tsx +66 -0
- package/src/components/Blocks/Components/shared/top-rating-product-card.tsx +63 -0
- package/src/components/Blocks/Icons/Components/Category.tsx +14 -0
- package/src/components/Blocks/Icons/Components/DottedStar.tsx +40 -0
- package/src/components/Blocks/Icons/Components/FallbackIcon.tsx +33 -0
- package/src/components/Blocks/Icons/Components/GiftBox.tsx +18 -0
- package/src/components/Blocks/Icons/Components/Light.tsx +13 -0
- package/src/components/Blocks/Icons/Components/NewArrival.tsx +18 -0
- package/src/components/Blocks/Icons/Components/RankBadge.tsx +39 -0
- package/src/components/Blocks/Icons/index.ts +32 -0
- package/src/components/Blocks/index.tsx +16 -0
- package/src/components/Blocks/interfaces.ts +240 -0
- package/src/components/BoxShadowCard.tsx +16 -0
- package/src/components/Footer/data/index.ts +32 -0
- package/src/components/Footer/index.tsx +88 -0
- package/src/components/Footer/interfaces.ts +37 -0
- package/src/components/Footer/sections/FooterAppStore.tsx +45 -0
- package/src/components/Footer/sections/FooterContact.tsx +36 -0
- package/src/components/Footer/sections/FooterLinks.tsx +30 -0
- package/src/components/Footer/sections/FooterLogo.tsx +26 -0
- package/src/components/Footer/sections/FooterSocialLinks.tsx +70 -0
- package/src/components/Footer/styles/index.ts +39 -0
- package/src/components/GlobalLoading/index.tsx +102 -0
- package/src/components/ImageWithFallback.tsx +51 -0
- package/src/components/Loading/index.tsx +36 -0
- package/src/components/NavProvider/index.tsx +59 -0
- package/src/components/NavProvider/utils/createLink.ts +15 -0
- package/src/components/Notifications/README.md +15 -0
- package/src/components/Notifications/notification-context.tsx +82 -0
- package/src/components/Notifications/use-notification.ts +12 -0
- package/src/components/README.md +9 -0
- package/src/components/ReactQueryProvider/index.tsx +12 -0
- package/src/components/Shared/Image.tsx +5 -0
- package/src/components/T/index.tsx +15 -0
- package/src/components/_components/BazaarCard.tsx +21 -0
- package/src/components/_components/BazaarImage.tsx +12 -0
- package/src/components/_components/BazaarMenu.tsx +47 -0
- package/src/components/_components/BazaarSwitch.tsx +37 -0
- package/src/components/_components/BazaarTextField.tsx +73 -0
- package/src/components/_components/DropZone.tsx +86 -0
- package/src/components/_components/HoverBox.tsx +22 -0
- package/src/components/_components/LazyImage.tsx +9 -0
- package/src/components/_components/MiniCartClient.tsx +65 -0
- package/src/components/_components/SearchInput.tsx +28 -0
- package/src/components/_components/SnackbarProvider.tsx +32 -0
- package/src/components/_components/Typography.tsx +227 -0
- package/src/components/_components/WhiteButton.tsx +20 -0
- package/src/components/_components/accordion/accordion-header.tsx +43 -0
- package/src/components/_components/accordion/index.ts +1 -0
- package/src/components/_components/bazaar-types.ts +84 -0
- package/src/components/_components/carousel/carousel.tsx +72 -0
- package/src/components/_components/carousel/components/carousel-arrows.tsx +60 -0
- package/src/components/_components/carousel/components/carousel-dots.tsx +21 -0
- package/src/components/_components/carousel/index.ts +3 -0
- package/src/components/_components/carousel/styles/index.ts +93 -0
- package/src/components/_components/carousel-cards/carousel-card-1/carousel-card-1.tsx +64 -0
- package/src/components/_components/carousel-cards/carousel-card-1/index.ts +1 -0
- package/src/components/_components/carousel-cards/carousel-card-1/styles.ts +34 -0
- package/src/components/_components/carousel-cards/carousel-card-2/carousel-card-2.tsx +73 -0
- package/src/components/_components/carousel-cards/carousel-card-2/index.ts +1 -0
- package/src/components/_components/carousel-cards/carousel-card-2/styles.ts +26 -0
- package/src/components/_components/carousel-cards/carousel-card-3/carousel-card-3.tsx +34 -0
- package/src/components/_components/carousel-cards/carousel-card-3/index.ts +1 -0
- package/src/components/_components/carousel-cards/carousel-card-3/styles.ts +28 -0
- package/src/components/_components/carousel-cards/carousel-card-4/carousel-card-4.tsx +76 -0
- package/src/components/_components/carousel-cards/carousel-card-4/index.ts +1 -0
- package/src/components/_components/carousel-cards/carousel-card-4/styles.ts +27 -0
- package/src/components/_components/categories/category-list/category-list.tsx +59 -0
- package/src/components/_components/categories/category-list/index.ts +1 -0
- package/src/components/_components/categories/category-list/styles.ts +29 -0
- package/src/components/_components/categories/category-list/types.ts +4 -0
- package/src/components/_components/categories/category-list-item/category-menu-item.tsx +37 -0
- package/src/components/_components/categories/category-list-item/index.ts +1 -0
- package/src/components/_components/categories/category-list-item/styles.ts +35 -0
- package/src/components/_components/categories/category-menu.tsx +51 -0
- package/src/components/_components/categories/mega-menu/banner.tsx +56 -0
- package/src/components/_components/categories/mega-menu/column-list.tsx +70 -0
- package/src/components/_components/categories/mega-menu/mega-menu-1.tsx +37 -0
- package/src/components/_components/categories/mega-menu/mega-menu-2.tsx +37 -0
- package/src/components/_components/categories/mega-menu/styles.ts +25 -0
- package/src/components/_components/categories/types.ts +16 -0
- package/src/components/_components/category-cards/category-card-1/category-card-1.tsx +21 -0
- package/src/components/_components/category-cards/category-card-1/index.ts +1 -0
- package/src/components/_components/category-cards/category-card-1/styles.ts +37 -0
- package/src/components/_components/countdown/count-box.tsx +16 -0
- package/src/components/_components/countdown/count-down.tsx +24 -0
- package/src/components/_components/countdown/index.tsx +2 -0
- package/src/components/_components/countdown/useCountDown.ts +41 -0
- package/src/components/_components/data-table/index.ts +2 -0
- package/src/components/_components/data-table/table-header.tsx +91 -0
- package/src/components/_components/data-table/table-pagination.tsx +36 -0
- package/src/components/_components/flex-box/flex-between.tsx +14 -0
- package/src/components/_components/flex-box/flex-box.tsx +9 -0
- package/src/components/_components/flex-box/flex-row-center.tsx +9 -0
- package/src/components/_components/flex-box/index.ts +5 -0
- package/src/components/_components/footer/components/about-links.tsx +23 -0
- package/src/components/_components/footer/components/app-store.tsx +38 -0
- package/src/components/_components/footer/components/customer-care-links.tsx +21 -0
- package/src/components/_components/footer/components/logo.tsx +23 -0
- package/src/components/_components/footer/components/social-links.tsx +43 -0
- package/src/components/_components/footer/data/index.ts +54 -0
- package/src/components/_components/footer/footer-1.tsx +62 -0
- package/src/components/_components/footer/footer-2.tsx +57 -0
- package/src/components/_components/footer/footer-3.tsx +53 -0
- package/src/components/_components/footer/footer-4.tsx +71 -0
- package/src/components/_components/footer/index.ts +4 -0
- package/src/components/_components/footer/styles/index.ts +42 -0
- package/src/components/_components/header/components/categories-menu.tsx +23 -0
- package/src/components/_components/header/components/mobile-header.tsx +72 -0
- package/src/components/_components/header/components/user.test.tsx +200 -0
- package/src/components/_components/header/components/user.tsx +205 -0
- package/src/components/_components/header/header.tsx +63 -0
- package/src/components/_components/header/hooks/use-header.ts +13 -0
- package/src/components/_components/header/index.ts +1 -0
- package/src/components/_components/header/sticky-header.tsx +17 -0
- package/src/components/_components/header/styles/index.ts +24 -0
- package/src/components/_components/hooks/useOverflowDetect.ts +34 -0
- package/src/components/_components/hooks/useSettings.ts +16 -0
- package/src/components/_components/icons/cart-bag.tsx +13 -0
- package/src/components/_components/icons/category-outline.tsx +29 -0
- package/src/components/_components/icons/category.tsx +12 -0
- package/src/components/_components/icons/home.tsx +19 -0
- package/src/components/_components/icons/search.tsx +13 -0
- package/src/components/_components/icons/shopping-bag-outlined.tsx +13 -0
- package/src/components/_components/icons/up-down.tsx +21 -0
- package/src/components/_components/icons/user.tsx +13 -0
- package/src/components/_components/icons/user2.tsx +14 -0
- package/src/components/_components/mini-cart/__tests__/cart-item.test.tsx +174 -0
- package/src/components/_components/mini-cart/__tests__/mini-cart.test.tsx +121 -0
- package/src/components/_components/mini-cart/__tests__/test-cart-empty.json +84 -0
- package/src/components/_components/mini-cart/__tests__/test-cart-with-item.json +244 -0
- package/src/components/_components/mini-cart/components/bottom-actions.tsx +27 -0
- package/src/components/_components/mini-cart/components/cart-item.tsx +144 -0
- package/src/components/_components/mini-cart/components/empty-view.tsx +29 -0
- package/src/components/_components/mini-cart/components/top-header.tsx +34 -0
- package/src/components/_components/mini-cart/index.ts +1 -0
- package/src/components/_components/mini-cart/mini-cart.tsx +107 -0
- package/src/components/_components/mobile-navigation/index.ts +3 -0
- package/src/components/_components/mobile-navigation/mobile-navigation-bar.tsx +73 -0
- package/src/components/_components/mobile-navigation/styles/index.ts +63 -0
- package/src/components/_components/nav-link/index.ts +5 -0
- package/src/components/_components/nav-link/nav-link-2.tsx +32 -0
- package/src/components/_components/nav-link/nav-link-3.tsx +67 -0
- package/src/components/_components/nav-link/nav-link.tsx +53 -0
- package/src/components/_components/navbar/categories.tsx +27 -0
- package/src/components/_components/navbar/category-based-menu/category-based-menu.tsx +52 -0
- package/src/components/_components/navbar/category-based-menu/components/categories.tsx +44 -0
- package/src/components/_components/navbar/category-based-menu/components/category-item.tsx +31 -0
- package/src/components/_components/navbar/category-based-menu/components/child-categories.tsx +38 -0
- package/src/components/_components/navbar/category-based-menu/index.ts +1 -0
- package/src/components/_components/navbar/category-based-menu/styles.ts +81 -0
- package/src/components/_components/navbar/category-based-menu/types.ts +18 -0
- package/src/components/_components/navbar/index.ts +1 -0
- package/src/components/_components/navbar/mega-menu/category-list.tsx +29 -0
- package/src/components/_components/navbar/mega-menu/index.ts +1 -0
- package/src/components/_components/navbar/mega-menu/mega-menu.tsx +71 -0
- package/src/components/_components/navbar/mega-menu/styles.ts +43 -0
- package/src/components/_components/navbar/mobile-menu/index.ts +1 -0
- package/src/components/_components/navbar/mobile-menu/mobile-menu.tsx +70 -0
- package/src/components/_components/navbar/mobile-menu/render-levels.test.tsx +71 -0
- package/src/components/_components/navbar/mobile-menu/render-levels.tsx +62 -0
- package/src/components/_components/navbar/nav-list/cms-nav.test.tsx +84 -0
- package/src/components/_components/navbar/nav-list/index.ts +1 -0
- package/src/components/_components/navbar/nav-list/nav-item-child.tsx +66 -0
- package/src/components/_components/navbar/nav-list/nav-list.tsx +119 -0
- package/src/components/_components/navbar/navbar.tsx +43 -0
- package/src/components/_components/navbar/styles.ts +90 -0
- package/src/components/_components/navbar/utils/transform-nav.test.ts +209 -0
- package/src/components/_components/navbar/utils/transform-nav.ts +43 -0
- package/src/components/_components/newsletter/index.ts +1 -0
- package/src/components/_components/newsletter/newsletter.tsx +108 -0
- package/src/components/_components/newsletter/social-icons.tsx +35 -0
- package/src/components/_components/newsletter/styles.ts +65 -0
- package/src/components/_components/page-sidenav/grocery-side-nav/components/link-item.tsx +21 -0
- package/src/components/_components/page-sidenav/grocery-side-nav/components/list-item.tsx +27 -0
- package/src/components/_components/page-sidenav/grocery-side-nav/components/nav-accordion.tsx +36 -0
- package/src/components/_components/page-sidenav/grocery-side-nav/components/render-child.tsx +26 -0
- package/src/components/_components/page-sidenav/grocery-side-nav/grocery-side-nav.tsx +32 -0
- package/src/components/_components/page-sidenav/grocery-side-nav/index.ts +1 -0
- package/src/components/_components/page-sidenav/grocery-side-nav/styles/index.ts +11 -0
- package/src/components/_components/page-sidenav/health-beauty-side-nav/components/list-item.tsx +27 -0
- package/src/components/_components/page-sidenav/health-beauty-side-nav/components/nav-accordion.tsx +44 -0
- package/src/components/_components/page-sidenav/health-beauty-side-nav/components/render-child.tsx +20 -0
- package/src/components/_components/page-sidenav/health-beauty-side-nav/health-beauty-side-nav.tsx +43 -0
- package/src/components/_components/page-sidenav/health-beauty-side-nav/index.ts +1 -0
- package/src/components/_components/page-sidenav/health-beauty-side-nav/styles/index.ts +27 -0
- package/src/components/_components/page-sidenav/side-navbar/components/list-item.tsx +25 -0
- package/src/components/_components/page-sidenav/side-navbar/components/nav-accordion.tsx +46 -0
- package/src/components/_components/page-sidenav/side-navbar/components/render-child.tsx +20 -0
- package/src/components/_components/page-sidenav/side-navbar/index.ts +1 -0
- package/src/components/_components/page-sidenav/side-navbar/side-nav-bar.tsx +77 -0
- package/src/components/_components/page-sidenav/side-navbar/styles/index.ts +73 -0
- package/src/components/_components/page-sidenav/side-navbar-2/components/button-content.tsx +32 -0
- package/src/components/_components/page-sidenav/side-navbar-2/components/sidebar-accordion.tsx +66 -0
- package/src/components/_components/page-sidenav/side-navbar-2/index.ts +1 -0
- package/src/components/_components/page-sidenav/side-navbar-2/side-navbar-2.tsx +63 -0
- package/src/components/_components/page-sidenav/side-navbar-2/styles/index.ts +68 -0
- package/src/components/_components/product-cards/discount-chip.tsx +43 -0
- package/src/components/_components/product-cards/product-card-1/components/hover-actions.tsx +37 -0
- package/src/components/_components/product-cards/product-card-1/components/quantity-buttons.tsx +56 -0
- package/src/components/_components/product-cards/product-card-1/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-1/product-card.tsx +146 -0
- package/src/components/_components/product-cards/product-card-1/styles/index.ts +46 -0
- package/src/components/_components/product-cards/product-card-10/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-10/product-card.tsx +124 -0
- package/src/components/_components/product-cards/product-card-10/styles/index.ts +38 -0
- package/src/components/_components/product-cards/product-card-11/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-11/product-card.tsx +63 -0
- package/src/components/_components/product-cards/product-card-11/styles/index.ts +16 -0
- package/src/components/_components/product-cards/product-card-12/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-12/product-card.tsx +42 -0
- package/src/components/_components/product-cards/product-card-12/styles/index.ts +16 -0
- package/src/components/_components/product-cards/product-card-13/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-13/product-card.tsx +45 -0
- package/src/components/_components/product-cards/product-card-13/styles/index.ts +25 -0
- package/src/components/_components/product-cards/product-card-14/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-14/product-card.tsx +122 -0
- package/src/components/_components/product-cards/product-card-14/styles/index.ts +40 -0
- package/src/components/_components/product-cards/product-card-15/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-15/product-card.tsx +118 -0
- package/src/components/_components/product-cards/product-card-15/styles/index.ts +57 -0
- package/src/components/_components/product-cards/product-card-16/components/quantity-buttons.tsx +56 -0
- package/src/components/_components/product-cards/product-card-16/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-16/product-card.tsx +114 -0
- package/src/components/_components/product-cards/product-card-16/styles/index.ts +18 -0
- package/src/components/_components/product-cards/product-card-2/components/favorite-button.tsx +29 -0
- package/src/components/_components/product-cards/product-card-2/components/product-price.tsx +26 -0
- package/src/components/_components/product-cards/product-card-2/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-2/product-card.tsx +70 -0
- package/src/components/_components/product-cards/product-card-3/components/hover-actions.tsx +83 -0
- package/src/components/_components/product-cards/product-card-3/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-3/product-card.tsx +110 -0
- package/src/components/_components/product-cards/product-card-3/styles/index.ts +89 -0
- package/src/components/_components/product-cards/product-card-4/components/hover-actions.tsx +50 -0
- package/src/components/_components/product-cards/product-card-4/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-4/product-card.tsx +128 -0
- package/src/components/_components/product-cards/product-card-4/styles/index.ts +66 -0
- package/src/components/_components/product-cards/product-card-5/components/button-actions.tsx +49 -0
- package/src/components/_components/product-cards/product-card-5/components/hover-actions.tsx +50 -0
- package/src/components/_components/product-cards/product-card-5/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-5/product-card.tsx +137 -0
- package/src/components/_components/product-cards/product-card-5/styles/index.ts +94 -0
- package/src/components/_components/product-cards/product-card-6/components/hover-actions.tsx +50 -0
- package/src/components/_components/product-cards/product-card-6/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-6/product-card.tsx +121 -0
- package/src/components/_components/product-cards/product-card-6/styles/index.ts +63 -0
- package/src/components/_components/product-cards/product-card-7/components/product-status.tsx +18 -0
- package/src/components/_components/product-cards/product-card-7/components/quantity-buttons.tsx +47 -0
- package/src/components/_components/product-cards/product-card-7/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-7/product-card.tsx +136 -0
- package/src/components/_components/product-cards/product-card-7/styles/index.ts +98 -0
- package/src/components/_components/product-cards/product-card-8/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-8/product-card.tsx +133 -0
- package/src/components/_components/product-cards/product-card-8/styles/index.ts +51 -0
- package/src/components/_components/product-cards/product-card-9/components/add-to-cart.tsx +60 -0
- package/src/components/_components/product-cards/product-card-9/components/favorite-button.tsx +27 -0
- package/src/components/_components/product-cards/product-card-9/components/tags.tsx +33 -0
- package/src/components/_components/product-cards/product-card-9/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-9/product-card.tsx +169 -0
- package/src/components/_components/product-cards/product-price.tsx +26 -0
- package/src/components/_components/product-cards/product-rating.tsx +28 -0
- package/src/components/_components/product-cards/product-title.tsx +24 -0
- package/src/components/_components/product-cards/use-product.ts +35 -0
- package/src/components/_components/products-view/product-view-dialog.tsx +180 -0
- package/src/components/_components/products-view/products-grid-view.tsx +39 -0
- package/src/components/_components/products-view/products-list-view.tsx +35 -0
- package/src/components/_components/progress/index.ts +1 -0
- package/src/components/_components/progress/progress.tsx +77 -0
- package/src/components/_components/scrollbar/index.ts +1 -0
- package/src/components/_components/scrollbar/scrollbar.tsx +27 -0
- package/src/components/_components/scrollbar/styles.ts +15 -0
- package/src/components/_components/search-box/components/category-dropdown.tsx +61 -0
- package/src/components/_components/search-box/components/search-result.tsx +29 -0
- package/src/components/_components/search-box/hooks/use-search.ts +63 -0
- package/src/components/_components/search-box/index.ts +2 -0
- package/src/components/_components/search-box/search-input-category.test.tsx +110 -0
- package/src/components/_components/search-box/search-input-category.tsx +104 -0
- package/src/components/_components/search-box/search-input.test.tsx +41 -0
- package/src/components/_components/search-box/search-input.tsx +64 -0
- package/src/components/_components/search-box/styles/index.ts +45 -0
- package/src/components/_components/section-header/index.ts +2 -0
- package/src/components/_components/section-header/section-creator.tsx +28 -0
- package/src/components/_components/section-header/section-header.tsx +44 -0
- package/src/components/_components/service-cards/icon-component.tsx +18 -0
- package/src/components/_components/service-cards/service-card-1/index.ts +1 -0
- package/src/components/_components/service-cards/service-card-1/service-card-1.tsx +39 -0
- package/src/components/_components/service-cards/service-card-2/index.ts +1 -0
- package/src/components/_components/service-cards/service-card-2/service-card-2.tsx +34 -0
- package/src/components/_components/service-cards/service-card-3/index.ts +1 -0
- package/src/components/_components/service-cards/service-card-3/service-card-3.tsx +25 -0
- package/src/components/_components/service-cards/service-card-3/styles.ts +23 -0
- package/src/components/_components/settings/index.ts +1 -0
- package/src/components/_components/settings/setting.tsx +141 -0
- package/src/components/_components/settings/styles.ts +57 -0
- package/src/components/_components/shop-card/index.ts +1 -0
- package/src/components/_components/shop-card/shop-card.tsx +152 -0
- package/src/components/_components/shop-card/styles.ts +33 -0
- package/src/components/_components/side-nav/index.ts +1 -0
- package/src/components/_components/side-nav/side-nav.tsx +49 -0
- package/src/components/_components/site-logo.tsx +17 -0
- package/src/components/_components/sticky/Sticky.tsx +62 -0
- package/src/components/_components/sticky/index.ts +1 -0
- package/src/components/_components/sticky/styles.ts +38 -0
- package/src/components/_components/sticky-wrapper/index.ts +1 -0
- package/src/components/_components/sticky-wrapper/sticky-wrapper.tsx +21 -0
- package/src/components/_components/sticky-wrapper/styles.ts +25 -0
- package/src/components/_components/stories/story-content/index.ts +1 -0
- package/src/components/_components/stories/story-content/story-content.tsx +28 -0
- package/src/components/_components/stories/story-content/styles.ts +22 -0
- package/src/components/_components/stories/story-item/index.ts +1 -0
- package/src/components/_components/stories/story-item/story-item.tsx +24 -0
- package/src/components/_components/stories/story-item/styles.ts +11 -0
- package/src/components/_components/stories/story-viewer/index.ts +1 -0
- package/src/components/_components/stories/story-viewer/story-viewer.tsx +44 -0
- package/src/components/_components/stories/story-viewer/styles.ts +15 -0
- package/src/components/_components/subscribe-input/index.ts +1 -0
- package/src/components/_components/subscribe-input/styles.ts +14 -0
- package/src/components/_components/subscribe-input/subscribe-input.tsx +43 -0
- package/src/components/_components/topbar/index.ts +1 -0
- package/src/components/_components/topbar/styles.ts +55 -0
- package/src/components/_components/topbar/top-bar.tsx +112 -0
- package/src/components/_components/utils/constants.ts +8 -0
- package/src/components/countries-input.tsx +78 -0
- package/src/config.ts +47 -0
- package/src/lib/build-detail-url.ts +8 -0
- package/src/lib/build-product-detail-url.ts +12 -0
- package/src/lib/cart-cookie-client-handler.ts +12 -0
- package/src/lib/cart-cookie-handler.ts +14 -0
- package/src/lib/category-helpers.ts +113 -0
- package/src/lib/create-graphql-client.ts +32 -0
- package/src/lib/currency-formatter.ts +31 -0
- package/src/lib/get-palette-color.ts +50 -0
- package/src/lib/graphqlRequestSdk.ts +41234 -0
- package/src/lib/hexToLuma.ts +55 -0
- package/src/lib/lib.ts +61 -0
- package/src/lib/map-helper.ts +71 -0
- package/src/lib/page-slugs.ts +10 -0
- package/src/lib/refiner-utils.ts +32 -0
- package/src/lib/store-hours-helper.ts +274 -0
- package/src/lib/test-media.ts +23 -0
- 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,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
|
+
};
|