@evenicanpm/storefront-core 1.0.0-alpha → 1.0.1

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 (196) hide show
  1. package/package.json +3 -2
  2. package/src/api-manager/api-manager.config.json +1 -1
  3. package/src/api-manager/datasources/d365/d365-address.datasource.ts +4 -4
  4. package/src/api-manager/datasources/d365/d365-cart.datasource.ts +100 -7
  5. package/src/api-manager/datasources/d365/d365-product.datasource.ts +39 -17
  6. package/src/api-manager/datasources/d365/d365-user.datasource.ts +220 -68
  7. package/src/api-manager/datasources/d365/utils/decode-jwt.ts +2 -2
  8. package/src/api-manager/datasources/e4/e4-cart.datasource.ts +6 -0
  9. package/src/api-manager/datasources/e4/e4-product.datasource.ts +22 -2
  10. package/src/api-manager/datasources/e4/e4.datasource.ts +1 -1
  11. package/src/api-manager/datasources/e4/e4.remaps.ts +24 -0
  12. package/src/api-manager/datasources/e4/e4.translator.ts +19 -1
  13. package/src/api-manager/datasources/e4/{e4-user.datasource.ts → user/e4-user.datasource.ts} +41 -19
  14. package/src/api-manager/datasources/e4/user/e4-user.remaps.ts +4 -0
  15. package/src/api-manager/datasources/e4/user/e4-user.translator.ts +10 -0
  16. package/src/api-manager/index.ts +77 -15
  17. package/src/api-manager/lib/get-graphql-client.ts +7 -7
  18. package/src/api-manager/schemas/address.schema.ts +1 -19
  19. package/src/api-manager/schemas/cart.schema.ts +18 -0
  20. package/src/api-manager/schemas/product.schema.ts +8 -1
  21. package/src/api-manager/schemas/user.schema.ts +52 -1
  22. package/src/api-manager/services/address/queries/get-states.ts +1 -1
  23. package/src/api-manager/services/cart/mutations/checkout.ts +16 -1
  24. package/src/api-manager/services/cart/queries/get-cart-lines-inventory.ts +15 -0
  25. package/src/api-manager/services/create-extension-query.ts +26 -0
  26. package/src/api-manager/services/create-mutation.ts +5 -1
  27. package/src/api-manager/services/create-query.ts +10 -4
  28. package/src/api-manager/services/organization/queries/get-channel-configuration.ts +1 -1
  29. package/src/api-manager/services/product/queries/get-product-prices.ts +16 -0
  30. package/src/api-manager/services/product/queries/search-products.ts +1 -0
  31. package/src/api-manager/services/user/mutations/add-to-wishlist.ts +24 -0
  32. package/src/api-manager/services/user/mutations/copy-cart-to-wishlist.ts +23 -0
  33. package/src/api-manager/services/user/mutations/create-wishlist.ts +4 -4
  34. package/src/api-manager/services/user/mutations/delete-wishlist.ts +4 -3
  35. package/src/api-manager/services/user/mutations/remove-from-wishlist.ts +21 -0
  36. package/src/api-manager/services/user/mutations/update-wishlist.ts +23 -0
  37. package/src/api-manager/services/user/queries/get-wishlist-details.ts +11 -4
  38. package/src/api-manager/services/user/queries/get-wishlists.ts +4 -3
  39. package/src/api-manager/types/Datasource.ts +42 -14
  40. package/src/auth/auth-options.ts +2 -2
  41. package/src/auth/msal.ts +9 -9
  42. package/src/auth/next-auth-cookie-manager.ts +5 -3
  43. package/src/auth/providers/aadb2c-provider.ts +3 -4
  44. package/src/cms/endpoints.ts +2 -3
  45. package/src/components/Blocks/Components/ProductCarousel/index.tsx +6 -6
  46. package/src/components/_components/LazyImage.tsx +5 -2
  47. package/src/components/_components/header/components/user.tsx +1 -2
  48. package/src/components/_components/navbar/category-based-menu/components/categories.tsx +1 -1
  49. package/src/components/_components/navbar/mega-menu/mega-menu.tsx +1 -1
  50. package/src/components/_components/navbar/nav-list/nav-item-child.tsx +2 -2
  51. package/src/components/_components/product-cards/product-card-1/components/quantity-buttons.tsx +17 -8
  52. package/src/components/_components/product-cards/product-card-1/product-card-1-wrapper.tsx +304 -0
  53. package/src/components/_components/product-cards/product-card-1/product-card.tsx +16 -55
  54. package/src/components/_components/product-cards/product-card-8/product-card.tsx +80 -60
  55. package/src/components/_components/product-cards/product-card-8/styles/index.ts +10 -0
  56. package/src/components/_components/product-cards/product-card-wishlist/components/hover-actions.tsx +37 -0
  57. package/src/components/_components/product-cards/product-card-wishlist/index.ts +1 -0
  58. package/src/components/_components/product-cards/product-card-wishlist/product-card.tsx +118 -0
  59. package/src/components/_components/product-cards/product-card-wishlist/styles/index.ts +51 -0
  60. package/src/components/_components/product-dimensions/product-dimensions.tsx +114 -0
  61. package/src/components/_components/product-quantity-buttons/product-quantity-buttons.tsx +88 -0
  62. package/src/components/_components/products-view/product-view-dialog.tsx +48 -10
  63. package/src/components/_components/products-view/products-grid-view.tsx +31 -17
  64. package/src/components/_components/products-view/products-list-view.tsx +30 -16
  65. package/src/components/_components/search-box/__test__/search-input-category.test.tsx +110 -0
  66. package/src/components/_components/search-box/__test__/search-input.test.tsx +137 -0
  67. package/src/components/_components/search-box/__test__/search-results.json +165 -0
  68. package/src/components/_components/search-box/components/search-result.tsx +66 -12
  69. package/src/components/_components/search-box/search-input-category.tsx +135 -32
  70. package/src/components/_components/search-box/styles/index.ts +2 -0
  71. package/src/components/_components/section-header/section-creator.tsx +1 -0
  72. package/src/components/_components/section-header/section-header.tsx +1 -1
  73. package/src/components/_components/settings/setting.tsx +1 -1
  74. package/src/components/_components/wishlist/add-to-wishlist-dialog.tsx +161 -0
  75. package/src/components/_components/wishlist/components/create-new-list.tsx +167 -0
  76. package/src/components/_components/wishlist/components/create-wishlist-button.tsx +40 -0
  77. package/src/components/_components/wishlist/components/dashboard-header.tsx +123 -0
  78. package/src/components/_components/wishlist/components/navigation.tsx +87 -0
  79. package/src/components/_components/wishlist/components/no-records.tsx +20 -0
  80. package/src/components/_components/wishlist/components/wishlist-modal-item.tsx +66 -0
  81. package/src/components/_components/wishlist/remove-from-wishlist-dialog.tsx +174 -0
  82. package/src/components/_components/wishlist/styles.ts +61 -0
  83. package/src/components/_components/wishlist-modal/TODO.md +10 -0
  84. package/src/components/_components/wishlist-modal/add-to-wishlist-button.tsx +68 -0
  85. package/src/components/_components/wishlist-modal/add-to-wishlist-dialog.tsx +161 -0
  86. package/src/components/_components/wishlist-modal/remove-from-wishlist-dialog.tsx +174 -0
  87. package/src/components/_components/wishlist-modal/wishlist-modal-item.tsx +65 -0
  88. package/src/components/countries-input.tsx +7 -12
  89. package/src/hooks/use-cart.tsx +82 -0
  90. package/src/hooks/use-variants.tsx +85 -0
  91. package/src/lib/cart-cookie-handler-constants.ts +8 -0
  92. package/src/lib/cart-cookie-handler.ts +27 -5
  93. package/src/lib/create-graphql-client.ts +1 -2
  94. package/src/lib/product-list-types.ts +41 -0
  95. package/src/pages/account/addresses/address-form.tsx +289 -0
  96. package/src/pages/account/addresses/address-item.tsx +104 -0
  97. package/src/pages/account/dashboard-header.tsx +123 -0
  98. package/src/pages/account/navigation.tsx +84 -0
  99. package/src/pages/account/no-records.tsx +20 -0
  100. package/src/pages/account/orders/icons/delivery.tsx +14 -0
  101. package/src/pages/account/orders/icons/package-box.tsx +13 -0
  102. package/src/pages/account/orders/icons/truck-filled.tsx +14 -0
  103. package/src/pages/account/orders/order-progress.tsx +111 -0
  104. package/src/pages/account/orders/order-row.tsx +61 -0
  105. package/src/pages/account/orders/order-summary.tsx +83 -0
  106. package/src/pages/account/orders/ordered-products.tsx +114 -0
  107. package/src/pages/account/profile/profile-button.test.tsx +59 -0
  108. package/src/pages/account/profile/profile-button.tsx +50 -0
  109. package/src/pages/account/profile/user-info.tsx +59 -0
  110. package/src/pages/account/styles.ts +32 -0
  111. package/src/pages/account/table-row.tsx +19 -0
  112. package/src/pages/account/wishlist/create-new-list.tsx +167 -0
  113. package/src/pages/account/wishlist/create-wishlist-button.tsx +40 -0
  114. package/src/pages/account/wishlist/wishlist-item.tsx +82 -0
  115. package/src/pages/blog/pagination.tsx +38 -0
  116. package/src/pages/cart/cart-item.tsx +312 -0
  117. package/src/pages/cart/checkout-form.tsx +122 -0
  118. package/src/pages/cart/coupon-entry.tsx +90 -0
  119. package/src/pages/cart/estimate-shipping.tsx +183 -0
  120. package/src/pages/cart/wrapper.tsx +30 -0
  121. package/src/pages/checkout/checkout-alt-form/address-card.tsx +73 -0
  122. package/src/pages/checkout/checkout-alt-form/checkout-form.tsx +133 -0
  123. package/src/pages/checkout/checkout-alt-form/checkout-step.tsx +120 -0
  124. package/src/pages/checkout/checkout-alt-form/customer-information.tsx +94 -0
  125. package/src/pages/checkout/checkout-alt-form/delivery-address.tsx +170 -0
  126. package/src/pages/checkout/checkout-alt-form/delivery-date.tsx +114 -0
  127. package/src/pages/checkout/checkout-alt-form/delivery-options.tsx +186 -0
  128. package/src/pages/checkout/checkout-alt-form/edit-address-form.tsx +130 -0
  129. package/src/pages/checkout/checkout-alt-form/heading.tsx +50 -0
  130. package/src/pages/checkout/checkout-alt-form/index.ts +1 -0
  131. package/src/pages/checkout/checkout-alt-form/new-address-form.tsx +294 -0
  132. package/src/pages/checkout/checkout-alt-form/node.tsx +9 -0
  133. package/src/pages/checkout/checkout-alt-form/payment-details.tsx +344 -0
  134. package/src/pages/checkout/checkout-alt-form/safe-card-preview-data.tsx +36 -0
  135. package/src/pages/checkout/checkout-alt-form/types.ts +20 -0
  136. package/src/pages/checkout/checkout-alt-summary/cart-item.tsx +39 -0
  137. package/src/pages/checkout/checkout-alt-summary/checkout-alt-summary.tsx +40 -0
  138. package/src/pages/checkout/checkout-alt-summary/index.ts +1 -0
  139. package/src/pages/checkout/checkout-alt-summary/list-item.tsx +31 -0
  140. package/src/pages/confirmation/address.tsx +22 -0
  141. package/src/pages/confirmation/confirmation-summary.tsx +52 -0
  142. package/src/pages/confirmation/ordered-products.tsx +108 -0
  143. package/src/pages/product-details/available-shops.tsx +48 -0
  144. package/src/pages/product-details/bopis/find-in-store-button.tsx +63 -0
  145. package/src/pages/product-details/bopis/find-in-store-modal.tsx +257 -0
  146. package/src/pages/product-details/bopis/pickup-option-select.tsx +127 -0
  147. package/src/pages/product-details/bopis/search-header.tsx +69 -0
  148. package/src/pages/product-details/checkbox-label.tsx +20 -0
  149. package/src/pages/product-details/currency.ts +64 -0
  150. package/src/pages/product-details/frequently-bought.tsx +90 -0
  151. package/src/pages/product-details/frequently-product-card.tsx +60 -0
  152. package/src/pages/product-details/product-comment.tsx +44 -0
  153. package/src/pages/product-details/product-description.tsx +22 -0
  154. package/src/pages/product-details/product-filter-card.tsx +257 -0
  155. package/src/pages/product-details/product-intro/product-intro-images.tsx +87 -0
  156. package/src/pages/product-details/product-intro/product-intro.tsx +250 -0
  157. package/src/pages/product-details/product-review.tsx +131 -0
  158. package/src/pages/product-details/product-tabs.tsx +51 -0
  159. package/src/pages/product-details/related-products.tsx +42 -0
  160. package/src/pages/product-details/types.ts +11 -0
  161. package/src/pages/product-list/breadcrumbs.tsx +39 -0
  162. package/src/pages/product-list/checkbox-label.tsx +20 -0
  163. package/src/pages/product-list/facet-group.tsx +125 -0
  164. package/src/pages/product-list/facet.tsx +36 -0
  165. package/src/pages/product-list/list-filter.tsx +40 -0
  166. package/src/pages/product-list/pagination.tsx +80 -0
  167. package/src/pages/product-list/product-list-context.tsx +302 -0
  168. package/src/pages/product-list/product-list-state.ts +187 -0
  169. package/src/pages/product-list/product-rating.tsx +16 -0
  170. package/src/pages/product-list/quick-view-dialog-content.tsx +205 -0
  171. package/src/pages/product-list/quick-view-dialog.tsx +54 -0
  172. package/src/pages/product-list/range-filter.tsx +125 -0
  173. package/src/pages/product-list/scrollbar.tsx +38 -0
  174. package/src/pages/product-list/search-bar.tsx +162 -0
  175. package/src/pages/product-list/selected-facets.tsx +80 -0
  176. package/src/pages/product-list/side-nav.tsx +49 -0
  177. package/src/pages/product-list/swatch.tsx +80 -0
  178. package/src/pages/product-list/types.ts +18 -0
  179. package/src/pages/product-list/use-product-list.ts +12 -0
  180. package/src/pages/product-list/useCategoryFilter.tsx +26 -0
  181. package/src/pages/product-list/utils/facet-helpers.ts +5 -0
  182. package/src/pages/product-list/utils/generate-breadcrumbs.ts +30 -0
  183. package/src/pages/product-list/utils/getCategoryFilterFromSlug.ts +153 -0
  184. package/src/pages/product-list/utils/product-list-helper.ts +111 -0
  185. package/src/pages/product-list/utils/product-list-types.ts +41 -0
  186. package/src/pages/product-list/utils/search-for-category.ts +76 -0
  187. package/src/pages/product-list/utils/sort-options.ts +44 -0
  188. package/src/pages/product-list/utils/use-previous-refiners.ts +14 -0
  189. package/src/pages/quickorder/order-upload.tsx +150 -0
  190. package/src/pages/quickorder/quick-order-form.tsx +343 -0
  191. package/src/pages/quickorder/quick-order-row.tsx +144 -0
  192. package/tsconfig.json +1 -0
  193. package/src/api-manager/datasources/e4/graphqlRequestSdk.ts +0 -43515
  194. package/src/config.ts +0 -47
  195. /package/src/{components/_components/hooks/useOverflowDetect.ts → hooks/use-overflow-detect.ts} +0 -0
  196. /package/src/{components/_components/hooks/useSettings.ts → hooks/use-settings.ts} +0 -0
@@ -0,0 +1,37 @@
1
+ import IconButton from "@mui/material/IconButton";
2
+ // MUI ICON COMPONENTS
3
+ import Favorite from "@mui/icons-material/Favorite";
4
+ import RemoveRedEye from "@mui/icons-material/RemoveRedEye";
5
+ import FavoriteBorder from "@mui/icons-material/FavoriteBorder";
6
+ // STYLED COMPONENTS
7
+ import { HoverIconWrapper } from "../styles";
8
+
9
+ // ==============================================================
10
+ interface Props {
11
+ isFavorite: boolean;
12
+ toggleView: () => void;
13
+ toggleFavorite: () => void;
14
+ }
15
+ // ==============================================================
16
+
17
+ export default function HoverActions({
18
+ isFavorite,
19
+ toggleFavorite,
20
+ toggleView,
21
+ }: Props) {
22
+ return (
23
+ <HoverIconWrapper className="hover-box">
24
+ <IconButton onClick={toggleView}>
25
+ <RemoveRedEye color="disabled" fontSize="small" />
26
+ </IconButton>
27
+
28
+ <IconButton onClick={toggleFavorite}>
29
+ {isFavorite ? (
30
+ <Favorite color="primary" fontSize="small" />
31
+ ) : (
32
+ <FavoriteBorder fontSize="small" color="disabled" />
33
+ )}
34
+ </IconButton>
35
+ </HoverIconWrapper>
36
+ );
37
+ }
@@ -0,0 +1 @@
1
+ export { default } from "./product-card";
@@ -0,0 +1,118 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import Box from "@mui/material/Box";
5
+ import Rating from "@mui/material/Rating";
6
+ // GLOBAL CUSTOM COMPONENTS
7
+ import ProductViewDialog from "@/_components/products-view/product-view-dialog";
8
+ import { Span } from "@/_components/Typography";
9
+ // LOCAL CUSTOM HOOK
10
+ import useProduct from "../use-product";
11
+ // LOCAL CUSTOM COMPONENTS
12
+ import HoverActions from "./components/hover-actions";
13
+ import ProductPrice from "../product-price";
14
+ import ProductTitle from "../product-title";
15
+ import DiscountChip from "../discount-chip";
16
+ // STYLED COMPONENTS
17
+ import { ImageWrapper, ContentWrapper, StyledBazaarCard } from "./styles";
18
+ import { IconButton } from "@mui/material";
19
+ import { Delete } from "@mui/icons-material";
20
+ import LazyImage from "@/_components/LazyImage";
21
+
22
+ // ========================================================
23
+ type Props = {
24
+ title: string;
25
+ slug: string;
26
+ price: number;
27
+ imgUrl: string;
28
+ rating?: number;
29
+ discount?: number;
30
+ id: string | number;
31
+ hideRating?: boolean;
32
+ hoverEffect?: boolean;
33
+ showProductSize?: boolean;
34
+ lineId: string | undefined;
35
+ handleRemoveProductFromWishlist: (linedId: string | undefined) => void;
36
+ };
37
+ // ========================================================
38
+
39
+ export default function ProductCardWishlist({
40
+ id,
41
+ slug,
42
+ title,
43
+ price,
44
+ imgUrl,
45
+ rating = 5,
46
+ hideRating,
47
+ hoverEffect,
48
+ discount = 5,
49
+ showProductSize,
50
+ lineId,
51
+ handleRemoveProductFromWishlist,
52
+ }: Props) {
53
+ const { isFavorite, openModal, toggleDialog, toggleFavorite } =
54
+ useProduct(slug);
55
+
56
+ return (
57
+ <StyledBazaarCard hoverEffect={hoverEffect}>
58
+ <ImageWrapper>
59
+ {/* DISCOUNT PERCENT CHIP IF AVAILABLE */}
60
+ <DiscountChip discount={discount} />
61
+
62
+ {/* HOVER ACTION ICONS */}
63
+ <HoverActions
64
+ isFavorite={isFavorite}
65
+ toggleView={toggleDialog}
66
+ toggleFavorite={toggleFavorite}
67
+ />
68
+
69
+ {/* PRODUCT IMAGE / THUMBNAIL */}
70
+ <Link href={`/products/${slug}`}>
71
+ <LazyImage
72
+ priority
73
+ src={imgUrl}
74
+ width={500}
75
+ height={500}
76
+ alt={title}
77
+ />
78
+ </Link>
79
+ </ImageWrapper>
80
+
81
+ {/* PRODUCT VIEW DIALOG BOX */}
82
+ <ProductViewDialog
83
+ openDialog={openModal}
84
+ handleCloseDialog={toggleDialog}
85
+ product={{ title, price, id, slug, imgGroup: [imgUrl, imgUrl] }}
86
+ />
87
+
88
+ <ContentWrapper>
89
+ <Box flex="1 1 0" minWidth="0px" mr={1}>
90
+ {/* PRODUCT NAME / TITLE */}
91
+ <ProductTitle title={title} slug={slug} />
92
+
93
+ {/* PRODUCT RATINGS IF AVAILABLE */}
94
+ {!hideRating ? (
95
+ <Rating size="small" value={rating} color="warn" readOnly />
96
+ ) : null}
97
+
98
+ {/* PRODUCT SIZE IF AVAILABLE */}
99
+ {showProductSize ? (
100
+ <Span color="grey.600" mb={1} display="block">
101
+ Liter
102
+ </Span>
103
+ ) : null}
104
+
105
+ {/* PRODUCT PRICE WITH DISCOUNT */}
106
+ <ProductPrice discount={discount} price={price} />
107
+ </Box>
108
+
109
+ {/* PRODUCT QUANTITY HANDLER BUTTONS */}
110
+ <Box display="flex" alignItems="center" gap={1} justifySelf="end">
111
+ <IconButton onClick={() => handleRemoveProductFromWishlist(lineId)}>
112
+ <Delete fontSize="small" color="inherit" />
113
+ </IconButton>
114
+ </Box>
115
+ </ContentWrapper>
116
+ </StyledBazaarCard>
117
+ );
118
+ }
@@ -0,0 +1,51 @@
1
+ import BazaarCard, { Props } from "@/_components/BazaarCard";
2
+ import styled from "@mui/material/styles/styled";
3
+ // GLOBAL CUSTOM COMPONENT
4
+ import React, { ComponentType } from "react";
5
+
6
+ export const StyledBazaarCard: ComponentType<Props> = styled(BazaarCard)({
7
+ height: "100%",
8
+ margin: "auto",
9
+ display: "flex",
10
+ overflow: "hidden",
11
+ borderRadius: "8px",
12
+ position: "relative",
13
+ flexDirection: "column",
14
+ justifyContent: "space-between",
15
+ transition: "all 250ms ease-in-out",
16
+ ":hover": { "& .hover-box": { opacity: 1 } },
17
+ });
18
+
19
+ export const ImageWrapper: ComponentType<React.ComponentProps<"div">> = styled(
20
+ "div",
21
+ )(({ theme }) => ({
22
+ textAlign: "center",
23
+ position: "relative",
24
+ display: "inline-block",
25
+ [theme.breakpoints.down("sm")]: { display: "block" },
26
+ }));
27
+
28
+ export const HoverIconWrapper: ComponentType<React.ComponentProps<"div">> =
29
+ styled("div")({
30
+ zIndex: 2,
31
+ top: "7px",
32
+ opacity: 0,
33
+ right: "15px",
34
+ display: "flex",
35
+ cursor: "pointer",
36
+ position: "absolute",
37
+ flexDirection: "column",
38
+ transition: "all 0.3s ease-in-out",
39
+ });
40
+
41
+ export const ContentWrapper: ComponentType<React.ComponentProps<"div">> =
42
+ styled("div")({
43
+ gap: 8,
44
+ display: "flex",
45
+ padding: "1rem",
46
+ "& .title, & .categories": {
47
+ overflow: "hidden",
48
+ whiteSpace: "nowrap",
49
+ textOverflow: "ellipsis",
50
+ },
51
+ });
@@ -0,0 +1,114 @@
1
+ "use client";
2
+ import Box from "@mui/material/Box";
3
+ import Chip from "@mui/material/Chip";
4
+ import { H6 } from "@/components/_components/Typography";
5
+
6
+ import {
7
+ ProductDimensionType,
8
+ ProductDimensionValueInventoryAvailability,
9
+ } from "@msdyn365-commerce/retail-proxy";
10
+ import { useTranslations } from "next-intl";
11
+
12
+ // ================================================================
13
+ type Props = {
14
+ dimensionGroups: ProductDimensionValueInventoryAvailability[][];
15
+ selectDimensions: Record<number, ProductDimensionValueInventoryAvailability>;
16
+ handleChangeVariant: (
17
+ dimension: ProductDimensionValueInventoryAvailability,
18
+ ) => void;
19
+ showDimensionError?: boolean;
20
+ };
21
+ // ================================================================
22
+
23
+ export default function ProductDimensions({
24
+ dimensionGroups,
25
+ selectDimensions,
26
+ handleChangeVariant,
27
+ showDimensionError,
28
+ }: Props) {
29
+ const t = useTranslations("productDetail.Dimensions");
30
+ const hasSelectedDimension = (
31
+ dimension: ProductDimensionValueInventoryAvailability[],
32
+ ) => {
33
+ return dimension.some((dim) =>
34
+ Object.values(selectDimensions).some(
35
+ (selectedDimension) =>
36
+ selectedDimension.DimensionValue?.RecordId ===
37
+ dim.DimensionValue?.RecordId,
38
+ ),
39
+ );
40
+ };
41
+
42
+ return (
43
+ <>
44
+ {Array.isArray(dimensionGroups) &&
45
+ dimensionGroups.map((dimensions, i) => (
46
+ <Box key={i} mb={2}>
47
+ <H6 mb={1}>
48
+ {ProductDimensionType[dimensions[0]?.DimensionTypeValue || 0]}
49
+ </H6>
50
+ {dimensions.map((dimension) => {
51
+ // CHECK STOCK
52
+ const disabled =
53
+ dimension.TotalAvailableInventoryLevelCode !== "AVAIL";
54
+ const selected =
55
+ selectDimensions[dimension.DimensionTypeValue || 0]
56
+ ?.DimensionValue === dimension.DimensionValue;
57
+
58
+ // SWATCH DIMENSIONS
59
+ if (
60
+ ProductDimensionType[dimension.DimensionTypeValue || 0] ===
61
+ "Color"
62
+ ) {
63
+ return (
64
+ <Chip
65
+ key={dimension.DimensionValue?.RecordId}
66
+ onClick={() => {
67
+ handleChangeVariant(dimension);
68
+ }}
69
+ disabled={disabled}
70
+ sx={{
71
+ borderRadius: "100%",
72
+ mr: 1,
73
+ cursor: "pointer",
74
+ backgroundColor: dimension.DimensionValue?.Value,
75
+ width: 32,
76
+ height: 32,
77
+ border: selected ? "2px solid" : "2px solid transparent",
78
+ "&:hover": {
79
+ backgroundColor: dimension.DimensionValue?.Value,
80
+ },
81
+ }}
82
+ />
83
+ );
84
+ }
85
+
86
+ // TEXT DIMENSIONS
87
+ return (
88
+ <Chip
89
+ key={dimension.DimensionValue?.RecordId}
90
+ label={dimension.DimensionValue?.Value}
91
+ onClick={() => {
92
+ handleChangeVariant(dimension);
93
+ }}
94
+ disabled={disabled}
95
+ sx={{ borderRadius: "4px", mr: 1, cursor: "pointer", mb: 1 }}
96
+ color={selected ? "primary" : "default"}
97
+ />
98
+ );
99
+ })}
100
+ {showDimensionError && !hasSelectedDimension(dimensions) && (
101
+ <H6 color="error.main" mb={1}>
102
+ {t("selectError", {
103
+ dimension:
104
+ ProductDimensionType[
105
+ dimensions[0]?.DimensionTypeValue || 0
106
+ ],
107
+ })}
108
+ </H6>
109
+ )}
110
+ </Box>
111
+ ))}
112
+ </>
113
+ );
114
+ }
@@ -0,0 +1,88 @@
1
+ import React from "react";
2
+ import { FlexBox } from "@/components/_components/flex-box";
3
+ import Button from "@mui/material/Button";
4
+ import { H3 } from "@/components/_components/Typography";
5
+ import { MdAdd as Add } from "react-icons/md";
6
+ import { MdRemove as Remove } from "react-icons/md";
7
+ import CircularProgress from "@mui/material/CircularProgress";
8
+ import { CartLine } from "@msdyn365-commerce/retail-proxy";
9
+ import { useTranslations } from "next-intl";
10
+
11
+ interface Props {
12
+ loading: boolean;
13
+ productCartLine: CartLine | undefined;
14
+ handleCartAmountChange: (amount: number, currentCartLine: CartLine) => void;
15
+ handleAddToCart: () => void;
16
+ isOOS: boolean;
17
+ }
18
+
19
+ export default function QuantityButtons({
20
+ loading,
21
+ handleAddToCart,
22
+ handleCartAmountChange,
23
+ productCartLine,
24
+ isOOS,
25
+ }: Props) {
26
+ const t = useTranslations("productDetail");
27
+
28
+ if (!productCartLine?.Quantity || productCartLine.Quantity === 0) {
29
+ return (
30
+ <Button
31
+ color="primary"
32
+ variant="contained"
33
+ onClick={handleAddToCart}
34
+ disabled={isOOS}
35
+ >
36
+ {t("btnAddToCart")}
37
+ </Button>
38
+ );
39
+ }
40
+
41
+ return (
42
+ <FlexBox alignItems="center">
43
+ <Button
44
+ size="small"
45
+ sx={{ p: 1 }}
46
+ color="primary"
47
+ variant="outlined"
48
+ disabled={loading}
49
+ onClick={() =>
50
+ handleCartAmountChange(
51
+ (productCartLine?.Quantity || 0) - 1,
52
+ productCartLine,
53
+ )
54
+ }
55
+ >
56
+ <Remove fontSize="small" />
57
+ </Button>
58
+
59
+ <H3
60
+ fontWeight="600"
61
+ mx={2.5}
62
+ sx={{ width: "20px", display: "flex", justifyContent: "center" }}
63
+ >
64
+ {loading ? (
65
+ <CircularProgress size={"10px"} />
66
+ ) : (
67
+ productCartLine.Quantity.toString().padStart(2, "0")
68
+ )}
69
+ </H3>
70
+
71
+ <Button
72
+ size="small"
73
+ sx={{ p: 1 }}
74
+ color="primary"
75
+ variant="outlined"
76
+ disabled={loading}
77
+ onClick={() =>
78
+ handleCartAmountChange(
79
+ (productCartLine?.Quantity || 0) + 1,
80
+ productCartLine,
81
+ )
82
+ }
83
+ >
84
+ <Add fontSize="small" />
85
+ </Button>
86
+ </FlexBox>
87
+ );
88
+ }
@@ -9,20 +9,24 @@ import DialogContent from "@mui/material/DialogContent";
9
9
  import Add from "@mui/icons-material/Add";
10
10
  import Close from "@mui/icons-material/Close";
11
11
  import Remove from "@mui/icons-material/Remove";
12
- // GLOBAL CUSTOM COMPONENTS
13
- import { Carousel } from "@/components/_components/carousel/index";
14
- import BazaarImage from "@/components/_components/BazaarImage";
15
- import FlexBox from "@/components/_components/flex-box/flex-box";
16
- import { H1, H2, H3, H6, Paragraph } from "@/components/_components/Typography";
12
+ // GLOBAL CUSTOM COMPONENT
17
13
  // LOCAL CUSTOM HOOKS
18
- //import useCart from "hooks/useCart";
14
+ import useAddToCart from "@/api-manager/services/cart/mutations/add-to-cart";
15
+ import { useTranslations } from "next-intl";
16
+ import getCart from "@/api-manager/services/cart/queries/get-cart";
19
17
  // CUSTOM UTILS LIBRARY FUNCTION
18
+ import { Carousel } from "../carousel";
19
+ import { useNotification } from "@/components/Notifications/use-notification";
20
+ import BazaarImage from "../BazaarImage";
21
+ import { FlexBox } from "../flex-box";
22
+ import { H2, Paragraph, H1, H6, H3 } from "../Typography";
20
23
  import { currency } from "@/lib/lib";
21
24
 
22
25
  // =====================================================
23
26
  interface Props {
24
27
  product: ProductInfo;
25
28
  openDialog: boolean;
29
+ cartId?: string;
26
30
  handleCloseDialog: () => void;
27
31
  }
28
32
  // =====================================================
@@ -31,7 +35,7 @@ type CartItem = {
31
35
  qty: number;
32
36
  };
33
37
  // =====================================================
34
- type ProductInfo = {
38
+ export type ProductInfo = {
35
39
  id: string | number;
36
40
  title: string;
37
41
  imgGroup: string[];
@@ -50,7 +54,12 @@ type CartDispatch = {
50
54
  // =====================================================
51
55
 
52
56
  export default function ProductViewDialog(props: Props) {
53
- const { product, openDialog, handleCloseDialog } = props;
57
+ const { product, openDialog, cartId, handleCloseDialog } = props;
58
+ const { mutateAsync: addToCart } = useAddToCart();
59
+ const { data: cart } = getCart.useData();
60
+
61
+ const t = useTranslations("ProductViewDialog");
62
+ const { setNotification } = useNotification();
54
63
 
55
64
  //const { state, dispatch } = useCart();
56
65
  const state: { cart: CartItem[] } = {
@@ -73,6 +82,31 @@ export default function ProductViewDialog(props: Props) {
73
82
  });
74
83
  };
75
84
 
85
+ const handleAddToCart = async () => {
86
+ if (!cart) return;
87
+ try {
88
+ await addToCart({
89
+ cartId: cartId,
90
+ version: cart.Version,
91
+ cartLine: [
92
+ {
93
+ ProductId: Number(product.id),
94
+ Quantity: 1,
95
+ },
96
+ ],
97
+ });
98
+ setNotification({
99
+ message: t("addToCartSuccess"),
100
+ severity: "success",
101
+ });
102
+ } catch (error) {
103
+ setNotification({
104
+ message: t("addToCartError"),
105
+ severity: "error",
106
+ });
107
+ }
108
+ };
109
+
76
110
  return (
77
111
  <Dialog
78
112
  open={openDialog}
@@ -133,16 +167,19 @@ export default function ProductViewDialog(props: Props) {
133
167
  {!cartItem?.qty ? (
134
168
  <Button
135
169
  size="large"
170
+ color={"primary"}
136
171
  variant="contained"
137
- onClick={handleCartAmountChange(1)}
172
+ // onClick={handleCartAmountChange(1)}
173
+ onClick={handleAddToCart}
138
174
  sx={{ height: 45, borderRadius: 2 }}
139
175
  >
140
- Add to Cart
176
+ {t("addToCartBtn")}
141
177
  </Button>
142
178
  ) : (
143
179
  <FlexBox alignItems="center">
144
180
  <Button
145
181
  size="small"
182
+ color={"primary"}
146
183
  variant="outlined"
147
184
  sx={{ p: ".6rem", height: 45 }}
148
185
  onClick={handleCartAmountChange(cartItem?.qty - 1)}
@@ -156,6 +193,7 @@ export default function ProductViewDialog(props: Props) {
156
193
 
157
194
  <Button
158
195
  size="small"
196
+ color={"primary"}
159
197
  variant="outlined"
160
198
  sx={{ p: ".6rem", height: 45 }}
161
199
  onClick={handleCartAmountChange(cartItem?.qty + 1)}
@@ -5,30 +5,44 @@ import { FlexBetween } from "@/components/_components/flex-box/index";
5
5
  import ProductCard16 from "@/components/_components/product-cards/product-card-16/index";
6
6
  // DATA MODEL
7
7
  import { ProductSearchResult as Product } from "@msdyn365-commerce/retail-proxy";
8
+ import { ProductPrice } from "@/api-manager/schemas/product.schema";
8
9
 
9
10
  // ========================================================
10
- type Props = { products: Product[]; pagination?: ReactNode };
11
+ type Props = {
12
+ products: Product[];
13
+ pagination?: ReactNode;
14
+ productPrices?: ProductPrice[];
15
+ };
11
16
  // ========================================================
12
17
 
13
- export default function ProductsGridView({ products, pagination }: Props) {
18
+ export default function ProductsGridView({
19
+ products,
20
+ pagination,
21
+ productPrices,
22
+ }: Props) {
14
23
  return (
15
24
  <Fragment>
16
25
  <Grid container spacing={3}>
17
- {products.map((item: Product) => (
18
- <Grid size={{ lg: 4, sm: 6, xs: 12 }} key={item.ItemId}>
19
- <ProductCard16
20
- id={item.RecordId}
21
- key={item.RecordId}
22
- slug={item.ItemId ?? ""}
23
- title={item.Name ?? ""}
24
- price={item.Price ?? 0}
25
- discount={0} // Need to get discount info for product.
26
- rating={item.TotalRatings ?? 0}
27
- imgUrl={item.PrimaryImageUrl ?? ""}
28
- showAddToCart={false}
29
- />
30
- </Grid>
31
- ))}
26
+ {products.map((item: Product) => {
27
+ const matchingPrice = productPrices?.find(
28
+ (price) => price.ProductId === item.RecordId,
29
+ );
30
+ return (
31
+ <Grid size={{ lg: 4, sm: 6, xs: 12 }} key={item.ItemId}>
32
+ <ProductCard16
33
+ id={item.RecordId}
34
+ key={item.RecordId}
35
+ slug={item.ItemId ?? ""}
36
+ title={item.Name ?? ""}
37
+ price={matchingPrice?.CustomerContextualPrice ?? null}
38
+ discount={0} // Need to get discount info for product.
39
+ rating={item.TotalRatings ?? 0}
40
+ imgUrl={item.PrimaryImageUrl ?? ""}
41
+ showAddToCart={false}
42
+ />
43
+ </Grid>
44
+ );
45
+ })}
32
46
  </Grid>
33
47
 
34
48
  <FlexBetween flexWrap="wrap" mt={6}>
@@ -4,28 +4,42 @@ import FlexBetween from "@/components/_components/flex-box/flex-between";
4
4
  import { ProductCard9 } from "@/components/_components/product-cards/product-card-9/index";
5
5
  // DATA MODEL
6
6
  import { ProductSearchResult as Product } from "@msdyn365-commerce/retail-proxy";
7
+ import { ProductPrice } from "@/api-manager/schemas/product.schema";
7
8
 
8
9
  // ==========================================================
9
- type Props = { products: Product[]; pagination?: ReactNode };
10
+ type Props = {
11
+ products: Product[];
12
+ pagination?: ReactNode;
13
+ productPrices?: ProductPrice[];
14
+ };
10
15
  // ==========================================================
11
16
 
12
- export default function ProductsListView({ products, pagination }: Props) {
17
+ export default function ProductsListView({
18
+ products,
19
+ pagination,
20
+ productPrices,
21
+ }: Props) {
13
22
  return (
14
23
  <div>
15
- {products.map((item) => (
16
- <ProductCard9
17
- id={item.RecordId}
18
- key={item.RecordId}
19
- slug={item.ItemId ?? ""}
20
- title={item.Name ?? ""}
21
- price={item.Price}
22
- off={0} // Need to get discount info for product.
23
- rating={item.TotalRatings ?? 0}
24
- imgUrl={item.PrimaryImageUrl ?? ""}
25
- showAddToCart={false}
26
- showFavorite={false}
27
- />
28
- ))}
24
+ {products.map((item) => {
25
+ const matchingPrice = productPrices?.find(
26
+ (price) => price.ProductId === item.RecordId,
27
+ );
28
+ return (
29
+ <ProductCard9
30
+ id={item.RecordId}
31
+ key={item.RecordId}
32
+ slug={item.ItemId ?? ""}
33
+ title={item.Name ?? ""}
34
+ price={matchingPrice?.CustomerContextualPrice ?? null}
35
+ off={0} // Need to get discount info for product.
36
+ rating={item.TotalRatings ?? 0}
37
+ imgUrl={item.PrimaryImageUrl ?? ""}
38
+ showAddToCart={false}
39
+ showFavorite={false}
40
+ />
41
+ );
42
+ })}
29
43
 
30
44
  <FlexBetween flexWrap="wrap" mt={4}>
31
45
  {pagination}