@evenicanpm/storefront-core 2.4.1 → 2.5.0
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 +16 -0
- package/package.json +1 -1
- 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/sections/footer-contact.tsx +0 -2
- package/src/cms/blocks/components/footer/sections/footer-logo.tsx +2 -1
- 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/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
|
@@ -11,7 +11,7 @@ import { withZodSchema } from "formik-validator-zod";
|
|
|
11
11
|
import isFunction from "lodash/isFunction";
|
|
12
12
|
import { useTranslations } from "next-intl";
|
|
13
13
|
import type React from "react";
|
|
14
|
-
import { createContext } from "react";
|
|
14
|
+
import { createContext, useMemo } from "react";
|
|
15
15
|
import { z } from "zod";
|
|
16
16
|
|
|
17
17
|
interface Props {
|
|
@@ -82,9 +82,13 @@ export default function CreateNewList(props: Readonly<Props>) {
|
|
|
82
82
|
resetForm();
|
|
83
83
|
}
|
|
84
84
|
};
|
|
85
|
+
const contextValue = useMemo(
|
|
86
|
+
() => ({ formik, handleClose }),
|
|
87
|
+
[formik, handleClose],
|
|
88
|
+
);
|
|
85
89
|
|
|
86
90
|
return (
|
|
87
|
-
<CreateNewWishlistContext.Provider value={
|
|
91
|
+
<CreateNewWishlistContext.Provider value={contextValue}>
|
|
88
92
|
<Dialog open={props.open} onClose={handleClose}>
|
|
89
93
|
<DialogContent>
|
|
90
94
|
{isSubmitting ? <CircularProgress /> : children}
|
|
@@ -4,8 +4,8 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|
|
4
4
|
|
|
5
5
|
export default function useOverflowDetect() {
|
|
6
6
|
const elementRef = useRef<HTMLElement | null>(null);
|
|
7
|
-
const [isLeftOverflowing,
|
|
8
|
-
const [isRightOverflowing,
|
|
7
|
+
const [isLeftOverflowing, setIsLeftOverflowing] = useState(false);
|
|
8
|
+
const [isRightOverflowing, setIsRightOverflowing] = useState(false);
|
|
9
9
|
|
|
10
10
|
const checkOverflow = useCallback(() => {
|
|
11
11
|
const element = elementRef.current;
|
|
@@ -15,9 +15,9 @@ export default function useOverflowDetect() {
|
|
|
15
15
|
const viewportWidth =
|
|
16
16
|
window.innerWidth || document.documentElement.clientWidth;
|
|
17
17
|
|
|
18
|
-
if (elementRect.left < 0)
|
|
18
|
+
if (elementRect.left < 0) setIsLeftOverflowing(true);
|
|
19
19
|
|
|
20
|
-
if (elementRect.right > viewportWidth)
|
|
20
|
+
if (elementRect.right > viewportWidth) setIsRightOverflowing(true);
|
|
21
21
|
}
|
|
22
22
|
}, []);
|
|
23
23
|
|
package/src/lib/page-slugs.ts
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Central registry of URL path segments for storefront pages.
|
|
3
|
+
*
|
|
4
|
+
* Use these constants instead of hardcoding path strings inline.
|
|
5
|
+
* Values are bare slugs (no leading slash) so they can be composed
|
|
6
|
+
* freely into full paths or passed to URL constructors.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* // Building a product detail URL
|
|
10
|
+
* `/${PageSlug.ProductDetail}/${slug}/${id}`
|
|
11
|
+
*
|
|
12
|
+
* // Navigating to the product list
|
|
13
|
+
* new URL(PageSlug.ProductList, globalThis.location.origin)
|
|
14
|
+
*
|
|
15
|
+
* Add new entries here when introducing new top-level pages.
|
|
16
|
+
*/
|
|
1
17
|
export const PageSlug = {
|
|
2
18
|
ProductDetail: "product",
|
|
3
19
|
ProductList: "products",
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
} from "@evenicanpm/storefront-core/src/components/Typography";
|
|
12
12
|
import {
|
|
13
13
|
type AccountRoute,
|
|
14
|
-
type AccountRouteOverrides,
|
|
15
14
|
useCreateAccountRoutes,
|
|
16
15
|
} from "@evenicanpm/storefront-core/src/pages/account/account-routes";
|
|
17
16
|
// STYLED COMPONENTS
|
|
@@ -21,7 +20,7 @@ import {
|
|
|
21
20
|
} from "@evenicanpm/storefront-core/src/pages/account/styles";
|
|
22
21
|
import { usePathname } from "next/navigation";
|
|
23
22
|
import { useTranslations } from "next-intl";
|
|
24
|
-
import { createContext, Fragment, type ReactNode } from "react";
|
|
23
|
+
import { createContext, Fragment, type ReactNode, useMemo } from "react";
|
|
25
24
|
import type { IconType } from "react-icons";
|
|
26
25
|
|
|
27
26
|
/**
|
|
@@ -82,10 +81,8 @@ const routeToNavItem = (route: AccountRoute): NavItem => {
|
|
|
82
81
|
};
|
|
83
82
|
};
|
|
84
83
|
|
|
85
|
-
export const DEFAULT_MENU_ITEMS = (
|
|
86
|
-
|
|
87
|
-
): NavSection[] => {
|
|
88
|
-
const routes = useCreateAccountRoutes(overrides);
|
|
84
|
+
export const DEFAULT_MENU_ITEMS = (): NavSection[] => {
|
|
85
|
+
const routes = useCreateAccountRoutes();
|
|
89
86
|
return [
|
|
90
87
|
{
|
|
91
88
|
title: "DASHBOARD",
|
|
@@ -112,21 +109,16 @@ const AccountNavigationContext =
|
|
|
112
109
|
interface AccountNavigationProps {
|
|
113
110
|
items?: NavSection[];
|
|
114
111
|
children?: ReactNode;
|
|
115
|
-
routeOverrides?: AccountRouteOverrides;
|
|
116
112
|
}
|
|
117
113
|
|
|
118
|
-
const AccountNavigation = ({
|
|
119
|
-
items,
|
|
120
|
-
children,
|
|
121
|
-
routeOverrides,
|
|
122
|
-
}: AccountNavigationProps) => {
|
|
114
|
+
const AccountNavigation = ({ items, children }: AccountNavigationProps) => {
|
|
123
115
|
const pathname = usePathname();
|
|
124
116
|
const t = useTranslations("Account.Menu");
|
|
125
117
|
|
|
126
118
|
const { data: user } = getUser.useData();
|
|
127
119
|
const { data: counts } = getUserCounts.useData(String(user?.RecordId) || "");
|
|
128
120
|
|
|
129
|
-
const defaultItems = DEFAULT_MENU_ITEMS(
|
|
121
|
+
const defaultItems = DEFAULT_MENU_ITEMS();
|
|
130
122
|
|
|
131
123
|
// Render either the props items or the default items
|
|
132
124
|
const itemsWCounts = (items || defaultItems).map((section) => ({
|
|
@@ -141,9 +133,10 @@ const AccountNavigation = ({
|
|
|
141
133
|
return item;
|
|
142
134
|
}),
|
|
143
135
|
}));
|
|
136
|
+
const contextValue = useMemo(() => ({ items: itemsWCounts }), [itemsWCounts]);
|
|
144
137
|
|
|
145
138
|
return (
|
|
146
|
-
<AccountNavigationContext.Provider value={
|
|
139
|
+
<AccountNavigationContext.Provider value={contextValue}>
|
|
147
140
|
<MainContainer>
|
|
148
141
|
{children ||
|
|
149
142
|
itemsWCounts.map((section) => (
|
|
@@ -64,23 +64,18 @@ export const RoutesOverrideContext = createContext<
|
|
|
64
64
|
export type AccountRouteKey = keyof typeof defaults;
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
|
-
* Hook that builds the account routes map, merging defaults with
|
|
68
|
-
*
|
|
69
|
-
* 1. `overrides` parameter passed directly to the hook
|
|
70
|
-
* 2. Values from {@link RoutesOverrideContext}
|
|
71
|
-
* 3. Built-in defaults
|
|
67
|
+
* Hook that builds the account routes map, merging defaults with any overrides
|
|
68
|
+
* supplied via {@link RoutesOverrideContext}.
|
|
72
69
|
*
|
|
73
|
-
* @
|
|
74
|
-
* @returns The full set of account routes with any overrides merged in
|
|
70
|
+
* @returns The full set of account routes with context overrides merged in
|
|
75
71
|
*/
|
|
76
|
-
export const useCreateAccountRoutes = (
|
|
72
|
+
export const useCreateAccountRoutes = () => {
|
|
77
73
|
const ctxOverrides = useContext(RoutesOverrideContext);
|
|
78
74
|
return {
|
|
79
75
|
...defaults,
|
|
80
76
|
wishlists: {
|
|
81
77
|
...defaults.wishlists,
|
|
82
78
|
...ctxOverrides?.wishlists,
|
|
83
|
-
...overrides?.wishlists,
|
|
84
79
|
},
|
|
85
80
|
};
|
|
86
81
|
};
|
|
@@ -26,7 +26,7 @@ import { withZodSchema } from "formik-validator-zod";
|
|
|
26
26
|
import _ from "lodash";
|
|
27
27
|
import { useRouter } from "next/navigation";
|
|
28
28
|
import { useLocale, useTranslations } from "next-intl";
|
|
29
|
-
import React, { createContext, useContext, useRef } from "react";
|
|
29
|
+
import React, { createContext, useContext, useMemo, useRef } from "react";
|
|
30
30
|
import { z } from "zod";
|
|
31
31
|
|
|
32
32
|
interface AddressFormValues {
|
|
@@ -61,11 +61,15 @@ const AddressForm = ({ address, children }: RootProps) => {
|
|
|
61
61
|
const locale = useLocale();
|
|
62
62
|
|
|
63
63
|
const { data: countries } = getCountries.useData({ locale });
|
|
64
|
-
const defaultCountry = countries
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
const defaultCountry = Array.isArray(countries)
|
|
65
|
+
? countries?.find(
|
|
66
|
+
(c) => c.CountryRegionId === address?.ThreeLetterISORegionName,
|
|
67
|
+
)
|
|
68
|
+
: null;
|
|
69
|
+
|
|
67
70
|
const [selectedCountry, setSelectedCountry] =
|
|
68
71
|
React.useState<CountryRegionInfo | null>(defaultCountry ?? null);
|
|
72
|
+
|
|
69
73
|
const { data: states } = getStates.useData({
|
|
70
74
|
countryId: selectedCountry?.CountryRegionId,
|
|
71
75
|
});
|
|
@@ -142,11 +146,19 @@ const AddressForm = ({ address, children }: RootProps) => {
|
|
|
142
146
|
onSubmit: handleSubmit,
|
|
143
147
|
validate: withZodSchema(FormSchema),
|
|
144
148
|
});
|
|
149
|
+
const contextValue = useMemo(
|
|
150
|
+
() => ({
|
|
151
|
+
formik,
|
|
152
|
+
countries,
|
|
153
|
+
states,
|
|
154
|
+
selectedCountry,
|
|
155
|
+
setSelectedCountry,
|
|
156
|
+
}),
|
|
157
|
+
[formik, countries, states, selectedCountry, setSelectedCountry],
|
|
158
|
+
);
|
|
145
159
|
|
|
146
160
|
return (
|
|
147
|
-
<FormContext.Provider
|
|
148
|
-
value={{ formik, countries, states, selectedCountry, setSelectedCountry }}
|
|
149
|
-
>
|
|
161
|
+
<FormContext.Provider value={contextValue}>
|
|
150
162
|
<form onSubmit={formik.handleSubmit}>{children}</form>
|
|
151
163
|
</FormContext.Provider>
|
|
152
164
|
);
|
|
@@ -167,7 +179,7 @@ AddressForm.Fields = ({ children }: { children?: React.ReactNode }) => {
|
|
|
167
179
|
);
|
|
168
180
|
};
|
|
169
181
|
|
|
170
|
-
|
|
182
|
+
const AddressFormField = ({ name, label, required }: FieldProps) => {
|
|
171
183
|
const ctx = useContext(FormContext);
|
|
172
184
|
const t = useTranslations("Address");
|
|
173
185
|
if (!ctx) return null;
|
|
@@ -194,7 +206,9 @@ AddressForm.Field = ({ name, label, required }: FieldProps) => {
|
|
|
194
206
|
);
|
|
195
207
|
};
|
|
196
208
|
|
|
197
|
-
AddressForm.
|
|
209
|
+
AddressForm.Field = AddressFormField;
|
|
210
|
+
|
|
211
|
+
const AddressFormCountry = () => {
|
|
198
212
|
const ctx = useContext(FormContext);
|
|
199
213
|
const t = useTranslations("Address");
|
|
200
214
|
if (!ctx) return null;
|
|
@@ -226,11 +240,13 @@ AddressForm.Country = () => {
|
|
|
226
240
|
}}
|
|
227
241
|
>
|
|
228
242
|
<MenuItem value="">Select Country</MenuItem>
|
|
229
|
-
{countries
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
243
|
+
{Array.isArray(countries) &&
|
|
244
|
+
countries.length > 0 &&
|
|
245
|
+
countries?.map(({ ShortName, CountryRegionId }) => (
|
|
246
|
+
<MenuItem key={CountryRegionId} value={CountryRegionId}>
|
|
247
|
+
{ShortName}
|
|
248
|
+
</MenuItem>
|
|
249
|
+
))}
|
|
234
250
|
</Select>
|
|
235
251
|
{formik.touched.Country &&
|
|
236
252
|
formik.errors.Country &&
|
|
@@ -244,7 +260,9 @@ AddressForm.Country = () => {
|
|
|
244
260
|
);
|
|
245
261
|
};
|
|
246
262
|
|
|
247
|
-
AddressForm.
|
|
263
|
+
AddressForm.Country = AddressFormCountry;
|
|
264
|
+
|
|
265
|
+
const AddressFormState = () => {
|
|
248
266
|
const ctx = useContext(FormContext);
|
|
249
267
|
const t = useTranslations("Address");
|
|
250
268
|
if (!ctx) return null;
|
|
@@ -287,6 +305,8 @@ AddressForm.State = () => {
|
|
|
287
305
|
);
|
|
288
306
|
};
|
|
289
307
|
|
|
308
|
+
AddressForm.State = AddressFormState;
|
|
309
|
+
|
|
290
310
|
AddressForm.Actions = ({ children }: { children?: React.ReactNode }) => {
|
|
291
311
|
return (
|
|
292
312
|
<Grid size={{ sm: 6, xs: 12 }} sx={{ mt: 3 }}>
|
|
@@ -295,7 +315,7 @@ AddressForm.Actions = ({ children }: { children?: React.ReactNode }) => {
|
|
|
295
315
|
);
|
|
296
316
|
};
|
|
297
317
|
|
|
298
|
-
|
|
318
|
+
const AddressFormSubmitButton = () => {
|
|
299
319
|
const t = useTranslations("Address");
|
|
300
320
|
const ctx = useContext(FormContext);
|
|
301
321
|
const isSubmitting = ctx?.formik.isSubmitting ?? false;
|
|
@@ -316,4 +336,6 @@ AddressForm.SubmitButton = () => {
|
|
|
316
336
|
);
|
|
317
337
|
};
|
|
318
338
|
|
|
339
|
+
AddressForm.SubmitButton = AddressFormSubmitButton;
|
|
340
|
+
|
|
319
341
|
export default AddressForm;
|
|
@@ -13,7 +13,7 @@ import IconButton from "@mui/material/IconButton";
|
|
|
13
13
|
import type { SxProps } from "@mui/material/styles";
|
|
14
14
|
import { useRouter } from "next/navigation";
|
|
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
|
// ICONS
|
|
18
18
|
import { MdDelete as Delete, MdEdit as Edit } from "react-icons/md";
|
|
19
19
|
|
|
@@ -61,11 +61,13 @@ const AddressListItem = ({ address, children, sx }: RootProps) => {
|
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
63
|
};
|
|
64
|
+
const contextValue = useMemo(
|
|
65
|
+
() => ({ address, setPrimaryAddress, editAddress, handleDelete }),
|
|
66
|
+
[address, setPrimaryAddress, editAddress, handleDelete],
|
|
67
|
+
);
|
|
64
68
|
|
|
65
69
|
return (
|
|
66
|
-
<AddressContext.Provider
|
|
67
|
-
value={{ address, setPrimaryAddress, editAddress, handleDelete }}
|
|
68
|
-
>
|
|
70
|
+
<AddressContext.Provider value={contextValue}>
|
|
69
71
|
<TableRow
|
|
70
72
|
sx={{
|
|
71
73
|
display: "grid",
|
|
@@ -89,7 +91,7 @@ interface FieldProps {
|
|
|
89
91
|
render?: (value: FieldValue, address: Address) => ReactNode;
|
|
90
92
|
}
|
|
91
93
|
|
|
92
|
-
|
|
94
|
+
const AddressListItemField = ({ field, render }: FieldProps) => {
|
|
93
95
|
const ctx = useContext(AddressContext);
|
|
94
96
|
if (!ctx) return null;
|
|
95
97
|
const { address } = ctx;
|
|
@@ -105,6 +107,8 @@ AddressListItem.Field = ({ field, render }: FieldProps) => {
|
|
|
105
107
|
);
|
|
106
108
|
};
|
|
107
109
|
|
|
110
|
+
AddressListItem.Field = AddressListItemField;
|
|
111
|
+
|
|
108
112
|
AddressListItem.Actions = ({ children }: { children: ReactNode }) => {
|
|
109
113
|
return (
|
|
110
114
|
<Box display="flex" alignItems="center" gap={1} justifySelf="end">
|
|
@@ -113,7 +117,7 @@ AddressListItem.Actions = ({ children }: { children: ReactNode }) => {
|
|
|
113
117
|
);
|
|
114
118
|
};
|
|
115
119
|
|
|
116
|
-
|
|
120
|
+
const AddressListItemPrimary = () => {
|
|
117
121
|
const ctx = useContext(AddressContext);
|
|
118
122
|
const t = useTranslations("Account.Addresses");
|
|
119
123
|
if (!ctx) return null;
|
|
@@ -135,7 +139,9 @@ AddressListItem.Primary = () => {
|
|
|
135
139
|
);
|
|
136
140
|
};
|
|
137
141
|
|
|
138
|
-
AddressListItem.
|
|
142
|
+
AddressListItem.Primary = AddressListItemPrimary;
|
|
143
|
+
|
|
144
|
+
const AddressListItemEdit = () => {
|
|
139
145
|
const ctx = useContext(AddressContext);
|
|
140
146
|
if (!ctx) return null;
|
|
141
147
|
const { address, editAddress } = ctx;
|
|
@@ -149,7 +155,9 @@ AddressListItem.Edit = () => {
|
|
|
149
155
|
);
|
|
150
156
|
};
|
|
151
157
|
|
|
152
|
-
AddressListItem.
|
|
158
|
+
AddressListItem.Edit = AddressListItemEdit;
|
|
159
|
+
|
|
160
|
+
const AddressListItemDelete = () => {
|
|
153
161
|
const ctx = useContext(AddressContext);
|
|
154
162
|
if (!ctx) return null;
|
|
155
163
|
const { address, handleDelete } = ctx;
|
|
@@ -163,4 +171,6 @@ AddressListItem.Delete = () => {
|
|
|
163
171
|
);
|
|
164
172
|
};
|
|
165
173
|
|
|
174
|
+
AddressListItem.Delete = AddressListItemDelete;
|
|
175
|
+
|
|
166
176
|
export default AddressListItem;
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "@mui/material";
|
|
16
16
|
import Link from "next/link";
|
|
17
17
|
import { useTranslations } from "next-intl";
|
|
18
|
-
import { createContext, type ReactNode, useContext } from "react";
|
|
18
|
+
import { createContext, type ReactNode, useContext, useMemo } from "react";
|
|
19
19
|
import type { IconType } from "react-icons";
|
|
20
20
|
import { MdMenu as Menu } from "react-icons/md";
|
|
21
21
|
|
|
@@ -44,14 +44,22 @@ const DashboardHeaderContext =
|
|
|
44
44
|
interface RootProps {
|
|
45
45
|
children: ReactNode;
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
const renderSideNavMenuButton = (close: () => void) => (
|
|
49
|
+
<IconButton onClick={close}>
|
|
50
|
+
<Menu fontSize="small" />
|
|
51
|
+
</IconButton>
|
|
52
|
+
);
|
|
53
|
+
|
|
47
54
|
const DashboardHeader = ({ children }: RootProps) => {
|
|
48
55
|
const t = useTranslations();
|
|
49
56
|
const isTablet = useMediaQuery((theme: Theme) =>
|
|
50
57
|
theme.breakpoints.down(1025),
|
|
51
58
|
);
|
|
59
|
+
const contextValue = useMemo(() => ({ isTablet, t }), [isTablet, t]);
|
|
52
60
|
|
|
53
61
|
return (
|
|
54
|
-
<DashboardHeaderContext.Provider value={
|
|
62
|
+
<DashboardHeaderContext.Provider value={contextValue}>
|
|
55
63
|
<StyledBox>
|
|
56
64
|
<FlexBox mt={2} className="headerHold">
|
|
57
65
|
{children}
|
|
@@ -61,7 +69,7 @@ const DashboardHeader = ({ children }: RootProps) => {
|
|
|
61
69
|
);
|
|
62
70
|
};
|
|
63
71
|
|
|
64
|
-
|
|
72
|
+
const DashboardHeaderTitle = ({
|
|
65
73
|
title,
|
|
66
74
|
titleMessage,
|
|
67
75
|
Icon,
|
|
@@ -87,7 +95,9 @@ DashboardHeader.Title = ({
|
|
|
87
95
|
);
|
|
88
96
|
};
|
|
89
97
|
|
|
90
|
-
DashboardHeader.
|
|
98
|
+
DashboardHeader.Title = DashboardHeaderTitle;
|
|
99
|
+
|
|
100
|
+
const DashboardHeaderButtons = ({ children }: { children: ReactNode }) => {
|
|
91
101
|
const ctx = useContext(DashboardHeaderContext);
|
|
92
102
|
if (!ctx) return null;
|
|
93
103
|
const { isTablet } = ctx;
|
|
@@ -108,7 +118,9 @@ DashboardHeader.Buttons = ({ children }: { children: ReactNode }) => {
|
|
|
108
118
|
);
|
|
109
119
|
};
|
|
110
120
|
|
|
111
|
-
DashboardHeader.
|
|
121
|
+
DashboardHeader.Buttons = DashboardHeaderButtons;
|
|
122
|
+
|
|
123
|
+
const DashboardHeaderGeneratedButton = ({
|
|
112
124
|
href,
|
|
113
125
|
text,
|
|
114
126
|
}: {
|
|
@@ -130,17 +142,12 @@ DashboardHeader.GeneratedButton = ({
|
|
|
130
142
|
);
|
|
131
143
|
};
|
|
132
144
|
|
|
145
|
+
DashboardHeader.GeneratedButton = DashboardHeaderGeneratedButton;
|
|
146
|
+
|
|
133
147
|
DashboardHeader.SideNav = ({ children }: { children?: ReactNode }) => {
|
|
134
148
|
return (
|
|
135
149
|
<div className="sidenav">
|
|
136
|
-
<SideNav
|
|
137
|
-
position="left"
|
|
138
|
-
handler={(close) => (
|
|
139
|
-
<IconButton onClick={close}>
|
|
140
|
-
<Menu fontSize="small" />
|
|
141
|
-
</IconButton>
|
|
142
|
-
)}
|
|
143
|
-
>
|
|
150
|
+
<SideNav position="left" handler={renderSideNavMenuButton}>
|
|
144
151
|
{children ?? <Navigation />}
|
|
145
152
|
</SideNav>
|
|
146
153
|
</div>
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type FilterOption,
|
|
21
21
|
FilterSourceType,
|
|
22
22
|
type OrderStatusFilter,
|
|
23
|
+
type OriginFilter,
|
|
23
24
|
} from "./order-history-filter-types";
|
|
24
25
|
import { useOrdersSearchAndFilter } from "./order-history-search-and-filter";
|
|
25
26
|
|
|
@@ -155,9 +156,9 @@ const OrdersFilterPanel = ({ children }: { children: React.ReactNode }) => {
|
|
|
155
156
|
</Button>
|
|
156
157
|
<Box>
|
|
157
158
|
{activeFilters.length > 0 &&
|
|
158
|
-
activeFilters.map((filter
|
|
159
|
+
activeFilters.map((filter) => (
|
|
159
160
|
<Box
|
|
160
|
-
key={
|
|
161
|
+
key={`${filter?.sourceType}-${filter?.label}`}
|
|
161
162
|
sx={{
|
|
162
163
|
display: "inline-flex",
|
|
163
164
|
alignItems: "center",
|
|
@@ -247,13 +248,13 @@ const OriginsFilterList = () => {
|
|
|
247
248
|
flexWrap: "nowrap",
|
|
248
249
|
}}
|
|
249
250
|
>
|
|
250
|
-
{originOptions.map((originOption
|
|
251
|
+
{originOptions.map((originOption: OriginFilter) => (
|
|
251
252
|
<FormControlLabel
|
|
252
|
-
key={
|
|
253
|
+
key={`${originOption?.value}-${originOption?.label}`}
|
|
253
254
|
control={
|
|
254
255
|
<Checkbox
|
|
255
256
|
checked={selectedOrigins.some(
|
|
256
|
-
(o) => o.value === originOption.value,
|
|
257
|
+
(o: OriginFilter) => o.value === originOption.value,
|
|
257
258
|
)}
|
|
258
259
|
onChange={() => handleSelectOrigin(originOption)}
|
|
259
260
|
/>
|
|
@@ -267,7 +268,8 @@ const OriginsFilterList = () => {
|
|
|
267
268
|
};
|
|
268
269
|
|
|
269
270
|
const CreatedDateFilterList = () => {
|
|
270
|
-
const { createdDate, handleSelectCreatedDate } =
|
|
271
|
+
const { createdDate, handleSelectCreatedDate, handleSetCreatedDate } =
|
|
272
|
+
useOrdersSearchAndFilter();
|
|
271
273
|
const t = useTranslations("Account.Orders");
|
|
272
274
|
|
|
273
275
|
return (
|
|
@@ -277,8 +279,8 @@ const CreatedDateFilterList = () => {
|
|
|
277
279
|
</Typography>
|
|
278
280
|
<Divider />
|
|
279
281
|
<RadioGroup value={createdDate?.label ?? ""}>
|
|
280
|
-
{createdDateOptions.map((createdDateOption
|
|
281
|
-
<div key={
|
|
282
|
+
{createdDateOptions.map((createdDateOption) => (
|
|
283
|
+
<div key={createdDateOption.label}>
|
|
282
284
|
<FormControlLabel
|
|
283
285
|
key={createdDateOption.label}
|
|
284
286
|
value={createdDateOption.label}
|
|
@@ -292,18 +294,17 @@ const CreatedDateFilterList = () => {
|
|
|
292
294
|
label={createdDateOption.label}
|
|
293
295
|
/>
|
|
294
296
|
{createdDateOption.label === "Custom Dates" &&
|
|
295
|
-
createdDate &&
|
|
296
|
-
createdDate.label === "Custom Dates" && (
|
|
297
|
+
createdDate?.label === "Custom Dates" && (
|
|
297
298
|
<Box mt={1} display="flex" flexDirection="column" gap={2}>
|
|
298
299
|
<TextField
|
|
299
300
|
label="From"
|
|
300
301
|
type="date"
|
|
301
302
|
value={createdDate?.startValue || ""}
|
|
302
|
-
onChange={(e) =>
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
)
|
|
303
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
304
|
+
handleSetCreatedDate({
|
|
305
|
+
...createdDate,
|
|
306
|
+
startValue: e.target.value,
|
|
307
|
+
})
|
|
307
308
|
}
|
|
308
309
|
slotProps={{
|
|
309
310
|
inputLabel: {
|
|
@@ -316,11 +317,11 @@ const CreatedDateFilterList = () => {
|
|
|
316
317
|
label="To"
|
|
317
318
|
type="date"
|
|
318
319
|
value={createdDate?.endValue || ""}
|
|
319
|
-
onChange={(e) =>
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
)
|
|
320
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
321
|
+
handleSetCreatedDate({
|
|
322
|
+
...createdDate,
|
|
323
|
+
endValue: e.target.value,
|
|
324
|
+
})
|
|
324
325
|
}
|
|
325
326
|
slotProps={{
|
|
326
327
|
inputLabel: {
|
|
@@ -25,17 +25,21 @@ const OrderHistoryTableHeader = ({
|
|
|
25
25
|
);
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
const OrderHistoryTableHeaderOrderNumber = () => {
|
|
29
29
|
const t = useTranslations("Account.Orders");
|
|
30
30
|
return <Paragraph ellipsis>{t("orderNumberHeader")}</Paragraph>;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
OrderHistoryTableHeader.
|
|
33
|
+
OrderHistoryTableHeader.OrderNumber = OrderHistoryTableHeaderOrderNumber;
|
|
34
|
+
|
|
35
|
+
const OrderHistoryTableHeaderOrderStatus = () => {
|
|
34
36
|
const t = useTranslations("Account.Orders");
|
|
35
37
|
return <Box textAlign="center">{t("orderStatusHeader")}</Box>;
|
|
36
38
|
};
|
|
37
39
|
|
|
38
|
-
OrderHistoryTableHeader.
|
|
40
|
+
OrderHistoryTableHeader.OrderStatus = OrderHistoryTableHeaderOrderStatus;
|
|
41
|
+
|
|
42
|
+
const OrderHistoryTableHeaderTransactionDate = () => {
|
|
39
43
|
const t = useTranslations("Account.Orders");
|
|
40
44
|
return (
|
|
41
45
|
<Paragraph textAlign={{ sm: "center", xs: "left" }}>
|
|
@@ -44,11 +48,17 @@ OrderHistoryTableHeader.TransactionDate = () => {
|
|
|
44
48
|
);
|
|
45
49
|
};
|
|
46
50
|
|
|
47
|
-
OrderHistoryTableHeader.
|
|
51
|
+
OrderHistoryTableHeader.TransactionDate =
|
|
52
|
+
OrderHistoryTableHeaderTransactionDate;
|
|
53
|
+
|
|
54
|
+
const OrderHistoryTableHeaderTransactionAmount = () => {
|
|
48
55
|
const t = useTranslations("Account.Orders");
|
|
49
56
|
return (
|
|
50
57
|
<Paragraph textAlign="center">{t("transactionAmountHeader")}</Paragraph>
|
|
51
58
|
);
|
|
52
59
|
};
|
|
53
60
|
|
|
61
|
+
OrderHistoryTableHeader.TransactionAmount =
|
|
62
|
+
OrderHistoryTableHeaderTransactionAmount;
|
|
63
|
+
|
|
54
64
|
export default OrderHistoryTableHeader;
|
|
@@ -74,11 +74,13 @@ const OrderHistory = ({ children }: { children: React.ReactNode }) => {
|
|
|
74
74
|
|
|
75
75
|
OrderHistory.SearchAndFilter = OrdersSearchAndFilter;
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
const OrderHistorySort = () => {
|
|
78
78
|
const { setSortColumn } = useOrderHistory();
|
|
79
79
|
return <OrdersSort setSortColumn={setSortColumn} />;
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
+
OrderHistory.Sort = OrderHistorySort;
|
|
83
|
+
|
|
82
84
|
OrderHistory.Table = OrderHistoryTable;
|
|
83
85
|
|
|
84
86
|
// OrderHistory.Table = () => {
|
|
@@ -62,12 +62,14 @@ const OrderHistoryTableRow = ({ children }: { children: React.ReactNode }) => {
|
|
|
62
62
|
);
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
const OrderHistoryTableRowOrderNumber = () => {
|
|
66
66
|
const { order } = useOrderHistoryTableRow();
|
|
67
67
|
return <H6 ellipsis>{order?.ChannelReferenceId}</H6>;
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
-
OrderHistoryTableRow.
|
|
70
|
+
OrderHistoryTableRow.OrderNumber = OrderHistoryTableRowOrderNumber;
|
|
71
|
+
|
|
72
|
+
const OrderHistoryTableRowOrderStatus = () => {
|
|
71
73
|
const { order } = useOrderHistoryTableRow();
|
|
72
74
|
const { label, color } = getStatusInfo(order.StatusValue ?? 0);
|
|
73
75
|
return (
|
|
@@ -77,7 +79,9 @@ OrderHistoryTableRow.OrderStatus = () => {
|
|
|
77
79
|
);
|
|
78
80
|
};
|
|
79
81
|
|
|
80
|
-
OrderHistoryTableRow.
|
|
82
|
+
OrderHistoryTableRow.OrderStatus = OrderHistoryTableRowOrderStatus;
|
|
83
|
+
|
|
84
|
+
const OrderHistoryTableRowTransactionDate = () => {
|
|
81
85
|
const { order } = useOrderHistoryTableRow();
|
|
82
86
|
return (
|
|
83
87
|
<Paragraph textAlign={{ sm: "center", xs: "left" }}>
|
|
@@ -86,7 +90,9 @@ OrderHistoryTableRow.TransactionDate = () => {
|
|
|
86
90
|
);
|
|
87
91
|
};
|
|
88
92
|
|
|
89
|
-
OrderHistoryTableRow.
|
|
93
|
+
OrderHistoryTableRow.TransactionDate = OrderHistoryTableRowTransactionDate;
|
|
94
|
+
|
|
95
|
+
const OrderHistoryTableRowTransactionAmount = () => {
|
|
90
96
|
const { order } = useOrderHistoryTableRow();
|
|
91
97
|
const { formatCurrency } = useCurrencyFormatter();
|
|
92
98
|
|
|
@@ -97,6 +103,8 @@ OrderHistoryTableRow.TransactionAmount = () => {
|
|
|
97
103
|
);
|
|
98
104
|
};
|
|
99
105
|
|
|
106
|
+
OrderHistoryTableRow.TransactionAmount = OrderHistoryTableRowTransactionAmount;
|
|
107
|
+
|
|
100
108
|
OrderHistoryTableRow.DetailsIcon = () => {
|
|
101
109
|
return (
|
|
102
110
|
<Box display={{ sm: "inline-flex", xs: "none" }} justifyContent="end">
|