@evenicanpm/storefront-core 2.4.2 → 2.5.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.
- package/CHANGELOG.md +14 -0
- package/package.json +90 -90
- package/src/api-manager/datasources/d365/d365-cart.datasource.ts +4 -3
- package/src/api-manager/datasources/d365/d365-user.datasource.ts +3 -3
- package/src/api-manager/datasources/d365/utils/get-context-cookie.ts +1 -0
- package/src/api-manager/datasources/e4/address/e4-address.datasource.ts +5 -14
- package/src/api-manager/datasources/e4/address/e4-address.translator.ts +4 -3
- package/src/api-manager/datasources/e4/categories/e4-categories.translator.ts +1 -1
- package/src/api-manager/datasources/e4/graphqlRequestSdk.ts +29 -3
- package/src/api-manager/datasources/e4/product/e4-product.translator.ts +1 -1
- package/src/api-manager/index.ts +1 -1
- package/src/api-manager/lib/get-graphql-client.ts +1 -1
- package/src/api-manager/services/cart/mutations/add-discount-code.ts +0 -11
- package/src/api-manager/services/create-query.ts +13 -7
- package/src/api-manager/services/user/mutations/add-to-wishlist.ts +1 -1
- package/src/api-manager/services/user/mutations/remove-from-wishlist.ts +1 -1
- package/src/auth/AUTH GUIDE.md +880 -0
- package/src/cms/blocks/components/featured-categories.tsx +18 -15
- package/src/cms/blocks/components/featured-products.tsx +3 -2
- package/src/cms/blocks/components/footer/data/index.ts +0 -0
- package/src/cms/blocks/components/footer/index.tsx +0 -0
- package/src/cms/blocks/components/footer/sections/footer-app-store.tsx +0 -0
- package/src/cms/blocks/components/footer/sections/footer-contact.tsx +0 -2
- package/src/cms/blocks/components/footer/sections/footer-links.tsx +0 -0
- package/src/cms/blocks/components/footer/sections/footer-logo.tsx +2 -1
- package/src/cms/blocks/components/footer/sections/footer-social-links.tsx +0 -0
- package/src/cms/blocks/components/footer/styles/index.ts +0 -0
- package/src/cms/blocks/components/hero-carousel/index.tsx +0 -0
- package/src/cms/blocks/components/product-carousel/index.tsx +0 -0
- package/src/cms/blocks/components/shared/featured-product-card.tsx +0 -0
- package/src/cms/blocks/components/shared/product-category-item.tsx +0 -0
- package/src/cms/blocks/components/shared/product-grid.tsx +0 -0
- package/src/cms/blocks/components/shared/top-categories-card.tsx +0 -0
- package/src/cms/blocks/components/shared/top-rating-product-card.tsx +0 -0
- package/src/cms/blocks/icons/components/category.tsx +0 -0
- package/src/cms/blocks/icons/components/dotted-star.tsx +0 -0
- package/src/cms/blocks/icons/components/gift-box.tsx +0 -0
- package/src/cms/blocks/icons/components/light.tsx +0 -0
- package/src/cms/blocks/icons/components/new-arrival.tsx +0 -0
- package/src/cms/blocks/icons/components/rank-badge.tsx +0 -0
- package/src/components/SearchInput.stories.tsx +12 -10
- package/src/components/base-layout.tsx +42 -0
- package/src/components/categories/category-list/category-list.tsx +32 -12
- package/src/components/header/__tests__/header.test.tsx +0 -24
- package/src/components/header/components/mobile-header.tsx +16 -8
- package/src/components/header/header.tsx +6 -3
- package/src/components/mini-cart/components/bottom-actions.tsx +7 -2
- package/src/components/mini-cart/components/cart-item.tsx +16 -13
- package/src/components/mini-cart/components/empty-view.tsx +12 -6
- package/src/components/mini-cart/components/top-header.tsx +9 -8
- package/src/components/mini-cart/mini-cart-trigger.tsx +11 -5
- package/src/components/mini-cart/mini-cart.tsx +30 -15
- package/src/components/mobile-navigation/mobile-navigation-bar.tsx +6 -2
- package/src/components/navbar/categories.tsx +8 -2
- package/src/components/navbar/category-based-menu/category-based-menu.tsx +6 -2
- package/src/components/navbar/mega-menu/mega-menu.tsx +22 -14
- package/src/components/navbar/mobile-menu/mobile-menu.test.tsx +8 -11
- package/src/components/navbar/mobile-menu/mobile-menu.tsx +13 -11
- package/src/components/navbar/nav-list/nav-list.tsx +3 -2
- package/src/components/navbar/navbar.tsx +4 -2
- package/src/components/product-cards/product-card/product-card.tsx +50 -26
- package/src/components/product-cards/product-card-plp/product-card.tsx +37 -16
- package/src/components/product-cards/product-card-plp-list/product-card.tsx +38 -16
- package/src/components/product-cards/product-card-search/product-card.tsx +34 -13
- package/src/components/product-dialog/ProductDialog.stories.tsx +20 -18
- package/src/components/product-dialog/compound/product-dialog.tsx +7 -4
- package/src/components/product-dimensions/compound/dimensions-group.tsx +4 -2
- package/src/components/product-dimensions/compound/dimensions.tsx +15 -6
- package/src/components/product-quantity-buttons/compound/quantity-buttons-root.tsx +21 -13
- package/src/components/products-view/compound/products-grid-view.tsx +11 -4
- package/src/components/products-view/compound/products-list-view.tsx +11 -4
- package/src/components/search-bar/compound/search-bar-root.tsx +6 -4
- package/src/components/search-bar/compound/textfield-adornment-category.tsx +25 -8
- package/src/components/search-bar/hooks/use-click-outside.ts +7 -1
- package/src/components/search-bar/hooks/use-search.ts +3 -3
- package/src/components/user/index.ts +3 -0
- package/src/components/user/use-user-auth.ts +163 -0
- package/src/components/user/user.tsx +215 -0
- package/src/components/wishlist-dialogs/add-to-wishlist/AddToWishlist.stories.tsx +20 -15
- package/src/components/wishlist-dialogs/add-to-wishlist/compound/add-to-wishlist-dialog.tsx +11 -8
- package/src/components/wishlist-dialogs/add-to-wishlist/compound/add-to-wishlist-list.tsx +18 -3
- package/src/components/wishlist-dialogs/add-to-wishlist/index.tsx +0 -1
- package/src/components/wishlist-dialogs/create-wishlist/compound/create-wishlist-dialog.tsx +6 -2
- package/src/hooks/use-overflow-detect.ts +4 -4
- package/src/lib/graphqlRequestSdk.ts +0 -0
- package/src/lib/page-slugs.ts +16 -0
- package/src/pages/account/account-navigation.tsx +7 -14
- package/src/pages/account/account-routes.ts +4 -9
- package/src/pages/account/addresses/address-form.tsx +38 -16
- package/src/pages/account/addresses/address-item.tsx +18 -8
- package/src/pages/account/dashboard-header.tsx +20 -13
- package/src/pages/account/orders/order-history-filters-panel.tsx +21 -20
- package/src/pages/account/orders/order-history-header.tsx +14 -4
- package/src/pages/account/orders/order-history-root.tsx +3 -1
- package/src/pages/account/orders/order-history-row.tsx +12 -4
- package/src/pages/account/orders/order-history-search-and-filter.tsx +88 -59
- package/src/pages/account/orders/order-history-search-dropdown.tsx +26 -9
- package/src/pages/account/orders/order-history-sort.tsx +3 -1
- package/src/pages/account/orders/order-history-table.tsx +27 -5
- package/src/pages/account/orders/order-progress.tsx +12 -6
- package/src/pages/account/orders/order-row.tsx +18 -6
- package/src/pages/account/orders/order-summary.tsx +24 -8
- package/src/pages/account/orders/ordered-products.tsx +15 -5
- package/src/pages/account/profile/user-info.tsx +11 -3
- package/src/pages/account/table-row-skeleton.tsx +1 -1
- package/src/pages/account/wishlist/create-new-list.tsx +33 -9
- package/src/pages/account/wishlist/wishlist-item.tsx +18 -6
- package/src/pages/cart/cart-item.tsx +21 -7
- package/src/pages/cart/checkout-form.tsx +55 -22
- package/src/pages/cart/coupon-entry.tsx +143 -36
- package/src/pages/cart/estimate-shipping.tsx +45 -21
- package/src/pages/checkout/checkout-alt-form/checkout-form.tsx +22 -14
- package/src/pages/checkout/checkout-alt-form/checkout-step.tsx +37 -16
- package/src/pages/checkout/checkout-alt-form/steps/address/address-card.tsx +9 -3
- package/src/pages/checkout/checkout-alt-form/steps/address/delivery-address.tsx +84 -51
- package/src/pages/checkout/checkout-alt-form/steps/address/new-address-form.tsx +41 -19
- package/src/pages/checkout/checkout-alt-form/steps/customer-info/customer-information.tsx +17 -10
- package/src/pages/checkout/checkout-alt-form/steps/payment/payment-details.tsx +15 -6
- package/src/pages/checkout/checkout-alt-form/steps/shipping/delivery-options.tsx +6 -2
- package/src/pages/checkout/checkout-alt-summary/cart-item.tsx +12 -4
- package/src/pages/checkout/checkout-alt-summary/checkout-alt-summary.tsx +12 -5
- package/src/pages/checkout/checkout-alt-summary/list-item.tsx +17 -10
- package/src/pages/confirmation/address.tsx +6 -2
- package/src/pages/confirmation/confirmation-summary.tsx +12 -4
- package/src/pages/confirmation/ordered-products.tsx +12 -4
- package/src/pages/product-details/bopis/store-card/shop-card.tsx +2 -2
- package/src/pages/product-details/bopis/store-card/utils/getDaysResources.ts +1 -1
- package/src/pages/product-details/product-intro/compound/product-info.tsx +41 -18
- package/src/pages/product-details/product-intro/compound/product-intro-images.tsx +18 -12
- package/src/pages/product-details/product-intro/compound/product-intro.tsx +20 -10
- package/src/pages/product-details/product-intro/compound/thumbnail-with-skeleton.tsx +1 -1
- package/src/pages/product-details/product-tabs.tsx +20 -12
- package/src/pages/product-list/product-list-view.tsx +4 -2
- package/src/pages/product-list/search-bar.tsx +7 -7
- package/src/pages/product-list/side-nav.tsx +5 -3
- package/src/pages/quickorder/order-upload.tsx +1 -1
- package/src/pages/quickorder/provider.tsx +26 -14
- package/src/pages/quickorder/quick-order.tsx +49 -22
- package/src/providers/nav-provider/index.tsx +16 -11
- package/tsconfig.json +0 -5
- package/src/components/header/components/user.tsx +0 -322
- /package/src/components/{header → user}/__tests__/user.test.tsx +0 -0
|
@@ -58,7 +58,7 @@ type PaymentDetailsCompound = React.FC<CheckoutStepComponentProps> & {
|
|
|
58
58
|
selectedPaymentMethod: PaymentMethod;
|
|
59
59
|
}>;
|
|
60
60
|
Form: React.FC<{
|
|
61
|
-
iframeReference: React.RefObject<HTMLIFrameElement>;
|
|
61
|
+
iframeReference: React.RefObject<HTMLIFrameElement | null>;
|
|
62
62
|
iframeHeight: number;
|
|
63
63
|
errorState: PaymentError[];
|
|
64
64
|
paymentAcceptPointData: CardPaymentAcceptPoint | null | undefined;
|
|
@@ -111,7 +111,7 @@ const PaymentDetails: PaymentDetailsCompound = (props) => {
|
|
|
111
111
|
|
|
112
112
|
const { mutateAsync: retrievePaymentAcceptResult } = usePaymentAcceptResult();
|
|
113
113
|
const iframeReference = React.useRef<HTMLIFrameElement>(null);
|
|
114
|
-
const [iframeHeight,
|
|
114
|
+
const [iframeHeight, setIframeHeight] = React.useState<number>(1);
|
|
115
115
|
const [errorState, setErrorState] = React.useState<PaymentError[]>([]);
|
|
116
116
|
|
|
117
117
|
const paymentConnectorMessage = React.useCallback(
|
|
@@ -182,7 +182,9 @@ const PaymentDetails: PaymentDetailsCompound = (props) => {
|
|
|
182
182
|
switch (type) {
|
|
183
183
|
case PaymentConnectorPostMessageType.Height: {
|
|
184
184
|
// Payment connector posts height after initialization
|
|
185
|
-
|
|
185
|
+
if (typeof value === "number") {
|
|
186
|
+
setIframeHeight(value);
|
|
187
|
+
}
|
|
186
188
|
postMessageToIframe(
|
|
187
189
|
paymentConnectorMessage(
|
|
188
190
|
cart.TotalAmount.toString(),
|
|
@@ -194,7 +196,7 @@ const PaymentDetails: PaymentDetailsCompound = (props) => {
|
|
|
194
196
|
case PaymentConnectorPostMessageType.Result: {
|
|
195
197
|
try {
|
|
196
198
|
if (typeof value !== "string") {
|
|
197
|
-
throw new
|
|
199
|
+
throw new TypeError("Invalid payment result access code");
|
|
198
200
|
}
|
|
199
201
|
await handleResultsAccessCode(value);
|
|
200
202
|
setStepSubmissionState("idle");
|
|
@@ -363,7 +365,10 @@ const PaymentDetails: PaymentDetailsCompound = (props) => {
|
|
|
363
365
|
);
|
|
364
366
|
};
|
|
365
367
|
|
|
366
|
-
|
|
368
|
+
const PaymentDetailsPreview = ({
|
|
369
|
+
paymentAcceptResult,
|
|
370
|
+
selectedPaymentMethod,
|
|
371
|
+
}) => {
|
|
367
372
|
const t = useTranslations("Checkout.Payment");
|
|
368
373
|
|
|
369
374
|
if (selectedPaymentMethod === "on-account") {
|
|
@@ -422,7 +427,9 @@ PaymentDetails.Preview = ({ paymentAcceptResult, selectedPaymentMethod }) => {
|
|
|
422
427
|
);
|
|
423
428
|
};
|
|
424
429
|
|
|
425
|
-
PaymentDetails.
|
|
430
|
+
PaymentDetails.Preview = PaymentDetailsPreview;
|
|
431
|
+
|
|
432
|
+
const PaymentDetailsForm = ({
|
|
426
433
|
iframeReference,
|
|
427
434
|
iframeHeight,
|
|
428
435
|
errorState,
|
|
@@ -468,4 +475,6 @@ PaymentDetails.Form = ({
|
|
|
468
475
|
);
|
|
469
476
|
};
|
|
470
477
|
|
|
478
|
+
PaymentDetails.Form = PaymentDetailsForm;
|
|
479
|
+
|
|
471
480
|
export default PaymentDetails;
|
|
@@ -173,7 +173,7 @@ const DeliveryOptions: DeliveryOptionsCompound = (props) => {
|
|
|
173
173
|
);
|
|
174
174
|
};
|
|
175
175
|
|
|
176
|
-
|
|
176
|
+
const DeliveryOptionsPreview = ({ deliveryOptions, selectedOption }) => {
|
|
177
177
|
const { formatCurrency } = useCurrencyFormatter();
|
|
178
178
|
const deliveryOption = deliveryOptions.find(
|
|
179
179
|
(dlv) => dlv.Code === selectedOption,
|
|
@@ -189,7 +189,9 @@ DeliveryOptions.Preview = ({ deliveryOptions, selectedOption }) => {
|
|
|
189
189
|
);
|
|
190
190
|
};
|
|
191
191
|
|
|
192
|
-
DeliveryOptions.
|
|
192
|
+
DeliveryOptions.Preview = DeliveryOptionsPreview;
|
|
193
|
+
|
|
194
|
+
const DeliveryOptionsForm = ({
|
|
193
195
|
deliveryOptions,
|
|
194
196
|
deliveryUnavailable,
|
|
195
197
|
selectedOption,
|
|
@@ -240,4 +242,6 @@ DeliveryOptions.Form = ({
|
|
|
240
242
|
);
|
|
241
243
|
};
|
|
242
244
|
|
|
245
|
+
DeliveryOptions.Form = DeliveryOptionsForm;
|
|
246
|
+
|
|
243
247
|
export default DeliveryOptions;
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
Span,
|
|
8
8
|
} from "@evenicanpm/storefront-core/src/components/Typography";
|
|
9
9
|
import useCurrencyFormatter from "@evenicanpm/storefront-core/src/lib/currency-formatter";
|
|
10
|
-
import { createContext, type ReactNode, useContext } from "react";
|
|
10
|
+
import { createContext, type ReactNode, useContext, useMemo } from "react";
|
|
11
11
|
|
|
12
12
|
interface CartItemContextValue {
|
|
13
13
|
cartLine: CartLine;
|
|
@@ -20,8 +20,12 @@ interface CartItemProps {
|
|
|
20
20
|
}
|
|
21
21
|
const CartItem = ({ cartLine, children }: CartItemProps) => {
|
|
22
22
|
const { formatCurrency } = useCurrencyFormatter();
|
|
23
|
+
const contextValue = useMemo(
|
|
24
|
+
() => ({ cartLine, formatCurrency }),
|
|
25
|
+
[cartLine, formatCurrency],
|
|
26
|
+
);
|
|
23
27
|
return (
|
|
24
|
-
<CartItemContext.Provider value={
|
|
28
|
+
<CartItemContext.Provider value={contextValue}>
|
|
25
29
|
<FlexBetween mb={1.5}>
|
|
26
30
|
{children ?? (
|
|
27
31
|
<>
|
|
@@ -34,7 +38,7 @@ const CartItem = ({ cartLine, children }: CartItemProps) => {
|
|
|
34
38
|
);
|
|
35
39
|
};
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
const CartItemDescription = () => {
|
|
38
42
|
const ctx = useContext(CartItemContext);
|
|
39
43
|
if (!ctx) return null;
|
|
40
44
|
const { cartLine } = ctx;
|
|
@@ -46,7 +50,9 @@ CartItem.Description = () => {
|
|
|
46
50
|
);
|
|
47
51
|
};
|
|
48
52
|
|
|
49
|
-
CartItem.
|
|
53
|
+
CartItem.Description = CartItemDescription;
|
|
54
|
+
|
|
55
|
+
const CartItemPrice = () => {
|
|
50
56
|
const ctx = useContext(CartItemContext);
|
|
51
57
|
if (!ctx) return null;
|
|
52
58
|
const { cartLine, formatCurrency } = ctx;
|
|
@@ -69,4 +75,6 @@ CartItem.Price = () => {
|
|
|
69
75
|
);
|
|
70
76
|
};
|
|
71
77
|
|
|
78
|
+
CartItem.Price = CartItemPrice;
|
|
79
|
+
|
|
72
80
|
export default CartItem;
|
|
@@ -13,7 +13,7 @@ import ListItem from "@evenicanpm/storefront-core/src/pages/checkout/checkout-al
|
|
|
13
13
|
import Box from "@mui/material/Box";
|
|
14
14
|
import Divider from "@mui/material/Divider";
|
|
15
15
|
import { useTranslations } from "next-intl";
|
|
16
|
-
import { createContext, type ReactNode, useContext } from "react";
|
|
16
|
+
import { createContext, type ReactNode, useContext, useMemo } from "react";
|
|
17
17
|
|
|
18
18
|
interface Props {
|
|
19
19
|
cart: Cart;
|
|
@@ -29,15 +29,16 @@ const CheckoutAltSummaryContext =
|
|
|
29
29
|
|
|
30
30
|
const CheckoutAltSummary = ({ cart, children }: Props) => {
|
|
31
31
|
const t = useTranslations("Checkout.Summary");
|
|
32
|
+
const contextValue = useMemo(() => ({ cart, t }), [cart, t]);
|
|
32
33
|
|
|
33
34
|
return (
|
|
34
|
-
<CheckoutAltSummaryContext.Provider value={
|
|
35
|
+
<CheckoutAltSummaryContext.Provider value={contextValue}>
|
|
35
36
|
<div>{children}</div>
|
|
36
37
|
</CheckoutAltSummaryContext.Provider>
|
|
37
38
|
);
|
|
38
39
|
};
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
const CheckoutAltSummaryTitle = () => {
|
|
41
42
|
const ctx = useContext(CheckoutAltSummaryContext);
|
|
42
43
|
if (!ctx) return null;
|
|
43
44
|
const { t } = ctx;
|
|
@@ -48,7 +49,9 @@ CheckoutAltSummary.Title = () => {
|
|
|
48
49
|
);
|
|
49
50
|
};
|
|
50
51
|
|
|
51
|
-
CheckoutAltSummary.
|
|
52
|
+
CheckoutAltSummary.Title = CheckoutAltSummaryTitle;
|
|
53
|
+
|
|
54
|
+
const CheckoutAltSummaryCartItems = () => {
|
|
52
55
|
const ctx = useContext(CheckoutAltSummaryContext);
|
|
53
56
|
if (!ctx) return null;
|
|
54
57
|
const { cart } = ctx;
|
|
@@ -61,11 +64,13 @@ CheckoutAltSummary.CartItems = () => {
|
|
|
61
64
|
);
|
|
62
65
|
};
|
|
63
66
|
|
|
67
|
+
CheckoutAltSummary.CartItems = CheckoutAltSummaryCartItems;
|
|
68
|
+
|
|
64
69
|
CheckoutAltSummary.Divider = (props: { sx?: object }) => {
|
|
65
70
|
return <Box component={Divider} borderColor="grey.300" {...props} />;
|
|
66
71
|
};
|
|
67
72
|
|
|
68
|
-
|
|
73
|
+
const CheckoutAltSummaryListItem = ({
|
|
69
74
|
cartKey,
|
|
70
75
|
titleKey,
|
|
71
76
|
color,
|
|
@@ -89,4 +94,6 @@ CheckoutAltSummary.ListItem = ({
|
|
|
89
94
|
);
|
|
90
95
|
};
|
|
91
96
|
|
|
97
|
+
CheckoutAltSummary.ListItem = CheckoutAltSummaryListItem;
|
|
98
|
+
|
|
92
99
|
export default CheckoutAltSummary;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FlexBetween } from "@evenicanpm/storefront-core/src/components/flex-box/index";
|
|
2
2
|
import { Paragraph } from "@evenicanpm/storefront-core/src/components/Typography";
|
|
3
3
|
import useCurrencyFormatter from "@evenicanpm/storefront-core/src/lib/currency-formatter";
|
|
4
|
-
import { createContext, type ReactNode, useContext } from "react";
|
|
4
|
+
import { createContext, type ReactNode, useContext, useMemo } from "react";
|
|
5
5
|
|
|
6
6
|
interface ListItemProps {
|
|
7
7
|
title: string;
|
|
@@ -30,13 +30,16 @@ const ListItem = ({
|
|
|
30
30
|
}: ListItemProps) => {
|
|
31
31
|
const { formatCurrency } = useCurrencyFormatter();
|
|
32
32
|
|
|
33
|
-
const contextValue: ListItemContextValue =
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
const contextValue: ListItemContextValue = useMemo(
|
|
34
|
+
() => ({
|
|
35
|
+
title,
|
|
36
|
+
value,
|
|
37
|
+
mb,
|
|
38
|
+
color,
|
|
39
|
+
formatCurrency,
|
|
40
|
+
}),
|
|
41
|
+
[title, value, mb, color, formatCurrency],
|
|
42
|
+
);
|
|
40
43
|
|
|
41
44
|
return (
|
|
42
45
|
<ListItemContext.Provider value={contextValue}>
|
|
@@ -52,14 +55,16 @@ const ListItem = ({
|
|
|
52
55
|
);
|
|
53
56
|
};
|
|
54
57
|
|
|
55
|
-
|
|
58
|
+
const ListItemTitle = () => {
|
|
56
59
|
const ctx = useContext(ListItemContext);
|
|
57
60
|
if (!ctx) return null;
|
|
58
61
|
const { title, color } = ctx;
|
|
59
62
|
return <Paragraph color={color}>{title}:</Paragraph>;
|
|
60
63
|
};
|
|
61
64
|
|
|
62
|
-
ListItem.
|
|
65
|
+
ListItem.Title = ListItemTitle;
|
|
66
|
+
|
|
67
|
+
const ListItemValue = () => {
|
|
63
68
|
const ctx = useContext(ListItemContext);
|
|
64
69
|
if (!ctx) return null;
|
|
65
70
|
const { value, formatCurrency } = ctx;
|
|
@@ -70,4 +75,6 @@ ListItem.Value = () => {
|
|
|
70
75
|
);
|
|
71
76
|
};
|
|
72
77
|
|
|
78
|
+
ListItem.Value = ListItemValue;
|
|
79
|
+
|
|
73
80
|
export default ListItem;
|
|
@@ -24,7 +24,7 @@ const OrderAddress = ({ address, children }: Props) => {
|
|
|
24
24
|
);
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
const OrderAddressHeading = ({ children }: { children?: ReactNode }) => {
|
|
28
28
|
const t = useTranslations("Address");
|
|
29
29
|
return (
|
|
30
30
|
<H5 mt={0} mb={2}>
|
|
@@ -33,7 +33,9 @@ OrderAddress.Heading = ({ children }: { children?: ReactNode }) => {
|
|
|
33
33
|
);
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
OrderAddress.
|
|
36
|
+
OrderAddress.Heading = OrderAddressHeading;
|
|
37
|
+
|
|
38
|
+
const OrderAddressField = ({
|
|
37
39
|
property,
|
|
38
40
|
}: {
|
|
39
41
|
property: Exclude<keyof Address, "ExtensionProperties">;
|
|
@@ -48,4 +50,6 @@ OrderAddress.Field = ({
|
|
|
48
50
|
return <Paragraph>{value}</Paragraph>;
|
|
49
51
|
};
|
|
50
52
|
|
|
53
|
+
OrderAddress.Field = OrderAddressField;
|
|
54
|
+
|
|
51
55
|
export default OrderAddress;
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import useCurrencyFormatter from "@evenicanpm/storefront-core/src/lib/currency-formatter";
|
|
13
13
|
import { Card, Divider } from "@mui/material";
|
|
14
14
|
import { useTranslations } from "next-intl";
|
|
15
|
-
import { createContext, type ReactNode, useContext } from "react";
|
|
15
|
+
import { createContext, type ReactNode, useContext, useMemo } from "react";
|
|
16
16
|
|
|
17
17
|
type SummaryValues = {
|
|
18
18
|
order: SalesOrder;
|
|
@@ -26,9 +26,13 @@ type Props = SummaryValues & { children?: ReactNode };
|
|
|
26
26
|
|
|
27
27
|
const OrderSummary = ({ order, children }: Props) => {
|
|
28
28
|
const { formatCurrency } = useCurrencyFormatter();
|
|
29
|
+
const contextValue = useMemo(
|
|
30
|
+
() => ({ order, formatCurrency }),
|
|
31
|
+
[order, formatCurrency],
|
|
32
|
+
);
|
|
29
33
|
|
|
30
34
|
return (
|
|
31
|
-
<SummaryContext.Provider value={
|
|
35
|
+
<SummaryContext.Provider value={contextValue}>
|
|
32
36
|
<Card sx={{ px: 3, mb: "30px" }}>
|
|
33
37
|
{children ?? (
|
|
34
38
|
<>
|
|
@@ -51,7 +55,7 @@ type ItemProps = {
|
|
|
51
55
|
field: keyof SalesOrder;
|
|
52
56
|
};
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
const OrderSummaryTitle = () => {
|
|
55
59
|
const t = useTranslations("Confirmation");
|
|
56
60
|
return (
|
|
57
61
|
<FlexBox
|
|
@@ -66,7 +70,9 @@ OrderSummary.Title = () => {
|
|
|
66
70
|
);
|
|
67
71
|
};
|
|
68
72
|
|
|
69
|
-
OrderSummary.
|
|
73
|
+
OrderSummary.Title = OrderSummaryTitle;
|
|
74
|
+
|
|
75
|
+
const OrderSummaryItem = ({ label, field }: ItemProps) => {
|
|
70
76
|
const ctx = useContext(SummaryContext);
|
|
71
77
|
const t = useTranslations("Checkout.Summary");
|
|
72
78
|
if (!ctx) return null;
|
|
@@ -88,6 +94,8 @@ OrderSummary.Item = ({ label, field }: ItemProps) => {
|
|
|
88
94
|
);
|
|
89
95
|
};
|
|
90
96
|
|
|
97
|
+
OrderSummary.Item = OrderSummaryItem;
|
|
98
|
+
|
|
91
99
|
OrderSummary.Divider = (props: { sx?: object }) => {
|
|
92
100
|
return <Divider {...props} />;
|
|
93
101
|
};
|
|
@@ -33,7 +33,7 @@ export const OrderedProducts = ({ order, children }: Props) => {
|
|
|
33
33
|
);
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
const OrderedProductsHeader = () => {
|
|
37
37
|
const ctx = useContext(OrderedProductsContext);
|
|
38
38
|
const t = useTranslations("Confirmation");
|
|
39
39
|
const { dateTime } = useFormatter();
|
|
@@ -68,6 +68,8 @@ OrderedProducts.Header = () => {
|
|
|
68
68
|
);
|
|
69
69
|
};
|
|
70
70
|
|
|
71
|
+
OrderedProducts.Header = OrderedProductsHeader;
|
|
72
|
+
|
|
71
73
|
OrderedProducts.List = ({ children }: { children: React.ReactNode }) => {
|
|
72
74
|
return (
|
|
73
75
|
<Grid container spacing={2} alignItems="center" padding="15px 5px">
|
|
@@ -100,7 +102,7 @@ OrderedProducts.Info = ({ children }: { children: React.ReactNode }) => {
|
|
|
100
102
|
return <div>{children}</div>;
|
|
101
103
|
};
|
|
102
104
|
|
|
103
|
-
|
|
105
|
+
const OrderedProductsTitle = ({ line }: LineProps) => {
|
|
104
106
|
const { formatCurrency } = useCurrencyFormatter();
|
|
105
107
|
return (
|
|
106
108
|
<>
|
|
@@ -112,7 +114,9 @@ OrderedProducts.Title = ({ line }: LineProps) => {
|
|
|
112
114
|
);
|
|
113
115
|
};
|
|
114
116
|
|
|
115
|
-
OrderedProducts.
|
|
117
|
+
OrderedProducts.Title = OrderedProductsTitle;
|
|
118
|
+
|
|
119
|
+
const OrderedProductsComment = ({ line }: LineProps) => {
|
|
116
120
|
const t = useTranslations("Confirmation");
|
|
117
121
|
if (!line.Comment) return null;
|
|
118
122
|
return (
|
|
@@ -125,6 +129,8 @@ OrderedProducts.Comment = ({ line }: LineProps) => {
|
|
|
125
129
|
);
|
|
126
130
|
};
|
|
127
131
|
|
|
132
|
+
OrderedProducts.Comment = OrderedProductsComment;
|
|
133
|
+
|
|
128
134
|
OrderedProducts.Dimensions = ({ line }: LineProps) => {
|
|
129
135
|
if (!line.Product?.Dimensions?.length) return <Box />;
|
|
130
136
|
return (
|
|
@@ -139,7 +145,7 @@ OrderedProducts.Dimensions = ({ line }: LineProps) => {
|
|
|
139
145
|
);
|
|
140
146
|
};
|
|
141
147
|
|
|
142
|
-
|
|
148
|
+
const OrderedProductsTotal = ({ line }: LineProps) => {
|
|
143
149
|
const { formatCurrency } = useCurrencyFormatter();
|
|
144
150
|
return (
|
|
145
151
|
<Grid size={{ xs: 4, sm: 2 }}>
|
|
@@ -150,4 +156,6 @@ OrderedProducts.Total = ({ line }: LineProps) => {
|
|
|
150
156
|
);
|
|
151
157
|
};
|
|
152
158
|
|
|
159
|
+
OrderedProducts.Total = OrderedProductsTotal;
|
|
160
|
+
|
|
153
161
|
export default OrderedProducts;
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
// STYLED COMPONENT
|
|
15
15
|
import { ContentWrapper } from "@evenicanpm/storefront-core/src/pages/product-details/bopis/store-card/styles";
|
|
16
16
|
import { convertSecondsToTime } from "@evenicanpm/storefront-core/src/pages/product-details/bopis/store-card/utils/convertSecondsToTime";
|
|
17
|
-
import {
|
|
17
|
+
import { useDaysResources } from "@evenicanpm/storefront-core/src/pages/product-details/bopis/store-card/utils/getDaysResources";
|
|
18
18
|
import type {
|
|
19
19
|
ProductWarehouseInventoryAvailability,
|
|
20
20
|
StoreHours,
|
|
@@ -39,7 +39,7 @@ export default function ShopCard(props: Readonly<Props>) {
|
|
|
39
39
|
const { name, address, actionArea, openFrom, openTo, storeHours } =
|
|
40
40
|
props || {};
|
|
41
41
|
|
|
42
|
-
const resources =
|
|
42
|
+
const resources = useDaysResources();
|
|
43
43
|
|
|
44
44
|
const renderStoreHours = () => {
|
|
45
45
|
if (storeHours?.RegularStoreHours) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { IStoreSelectorLocationLineItemResources } from "@evenicanpm/storefront-core/src/lib/store-hours-helper";
|
|
2
2
|
import { useTranslations } from "next-intl";
|
|
3
3
|
|
|
4
|
-
export const
|
|
4
|
+
export const useDaysResources = (): IStoreSelectorLocationLineItemResources => {
|
|
5
5
|
const daysTrans = useTranslations("StoreHours");
|
|
6
6
|
return {
|
|
7
7
|
days: {
|
|
@@ -13,7 +13,7 @@ import Box from "@mui/material/Box";
|
|
|
13
13
|
import Grid from "@mui/material/Grid2";
|
|
14
14
|
import Rating from "@mui/material/Rating";
|
|
15
15
|
import type React from "react";
|
|
16
|
-
import { useContext, useState } from "react";
|
|
16
|
+
import { useContext, useMemo, useState } from "react";
|
|
17
17
|
|
|
18
18
|
// D365
|
|
19
19
|
|
|
@@ -81,18 +81,27 @@ const ProductInfo = ({ children }: Props) => {
|
|
|
81
81
|
!productPrices ||
|
|
82
82
|
variantPending ||
|
|
83
83
|
(allDimensionsSelected && inventoryPending);
|
|
84
|
+
const contextValue = useMemo(
|
|
85
|
+
() => ({
|
|
86
|
+
hasVariants,
|
|
87
|
+
isProductDetailsPending,
|
|
88
|
+
productPrices,
|
|
89
|
+
shippingInventoryData,
|
|
90
|
+
showDimensionError,
|
|
91
|
+
setShowDimensionError,
|
|
92
|
+
}),
|
|
93
|
+
[
|
|
94
|
+
hasVariants,
|
|
95
|
+
isProductDetailsPending,
|
|
96
|
+
productPrices,
|
|
97
|
+
shippingInventoryData,
|
|
98
|
+
showDimensionError,
|
|
99
|
+
setShowDimensionError,
|
|
100
|
+
],
|
|
101
|
+
);
|
|
84
102
|
|
|
85
103
|
return (
|
|
86
|
-
<ProductInfoContext.Provider
|
|
87
|
-
value={{
|
|
88
|
-
hasVariants,
|
|
89
|
-
isProductDetailsPending,
|
|
90
|
-
productPrices,
|
|
91
|
-
shippingInventoryData,
|
|
92
|
-
showDimensionError,
|
|
93
|
-
setShowDimensionError,
|
|
94
|
-
}}
|
|
95
|
-
>
|
|
104
|
+
<ProductInfoContext.Provider value={contextValue}>
|
|
96
105
|
<Grid size={{ md: 6, xs: 12 }} alignItems="center">
|
|
97
106
|
{children}
|
|
98
107
|
</Grid>
|
|
@@ -103,7 +112,7 @@ const ProductInfo = ({ children }: Props) => {
|
|
|
103
112
|
/**
|
|
104
113
|
* @category Sub-Component
|
|
105
114
|
*/
|
|
106
|
-
|
|
115
|
+
const ProductInfoName = () => {
|
|
107
116
|
const IntroCtx = useProductIntro();
|
|
108
117
|
if (!IntroCtx)
|
|
109
118
|
throw new Error(
|
|
@@ -113,10 +122,12 @@ ProductInfo.Name = () => {
|
|
|
113
122
|
return <H1 mb={1}>{masterProduct.Name}</H1>;
|
|
114
123
|
};
|
|
115
124
|
|
|
125
|
+
ProductInfo.Name = ProductInfoName;
|
|
126
|
+
|
|
116
127
|
/**
|
|
117
128
|
* @category Sub-Component
|
|
118
129
|
*/
|
|
119
|
-
|
|
130
|
+
const ProductInfoSku = () => {
|
|
120
131
|
const IntroCtx = useProductIntro();
|
|
121
132
|
if (!IntroCtx)
|
|
122
133
|
throw new Error(
|
|
@@ -130,10 +141,12 @@ ProductInfo.Sku = () => {
|
|
|
130
141
|
);
|
|
131
142
|
};
|
|
132
143
|
|
|
144
|
+
ProductInfo.Sku = ProductInfoSku;
|
|
145
|
+
|
|
133
146
|
/**
|
|
134
147
|
* @category Sub-Component
|
|
135
148
|
*/
|
|
136
|
-
|
|
149
|
+
const ProductInfoRating = () => {
|
|
137
150
|
return (
|
|
138
151
|
<FlexBox alignItems="center" gap={1} mb={2}>
|
|
139
152
|
<Box lineHeight="1">Rated:</Box>
|
|
@@ -143,10 +156,12 @@ ProductInfo.Sku = () => {
|
|
|
143
156
|
);
|
|
144
157
|
};
|
|
145
158
|
|
|
159
|
+
ProductInfo.Rating = ProductInfoRating;
|
|
160
|
+
|
|
146
161
|
/**
|
|
147
162
|
* @category Sub-Component
|
|
148
163
|
*/
|
|
149
|
-
|
|
164
|
+
const ProductInfoDimensions = () => {
|
|
150
165
|
const InfoCtx = useContext(ProductInfoContext);
|
|
151
166
|
const IntroCtx = useProductIntro();
|
|
152
167
|
if (!InfoCtx || !IntroCtx)
|
|
@@ -170,7 +185,9 @@ ProductInfo.Dimensions = () => {
|
|
|
170
185
|
);
|
|
171
186
|
};
|
|
172
187
|
|
|
173
|
-
ProductInfo.
|
|
188
|
+
ProductInfo.Dimensions = ProductInfoDimensions;
|
|
189
|
+
|
|
190
|
+
const ProductInfoPrice = () => {
|
|
174
191
|
const { formatCurrency } = useCurrencyFormatter();
|
|
175
192
|
const { isProductDetailsPending, productPrices } = useProductInfo();
|
|
176
193
|
|
|
@@ -188,10 +205,12 @@ ProductInfo.Price = () => {
|
|
|
188
205
|
);
|
|
189
206
|
};
|
|
190
207
|
|
|
208
|
+
ProductInfo.Price = ProductInfoPrice;
|
|
209
|
+
|
|
191
210
|
/**
|
|
192
211
|
* @category Sub-Component
|
|
193
212
|
*/
|
|
194
|
-
|
|
213
|
+
const ProductInfoInventory = () => {
|
|
195
214
|
const InfoCtx = useContext(ProductInfoContext);
|
|
196
215
|
const IntroCtx = useProductIntro();
|
|
197
216
|
if (!InfoCtx || !IntroCtx)
|
|
@@ -227,12 +246,14 @@ ProductInfo.Inventory = () => {
|
|
|
227
246
|
);
|
|
228
247
|
};
|
|
229
248
|
|
|
249
|
+
ProductInfo.Inventory = ProductInfoInventory;
|
|
250
|
+
|
|
230
251
|
/**
|
|
231
252
|
* These are grouped together because they have similar functionality and callbacks
|
|
232
253
|
* addToCart Etc
|
|
233
254
|
* @category Sub-Component
|
|
234
255
|
*/
|
|
235
|
-
|
|
256
|
+
const ProductInfoButtons = () => {
|
|
236
257
|
const { masterProduct, selectedVariant, allDimensionsSelected } =
|
|
237
258
|
useProductIntro();
|
|
238
259
|
const { setShowDimensionError, shippingInventoryData, hasVariants } =
|
|
@@ -282,4 +303,6 @@ ProductInfo.Buttons = () => {
|
|
|
282
303
|
);
|
|
283
304
|
};
|
|
284
305
|
|
|
306
|
+
ProductInfo.Buttons = ProductInfoButtons;
|
|
307
|
+
|
|
285
308
|
export default ProductInfo;
|
|
@@ -13,7 +13,7 @@ import ThumbnailWithSkeleton from "@evenicanpm/storefront-core/src/pages/product
|
|
|
13
13
|
import Grid from "@mui/material/Grid2";
|
|
14
14
|
import Skeleton from "@mui/material/Skeleton";
|
|
15
15
|
import type React from "react";
|
|
16
|
-
import { useContext, useState } from "react";
|
|
16
|
+
import { useContext, useMemo, useState } from "react";
|
|
17
17
|
|
|
18
18
|
type Props = {
|
|
19
19
|
children: React.ReactNode;
|
|
@@ -56,17 +56,19 @@ export default function ProductImages({ children }: Readonly<Props>) {
|
|
|
56
56
|
const handleImageClick = (ind: number) => () => {
|
|
57
57
|
setSelectedImageIndex(ind);
|
|
58
58
|
};
|
|
59
|
+
const contextValue = useMemo(
|
|
60
|
+
() => ({
|
|
61
|
+
name: Name,
|
|
62
|
+
selectedImageIndex,
|
|
63
|
+
images,
|
|
64
|
+
handleImageClick,
|
|
65
|
+
primaryImageUrl,
|
|
66
|
+
}),
|
|
67
|
+
[Name, selectedImageIndex, images, handleImageClick, primaryImageUrl],
|
|
68
|
+
);
|
|
59
69
|
|
|
60
70
|
return (
|
|
61
|
-
<ProductImagesContext.Provider
|
|
62
|
-
value={{
|
|
63
|
-
name: Name,
|
|
64
|
-
selectedImageIndex,
|
|
65
|
-
images,
|
|
66
|
-
handleImageClick,
|
|
67
|
-
primaryImageUrl,
|
|
68
|
-
}}
|
|
69
|
-
>
|
|
71
|
+
<ProductImagesContext.Provider value={contextValue}>
|
|
70
72
|
<Grid size={{ md: 6, xs: 12 }} alignItems="center">
|
|
71
73
|
{children}
|
|
72
74
|
</Grid>
|
|
@@ -78,7 +80,7 @@ export default function ProductImages({ children }: Readonly<Props>) {
|
|
|
78
80
|
* The image gallery thumbnails, when clicked switches the main image.
|
|
79
81
|
* @category Sub-Component
|
|
80
82
|
*/
|
|
81
|
-
|
|
83
|
+
const ProductImagesThumbnails = () => {
|
|
82
84
|
const ctx = useContext(ProductImagesContext);
|
|
83
85
|
if (!ctx)
|
|
84
86
|
throw new Error(
|
|
@@ -113,12 +115,14 @@ ProductImages.Thumbnails = () => {
|
|
|
113
115
|
);
|
|
114
116
|
};
|
|
115
117
|
|
|
118
|
+
ProductImages.Thumbnails = ProductImagesThumbnails;
|
|
119
|
+
|
|
116
120
|
/**
|
|
117
121
|
* Main large image on PDP that displays currently selected image from
|
|
118
122
|
* product details.
|
|
119
123
|
* @category Sub-Component
|
|
120
124
|
*/
|
|
121
|
-
|
|
125
|
+
const ProductImagesMain = () => {
|
|
122
126
|
const ctx = useContext(ProductImagesContext);
|
|
123
127
|
if (!ctx)
|
|
124
128
|
throw new Error(
|
|
@@ -162,3 +166,5 @@ ProductImages.Main = () => {
|
|
|
162
166
|
</FlexBox>
|
|
163
167
|
);
|
|
164
168
|
};
|
|
169
|
+
|
|
170
|
+
ProductImages.Main = ProductImagesMain;
|
|
@@ -7,6 +7,7 @@ import ProductImages from "@evenicanpm/storefront-core/src/pages/product-details
|
|
|
7
7
|
import Box from "@mui/material/Box";
|
|
8
8
|
import Grid from "@mui/material/Grid2";
|
|
9
9
|
import type React from "react";
|
|
10
|
+
import { useMemo } from "react";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Master product data comes in as prop, selected variant details are called
|
|
@@ -23,18 +24,27 @@ export default function ProductIntro({ product, children }: Readonly<Props>) {
|
|
|
23
24
|
allDimensionsSelected,
|
|
24
25
|
variantPending,
|
|
25
26
|
} = useVariants(product);
|
|
27
|
+
const contextValue = useMemo(
|
|
28
|
+
() => ({
|
|
29
|
+
masterProduct: product,
|
|
30
|
+
allDimensionsSelected,
|
|
31
|
+
variantPending,
|
|
32
|
+
selectedVariant,
|
|
33
|
+
selectDimensions,
|
|
34
|
+
handleChangeVariant,
|
|
35
|
+
}),
|
|
36
|
+
[
|
|
37
|
+
product,
|
|
38
|
+
allDimensionsSelected,
|
|
39
|
+
variantPending,
|
|
40
|
+
selectedVariant,
|
|
41
|
+
selectDimensions,
|
|
42
|
+
handleChangeVariant,
|
|
43
|
+
],
|
|
44
|
+
);
|
|
26
45
|
|
|
27
46
|
return (
|
|
28
|
-
<ProductIntroContext.Provider
|
|
29
|
-
value={{
|
|
30
|
-
masterProduct: product,
|
|
31
|
-
allDimensionsSelected,
|
|
32
|
-
variantPending,
|
|
33
|
-
selectedVariant,
|
|
34
|
-
selectDimensions,
|
|
35
|
-
handleChangeVariant,
|
|
36
|
-
}}
|
|
37
|
-
>
|
|
47
|
+
<ProductIntroContext.Provider value={contextValue}>
|
|
38
48
|
<Box width="100%">
|
|
39
49
|
<Grid container spacing={3} justifyContent="space-around">
|
|
40
50
|
{children}
|