@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
@@ -6,51 +6,60 @@ import Remove from "@mui/icons-material/Remove";
6
6
  // GLOBAL CUSTOM COMPONENTS
7
7
  import { FlexBox } from "@/components/_components/flex-box/index";
8
8
  import { Paragraph } from "@/components/_components/Typography";
9
+ import { CircularProgress } from "@mui/material";
9
10
 
10
11
  // ==============================================================
11
12
  interface Props {
12
13
  quantity: number;
13
14
  handleDecrement: () => void;
14
15
  handleIncrement: () => void;
16
+ isLineUpdating: boolean;
15
17
  }
16
18
  // ==============================================================
17
19
 
18
20
  export default function QuantityButtons(props: Props) {
19
- const { quantity, handleDecrement, handleIncrement } = props || {};
21
+ const { quantity, handleDecrement, handleIncrement, isLineUpdating } =
22
+ props || {};
20
23
 
21
24
  return (
22
25
  <FlexBox
23
- width="30px"
24
26
  alignItems="center"
25
27
  className="add-cart"
26
- flexDirection="column-reverse"
28
+ flexDirection="row-reverse"
27
29
  justifyContent={quantity ? "space-between" : "flex-start"}
30
+ gap={1}
28
31
  >
29
32
  <Button
30
33
  color="primary"
31
34
  variant="outlined"
32
35
  onClick={handleIncrement}
33
36
  sx={{ padding: "3px" }}
37
+ disabled={isLineUpdating}
34
38
  >
35
39
  <Add fontSize="small" />
36
40
  </Button>
37
41
 
38
- {quantity ? (
42
+ {quantity && (
39
43
  <Fragment>
40
- <Paragraph color="text.primary" fontWeight="600">
41
- {quantity}
42
- </Paragraph>
44
+ {isLineUpdating ? (
45
+ <CircularProgress size={"10px"} color={"primary"} />
46
+ ) : (
47
+ <Paragraph color="text.primary" fontWeight="600">
48
+ {quantity}
49
+ </Paragraph>
50
+ )}
43
51
 
44
52
  <Button
45
53
  color="primary"
46
54
  variant="outlined"
47
55
  onClick={handleDecrement}
48
56
  sx={{ padding: "3px" }}
57
+ disabled={isLineUpdating}
49
58
  >
50
59
  <Remove fontSize="small" />
51
60
  </Button>
52
61
  </Fragment>
53
- ) : null}
62
+ )}
54
63
  </FlexBox>
55
64
  );
56
65
  }
@@ -0,0 +1,304 @@
1
+ "use client";
2
+
3
+ import { IconButton } from "@mui/material";
4
+ import ProductCard1 from "./product-card";
5
+ import { Delete, ShoppingCart } from "@mui/icons-material";
6
+ import {
7
+ ExtendedProductListLine,
8
+ ExtendedWishlist,
9
+ WishlistLinesInput,
10
+ } from "@/api-manager/schemas/user.schema";
11
+ import { useTranslations } from "next-intl";
12
+ import useRemoveFromWishlist from "@/api-manager/services/user/mutations/remove-from-wishlist";
13
+ import HoverActions from "./components/hover-actions";
14
+ import { useState } from "react";
15
+ import useUpdateWishlist from "@/api-manager/services/user/mutations/update-wishlist";
16
+ import useAddToCart from "@/api-manager/services/cart/mutations/add-to-cart";
17
+ import { Cart } from "@/api-manager/schemas/cart.schema";
18
+ import { FlexBox } from "@/_components/flex-box";
19
+ import AddToWishlistDialog from "@/_components/wishlist/add-to-wishlist-dialog";
20
+ import RemoveFromWishlistDialog from "@/_components/wishlist/remove-from-wishlist-dialog";
21
+ import ProductViewDialog from "@/_components/products-view/product-view-dialog";
22
+ import { useNotification } from "@/components/Notifications/use-notification";
23
+
24
+ type Props = {
25
+ title: string;
26
+ slug: string;
27
+ price: number;
28
+ imgUrl: string;
29
+ rating?: number;
30
+ discount?: number;
31
+ id: string | number;
32
+ hideRating?: boolean;
33
+ hoverEffect?: boolean;
34
+ showProductSize?: boolean;
35
+ mode: "PLP" | "WishlistDetail";
36
+ isFavorite?: boolean; // when called from PLP, whether the product is in a wishlist
37
+ wishlist?: ExtendedWishlist; // when called from wishlist detail page
38
+ cart?: Cart; // for adding wishlist item to cart in wishlist detail page
39
+ };
40
+ export default function ProductCard1Wrapper({
41
+ id,
42
+ slug,
43
+ title,
44
+ price,
45
+ imgUrl,
46
+ rating = 5,
47
+ hideRating,
48
+ hoverEffect,
49
+ discount = 5,
50
+ showProductSize,
51
+ mode,
52
+ isFavorite,
53
+ wishlist,
54
+ cart,
55
+ }: Props) {
56
+ const t = useTranslations("Account.Wishlists");
57
+ const { setNotification } = useNotification();
58
+ const { mutateAsync: removeFromWishlist } = useRemoveFromWishlist();
59
+ const { mutateAsync: updateWishlist } = useUpdateWishlist();
60
+ const [favorite, setFavorite] = useState(isFavorite || false);
61
+ const [openAddToWishlistDialog, setOpenAddToWishlistDialog] = useState(false);
62
+ const [openRemoveFromWishlistDialog, setOpenRemoveFromWishlistDialog] =
63
+ useState(false);
64
+ const [openProductModal, setOpenProductModal] = useState(false);
65
+ const [quantity, setQuantity] = useState(
66
+ wishlist?.ProductListLines?.find(
67
+ (item: ExtendedProductListLine) => item.ProductId === id,
68
+ )?.Quantity || 0,
69
+ );
70
+ const [isLineUpdating, setIsLineUpdating] = useState(false);
71
+ const { mutateAsync: addToCart } = useAddToCart();
72
+
73
+ const handleRemoveFromWishlist = async (productId: string | number) => {
74
+ try {
75
+ const extendedWishlistLine = wishlist?.ProductListLines?.find(
76
+ (item: ExtendedProductListLine) => item.ProductId === productId,
77
+ );
78
+
79
+ if (extendedWishlistLine && wishlist) {
80
+ const { ...wishlistLine } = extendedWishlistLine;
81
+ delete wishlistLine.Product;
82
+
83
+ const wishlistLinesInput: WishlistLinesInput = {
84
+ Id: wishlist.Id,
85
+ ProductListLines: [wishlistLine],
86
+ };
87
+
88
+ await removeFromWishlist(wishlistLinesInput);
89
+ setNotification({
90
+ message: t("wishlistLineRemoveSuccess"),
91
+ severity: "success",
92
+ });
93
+ }
94
+ } catch (error) {
95
+ setNotification({
96
+ message: t("wishlistLineRemoveFailed"),
97
+ severity: "error",
98
+ });
99
+ }
100
+ };
101
+
102
+ const handleToggleFavorite = () => {
103
+ if (favorite) {
104
+ setOpenRemoveFromWishlistDialog(true);
105
+ } else {
106
+ setOpenAddToWishlistDialog(true);
107
+ }
108
+ };
109
+
110
+ const handleToggleProductModal = () => {
111
+ setOpenProductModal(!openProductModal);
112
+ };
113
+
114
+ const handleCloseDialog = () => {
115
+ setOpenAddToWishlistDialog(false);
116
+ setOpenRemoveFromWishlistDialog(false);
117
+ };
118
+
119
+ const handleAddRemoveSuccess = () => {
120
+ setFavorite(!favorite);
121
+ };
122
+
123
+ const handleWishlistIncrementQuantity = async () => {
124
+ setIsLineUpdating(true);
125
+ // update wishlist product list lines
126
+ if (mode === "WishlistDetail" && wishlist && wishlist.ProductListLines) {
127
+ try {
128
+ const updatedProductListLines = wishlist.ProductListLines.map(
129
+ (line) => {
130
+ const { ...wishlistLine } = line;
131
+ delete wishlistLine.Product;
132
+ if (line.ProductId === Number(id)) {
133
+ return {
134
+ ...wishlistLine,
135
+ Quantity: quantity + 1,
136
+ };
137
+ }
138
+ return wishlistLine;
139
+ },
140
+ );
141
+ await updateWishlist({
142
+ Id: wishlist.Id,
143
+ ProductListLines: updatedProductListLines,
144
+ });
145
+ setQuantity(quantity + 1);
146
+ } catch (error) {
147
+ // Do nothing
148
+ }
149
+ } else {
150
+ // PLP mode
151
+ setQuantity(quantity + 1);
152
+ }
153
+ setIsLineUpdating(false);
154
+ };
155
+
156
+ const handleWishlistDecrementQuantity = async () => {
157
+ setIsLineUpdating(true);
158
+ // update wishlist product list lines
159
+ if (
160
+ mode === "WishlistDetail" &&
161
+ wishlist &&
162
+ wishlist.ProductListLines &&
163
+ quantity > 0
164
+ ) {
165
+ try {
166
+ const updatedProductListLines = wishlist.ProductListLines.map(
167
+ (line) => {
168
+ const { ...wishlistLine } = line;
169
+ delete wishlistLine.Product;
170
+ if (line.ProductId === Number(id)) {
171
+ return {
172
+ ...wishlistLine,
173
+ Quantity: quantity - 1,
174
+ };
175
+ }
176
+ return wishlistLine;
177
+ },
178
+ );
179
+ await updateWishlist({
180
+ Id: wishlist.Id,
181
+ ProductListLines: updatedProductListLines,
182
+ });
183
+ setQuantity(quantity - 1);
184
+ } catch (error) {
185
+ // Do nothing
186
+ }
187
+ } else {
188
+ // PLP mode
189
+ setQuantity(quantity - 1);
190
+ }
191
+ setIsLineUpdating(false);
192
+ };
193
+
194
+ const handleAddItemToCart = async () => {
195
+ if (!cart) return;
196
+ try {
197
+ await addToCart({
198
+ cartId: cart.Id,
199
+ version: cart.Version,
200
+ cartLine: [
201
+ {
202
+ ProductId: Number(id),
203
+ Quantity: quantity,
204
+ },
205
+ ],
206
+ });
207
+ setNotification({
208
+ message: "Successfully added item to cart",
209
+ severity: "success",
210
+ });
211
+ } catch (error) {
212
+ setNotification({
213
+ message: "Failed to add item to cart",
214
+ severity: "error",
215
+ });
216
+ }
217
+ };
218
+
219
+ // render wishlist controls depending on mode
220
+ const wishlistControls =
221
+ mode === "WishlistDetail" ? (
222
+ // render delete button
223
+ <>
224
+ <FlexBox
225
+ width="25px"
226
+ alignItems="center"
227
+ flexDirection="row-reverse"
228
+ justifyContent="space-between"
229
+ >
230
+ <IconButton
231
+ sx={{ padding: "3px" }}
232
+ onClick={() => handleAddItemToCart()}
233
+ >
234
+ <ShoppingCart fontSize="small" color="inherit" />
235
+ </IconButton>
236
+ </FlexBox>
237
+ <FlexBox
238
+ width="25px"
239
+ alignItems="center"
240
+ flexDirection="row-reverse"
241
+ justifyContent="space-between"
242
+ >
243
+ <IconButton
244
+ sx={{ padding: "3px" }}
245
+ onClick={() => handleRemoveFromWishlist(id)}
246
+ >
247
+ <Delete fontSize="small" color="inherit" />
248
+ </IconButton>
249
+ </FlexBox>
250
+ </>
251
+ ) : (
252
+ // render hover actions for PLP
253
+ <HoverActions
254
+ isFavorite={favorite}
255
+ toggleView={handleToggleProductModal}
256
+ toggleFavorite={handleToggleFavorite}
257
+ />
258
+ );
259
+
260
+ return (
261
+ <>
262
+ <ProductCard1
263
+ id={id}
264
+ slug={slug}
265
+ title={title}
266
+ price={price}
267
+ imgUrl={imgUrl}
268
+ rating={rating}
269
+ hideRating={hideRating}
270
+ hoverEffect={hoverEffect}
271
+ discount={discount}
272
+ showProductSize={showProductSize}
273
+ wishlistControls={wishlistControls}
274
+ quantity={quantity}
275
+ isLineUpdating={isLineUpdating}
276
+ handleIncrementQuantity={handleWishlistIncrementQuantity}
277
+ handleDecrementQuantity={handleWishlistDecrementQuantity}
278
+ />
279
+ {openAddToWishlistDialog && (
280
+ <AddToWishlistDialog
281
+ open={openAddToWishlistDialog}
282
+ handleClose={handleCloseDialog}
283
+ productId={Number(id)}
284
+ onSuccess={handleAddRemoveSuccess}
285
+ />
286
+ )}
287
+ {openRemoveFromWishlistDialog && (
288
+ <RemoveFromWishlistDialog
289
+ open={openRemoveFromWishlistDialog}
290
+ handleClose={handleCloseDialog}
291
+ productId={Number(id)}
292
+ onSuccess={handleAddRemoveSuccess}
293
+ />
294
+ )}
295
+ {openProductModal && (
296
+ <ProductViewDialog
297
+ openDialog={openProductModal || false}
298
+ handleCloseDialog={handleToggleProductModal}
299
+ product={{ title, price, id, slug, imgGroup: [imgUrl, imgUrl] }}
300
+ />
301
+ )}
302
+ </>
303
+ );
304
+ }
@@ -6,14 +6,10 @@ import Rating from "@mui/material/Rating";
6
6
  // GLOBAL CUSTOM COMPONENTS
7
7
  import LazyImage from "@/components/_components/LazyImage";
8
8
  import { Span } from "@/components/_components/Typography";
9
- import ProductViewDialog from "@/components/_components/products-view/product-view-dialog";
10
9
  // LOCAL CUSTOM HOOK
11
- import useProduct from "../use-product";
12
10
  // LOCAL CUSTOM COMPONENTS
13
- import HoverActions from "./components/hover-actions";
14
11
  import ProductPrice from "../product-price";
15
12
  import ProductTitle from "../product-title";
16
- import DiscountChip from "../discount-chip";
17
13
  import QuantityButtons from "./components/quantity-buttons";
18
14
  // STYLED COMPONENTS
19
15
  import { ImageWrapper, ContentWrapper, StyledBazaarCard } from "./styles/index";
@@ -31,6 +27,11 @@ type Props = {
31
27
  hideRating?: boolean;
32
28
  hoverEffect?: boolean;
33
29
  showProductSize?: boolean;
30
+ wishlistControls?: React.ReactNode;
31
+ quantity: number;
32
+ isLineUpdating: boolean;
33
+ handleIncrementQuantity: () => void;
34
+ handleDecrementQuantity: () => void;
34
35
  };
35
36
  // ========================================================
36
37
 
@@ -45,54 +46,17 @@ export default function ProductCard1({
45
46
  hoverEffect,
46
47
  discount = 5,
47
48
  showProductSize,
49
+ wishlistControls,
50
+ quantity,
51
+ isLineUpdating,
52
+ handleIncrementQuantity,
53
+ handleDecrementQuantity,
48
54
  }: Props) {
49
- const {
50
- isFavorite,
51
- openModal,
52
- cartItem,
53
- toggleDialog,
54
- toggleFavorite,
55
- handleCartAmountChange,
56
- } = useProduct(slug);
57
-
58
- const handleIncrementQuantity = () => {
59
- const product = {
60
- id,
61
- slug,
62
- price,
63
- imgUrl,
64
- name: title,
65
- qty: (cartItem?.Quantity || 0) + 1,
66
- };
67
- product;
68
- handleCartAmountChange();
69
- };
70
-
71
- const handleDecrementQuantity = () => {
72
- const product = {
73
- id,
74
- slug,
75
- price,
76
- imgUrl,
77
- name: title,
78
- qty: (cartItem?.Quantity || 0) - 1,
79
- };
80
- product;
81
- handleCartAmountChange("remove");
82
- };
83
-
84
55
  return (
85
56
  <StyledBazaarCard hoverEffect={hoverEffect}>
86
57
  <ImageWrapper>
87
58
  {/* DISCOUNT PERCENT CHIP IF AVAILABLE */}
88
- <DiscountChip discount={discount} />
89
-
90
- {/* HOVER ACTION ICONS */}
91
- <HoverActions
92
- isFavorite={isFavorite}
93
- toggleView={toggleDialog}
94
- toggleFavorite={toggleFavorite}
95
- />
59
+ {/* <DiscountChip discount={discount} /> */}
96
60
 
97
61
  {/* PRODUCT IMAGE / THUMBNAIL */}
98
62
  <Link href={buildDetailUrl(title, Number(id))}>
@@ -106,13 +70,6 @@ export default function ProductCard1({
106
70
  </Link>
107
71
  </ImageWrapper>
108
72
 
109
- {/* PRODUCT VIEW DIALOG BOX */}
110
- <ProductViewDialog
111
- openDialog={openModal}
112
- handleCloseDialog={toggleDialog}
113
- product={{ title, price, id, slug, imgGroup: [imgUrl, imgUrl] }}
114
- />
115
-
116
73
  <ContentWrapper>
117
74
  <Box flex="1 1 0" minWidth="0px" mr={1}>
118
75
  {/* PRODUCT NAME / TITLE */}
@@ -136,10 +93,14 @@ export default function ProductCard1({
136
93
 
137
94
  {/* PRODUCT QUANTITY HANDLER BUTTONS */}
138
95
  <QuantityButtons
139
- quantity={cartItem?.Quantity || 0}
96
+ quantity={quantity}
140
97
  handleIncrement={handleIncrementQuantity}
141
98
  handleDecrement={handleDecrementQuantity}
99
+ isLineUpdating={isLineUpdating}
142
100
  />
101
+
102
+ {/* WISHLIST CONTROLS: hover actions, delete button */}
103
+ {wishlistControls}
143
104
  </ContentWrapper>
144
105
  </StyledBazaarCard>
145
106
  );
@@ -13,7 +13,9 @@ import useProduct from "../use-product";
13
13
  import LazyImage from "@/components/_components/LazyImage";
14
14
  import { FlexRowCenter } from "@/components/_components/flex-box/index";
15
15
  import { H4, Paragraph, Small } from "@/components/_components/Typography";
16
- import ProductViewDialog from "@/components/_components/products-view/product-view-dialog";
16
+ import ProductViewDialog, {
17
+ ProductInfo,
18
+ } from "@/components/_components/products-view/product-view-dialog";
17
19
  // CUSTOM UTILS LIBRARY FUNCTION
18
20
  import { currency } from "@/lib/lib";
19
21
  // CUSTOM COMPONENTS
@@ -23,45 +25,56 @@ import {
23
25
  CardMedia,
24
26
  FavoriteButton,
25
27
  QuickViewButton,
28
+ QuickViewSmallButton,
26
29
  } from "./styles/index";
27
30
  // CUSTOM DATA MODEL
28
31
  import { Product } from "@/components/_components/bazaar-types";
32
+ import { DialogType } from "@/_components/search-box/search-input-category";
33
+ import { RemoveRedEye } from "@mui/icons-material";
34
+ import buildDetailUrl from "@/lib/build-detail-url";
29
35
 
30
36
  // ==============================================================
31
- type Props = { product: Product };
37
+ type Props = {
38
+ slug: string;
39
+ id: string | number;
40
+ title: string;
41
+ price: number;
42
+ thumbnail: string;
43
+ categories: string[];
44
+ reviews: number;
45
+ rating: number;
46
+ enableWishlistDialog?: boolean;
47
+ enableQuickViewDialog?: boolean;
48
+ openDialog: (
49
+ type: DialogType,
50
+ productId: number,
51
+ productInfo?: ProductInfo,
52
+ ) => void;
53
+ };
32
54
  // ==============================================================
33
-
34
- export default function ProductCard8({ product }: Props) {
35
- const { slug, id, title, price, thumbnail, images, categories, reviews } =
36
- product || {};
55
+ export default function ProductCard8(props: Props) {
56
+ const {
57
+ slug,
58
+ id,
59
+ title,
60
+ price,
61
+ thumbnail,
62
+ categories,
63
+ reviews,
64
+ rating,
65
+ openDialog,
66
+ enableWishlistDialog = true,
67
+ enableQuickViewDialog = true,
68
+ } = props;
37
69
 
38
70
  const {
39
- cartItem,
40
- handleCartAmountChange,
41
- isFavorite,
42
- openModal,
43
- toggleDialog,
44
- toggleFavorite,
71
+ isFavorite, // TODO: always false; need to check if product exists in any of the wishlists?
45
72
  } = useProduct(slug);
46
73
 
47
- // HANDLE ADD TO CART PRODUCT
48
- const handleAddToCart = () => {
49
- const payload = {
50
- id,
51
- slug,
52
- price,
53
- name: title,
54
- imgUrl: thumbnail,
55
- qty: (cartItem?.Quantity || 0) + 1,
56
- };
57
- payload;
58
- handleCartAmountChange();
59
- };
60
-
61
74
  return (
62
75
  <Card>
63
76
  <CardMedia>
64
- <Link href={`/products/${slug}`}>
77
+ <Link href={buildDetailUrl(title, Number(id))}>
65
78
  <LazyImage
66
79
  width={300}
67
80
  height={300}
@@ -70,42 +83,44 @@ export default function ProductCard8({ product }: Props) {
70
83
  src={thumbnail}
71
84
  />
72
85
  </Link>
73
-
74
- {/* ADD TO CART BUTTON */}
75
- <AddToCartButton className="product-actions" onClick={handleAddToCart}>
76
- <AddShoppingCart className="icon" fontSize="small" />
77
- </AddToCartButton>
86
+ {/* */}
87
+ {/* QUICK VIEW BUTTON */}
88
+ {enableQuickViewDialog && (
89
+ <QuickViewSmallButton
90
+ className="product-actions"
91
+ onClick={() =>
92
+ openDialog(DialogType.QuickView, Number(id), {
93
+ id: Number(id),
94
+ title,
95
+ imgGroup: [thumbnail],
96
+ price,
97
+ slug,
98
+ })
99
+ }
100
+ >
101
+ <RemoveRedEye className="icon" fontSize="small" />
102
+ </QuickViewSmallButton>
103
+ )}
78
104
 
79
105
  {/* PRODUCT FAVORITE BUTTON */}
80
- <FavoriteButton className="product-actions" onClick={toggleFavorite}>
81
- {isFavorite ? (
82
- <Favorite className="icon" fontSize="small" color="primary" />
83
- ) : (
84
- <FavoriteBorder className="icon" fontSize="small" />
85
- )}
86
- </FavoriteButton>
87
-
88
- {/* PRODUCT QUICK VIEW BUTTON */}
89
- <Box mx={1} position="relative">
90
- <QuickViewButton
91
- fullWidth
92
- size="large"
93
- variant="contained"
94
- className="product-view-action"
95
- onClick={toggleDialog}
106
+ {enableWishlistDialog && (
107
+ <FavoriteButton
108
+ className="product-actions"
109
+ onClick={() =>
110
+ isFavorite
111
+ ? openDialog(DialogType.RemoveFromWishlist, Number(id))
112
+ : openDialog(DialogType.AddToWishlist, Number(id))
113
+ }
96
114
  >
97
- Quick View
98
- </QuickViewButton>
99
- </Box>
115
+ {isFavorite ? (
116
+ <Favorite className="icon" fontSize="small" color="primary" />
117
+ ) : (
118
+ <FavoriteBorder className="icon" fontSize="small" />
119
+ )}
120
+ </FavoriteButton>
121
+ )}
100
122
  </CardMedia>
101
123
 
102
- {/* PRODUCT VIEW DIALOG BOX */}
103
- <ProductViewDialog
104
- openDialog={openModal}
105
- handleCloseDialog={toggleDialog}
106
- product={{ id, slug, title, price, imgGroup: images ?? [] }}
107
- />
108
-
109
124
  <Box p={1} textAlign="center">
110
125
  {/* PRODUCT CATEGORY */}
111
126
  {categories.length > 0 ? (
@@ -122,9 +137,14 @@ export default function ProductCard8({ product }: Props) {
122
137
 
123
138
  {/* PRODUCT RATING / REVIEW */}
124
139
  <FlexRowCenter gap={1}>
125
- <Rating name="read-only" value={4} readOnly sx={{ fontSize: 16 }} />
140
+ <Rating
141
+ name="read-only"
142
+ value={rating}
143
+ readOnly
144
+ sx={{ fontSize: 16 }}
145
+ />
126
146
  <Small fontWeight={600} color="grey.500">
127
- ({reviews?.length} Reviews)
147
+ ({reviews} Reviews)
128
148
  </Small>
129
149
  </FlexRowCenter>
130
150
  </Box>
@@ -49,3 +49,13 @@ export const QuickViewButton = styled(Button)({
49
49
  position: "absolute",
50
50
  transition: "all 0.3s",
51
51
  });
52
+
53
+ export const QuickViewSmallButton = styled(IconButton)(({ theme }) => ({
54
+ top: 15,
55
+ right: -40,
56
+ position: "absolute",
57
+ backgroundColor: "white",
58
+ transition: "right 0.3s .1s",
59
+ color: theme.palette.text.primary,
60
+ ".icon": { fontSize: 16 },
61
+ }));