@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.
- package/package.json +3 -2
- package/src/api-manager/api-manager.config.json +1 -1
- package/src/api-manager/datasources/d365/d365-address.datasource.ts +4 -4
- package/src/api-manager/datasources/d365/d365-cart.datasource.ts +100 -7
- package/src/api-manager/datasources/d365/d365-product.datasource.ts +39 -17
- package/src/api-manager/datasources/d365/d365-user.datasource.ts +220 -68
- package/src/api-manager/datasources/d365/utils/decode-jwt.ts +2 -2
- package/src/api-manager/datasources/e4/e4-cart.datasource.ts +6 -0
- package/src/api-manager/datasources/e4/e4-product.datasource.ts +22 -2
- package/src/api-manager/datasources/e4/e4.datasource.ts +1 -1
- package/src/api-manager/datasources/e4/e4.remaps.ts +24 -0
- package/src/api-manager/datasources/e4/e4.translator.ts +19 -1
- package/src/api-manager/datasources/e4/{e4-user.datasource.ts → user/e4-user.datasource.ts} +41 -19
- package/src/api-manager/datasources/e4/user/e4-user.remaps.ts +4 -0
- package/src/api-manager/datasources/e4/user/e4-user.translator.ts +10 -0
- package/src/api-manager/index.ts +77 -15
- package/src/api-manager/lib/get-graphql-client.ts +7 -7
- package/src/api-manager/schemas/address.schema.ts +1 -19
- package/src/api-manager/schemas/cart.schema.ts +18 -0
- package/src/api-manager/schemas/product.schema.ts +8 -1
- package/src/api-manager/schemas/user.schema.ts +52 -1
- package/src/api-manager/services/address/queries/get-states.ts +1 -1
- package/src/api-manager/services/cart/mutations/checkout.ts +16 -1
- package/src/api-manager/services/cart/queries/get-cart-lines-inventory.ts +15 -0
- package/src/api-manager/services/create-extension-query.ts +26 -0
- package/src/api-manager/services/create-mutation.ts +5 -1
- package/src/api-manager/services/create-query.ts +10 -4
- package/src/api-manager/services/organization/queries/get-channel-configuration.ts +1 -1
- package/src/api-manager/services/product/queries/get-product-prices.ts +16 -0
- package/src/api-manager/services/product/queries/search-products.ts +1 -0
- package/src/api-manager/services/user/mutations/add-to-wishlist.ts +24 -0
- package/src/api-manager/services/user/mutations/copy-cart-to-wishlist.ts +23 -0
- package/src/api-manager/services/user/mutations/create-wishlist.ts +4 -4
- package/src/api-manager/services/user/mutations/delete-wishlist.ts +4 -3
- package/src/api-manager/services/user/mutations/remove-from-wishlist.ts +21 -0
- package/src/api-manager/services/user/mutations/update-wishlist.ts +23 -0
- package/src/api-manager/services/user/queries/get-wishlist-details.ts +11 -4
- package/src/api-manager/services/user/queries/get-wishlists.ts +4 -3
- package/src/api-manager/types/Datasource.ts +42 -14
- package/src/auth/auth-options.ts +2 -2
- package/src/auth/msal.ts +9 -9
- package/src/auth/next-auth-cookie-manager.ts +5 -3
- package/src/auth/providers/aadb2c-provider.ts +3 -4
- package/src/cms/endpoints.ts +2 -3
- package/src/components/Blocks/Components/ProductCarousel/index.tsx +6 -6
- package/src/components/_components/LazyImage.tsx +5 -2
- package/src/components/_components/header/components/user.tsx +1 -2
- package/src/components/_components/navbar/category-based-menu/components/categories.tsx +1 -1
- package/src/components/_components/navbar/mega-menu/mega-menu.tsx +1 -1
- package/src/components/_components/navbar/nav-list/nav-item-child.tsx +2 -2
- package/src/components/_components/product-cards/product-card-1/components/quantity-buttons.tsx +17 -8
- package/src/components/_components/product-cards/product-card-1/product-card-1-wrapper.tsx +304 -0
- package/src/components/_components/product-cards/product-card-1/product-card.tsx +16 -55
- package/src/components/_components/product-cards/product-card-8/product-card.tsx +80 -60
- package/src/components/_components/product-cards/product-card-8/styles/index.ts +10 -0
- package/src/components/_components/product-cards/product-card-wishlist/components/hover-actions.tsx +37 -0
- package/src/components/_components/product-cards/product-card-wishlist/index.ts +1 -0
- package/src/components/_components/product-cards/product-card-wishlist/product-card.tsx +118 -0
- package/src/components/_components/product-cards/product-card-wishlist/styles/index.ts +51 -0
- package/src/components/_components/product-dimensions/product-dimensions.tsx +114 -0
- package/src/components/_components/product-quantity-buttons/product-quantity-buttons.tsx +88 -0
- package/src/components/_components/products-view/product-view-dialog.tsx +48 -10
- package/src/components/_components/products-view/products-grid-view.tsx +31 -17
- package/src/components/_components/products-view/products-list-view.tsx +30 -16
- package/src/components/_components/search-box/__test__/search-input-category.test.tsx +110 -0
- package/src/components/_components/search-box/__test__/search-input.test.tsx +137 -0
- package/src/components/_components/search-box/__test__/search-results.json +165 -0
- package/src/components/_components/search-box/components/search-result.tsx +66 -12
- package/src/components/_components/search-box/search-input-category.tsx +135 -32
- package/src/components/_components/search-box/styles/index.ts +2 -0
- package/src/components/_components/section-header/section-creator.tsx +1 -0
- package/src/components/_components/section-header/section-header.tsx +1 -1
- package/src/components/_components/settings/setting.tsx +1 -1
- package/src/components/_components/wishlist/add-to-wishlist-dialog.tsx +161 -0
- package/src/components/_components/wishlist/components/create-new-list.tsx +167 -0
- package/src/components/_components/wishlist/components/create-wishlist-button.tsx +40 -0
- package/src/components/_components/wishlist/components/dashboard-header.tsx +123 -0
- package/src/components/_components/wishlist/components/navigation.tsx +87 -0
- package/src/components/_components/wishlist/components/no-records.tsx +20 -0
- package/src/components/_components/wishlist/components/wishlist-modal-item.tsx +66 -0
- package/src/components/_components/wishlist/remove-from-wishlist-dialog.tsx +174 -0
- package/src/components/_components/wishlist/styles.ts +61 -0
- package/src/components/_components/wishlist-modal/TODO.md +10 -0
- package/src/components/_components/wishlist-modal/add-to-wishlist-button.tsx +68 -0
- package/src/components/_components/wishlist-modal/add-to-wishlist-dialog.tsx +161 -0
- package/src/components/_components/wishlist-modal/remove-from-wishlist-dialog.tsx +174 -0
- package/src/components/_components/wishlist-modal/wishlist-modal-item.tsx +65 -0
- package/src/components/countries-input.tsx +7 -12
- package/src/hooks/use-cart.tsx +82 -0
- package/src/hooks/use-variants.tsx +85 -0
- package/src/lib/cart-cookie-handler-constants.ts +8 -0
- package/src/lib/cart-cookie-handler.ts +27 -5
- package/src/lib/create-graphql-client.ts +1 -2
- package/src/lib/product-list-types.ts +41 -0
- package/src/pages/account/addresses/address-form.tsx +289 -0
- package/src/pages/account/addresses/address-item.tsx +104 -0
- package/src/pages/account/dashboard-header.tsx +123 -0
- package/src/pages/account/navigation.tsx +84 -0
- package/src/pages/account/no-records.tsx +20 -0
- package/src/pages/account/orders/icons/delivery.tsx +14 -0
- package/src/pages/account/orders/icons/package-box.tsx +13 -0
- package/src/pages/account/orders/icons/truck-filled.tsx +14 -0
- package/src/pages/account/orders/order-progress.tsx +111 -0
- package/src/pages/account/orders/order-row.tsx +61 -0
- package/src/pages/account/orders/order-summary.tsx +83 -0
- package/src/pages/account/orders/ordered-products.tsx +114 -0
- package/src/pages/account/profile/profile-button.test.tsx +59 -0
- package/src/pages/account/profile/profile-button.tsx +50 -0
- package/src/pages/account/profile/user-info.tsx +59 -0
- package/src/pages/account/styles.ts +32 -0
- package/src/pages/account/table-row.tsx +19 -0
- package/src/pages/account/wishlist/create-new-list.tsx +167 -0
- package/src/pages/account/wishlist/create-wishlist-button.tsx +40 -0
- package/src/pages/account/wishlist/wishlist-item.tsx +82 -0
- package/src/pages/blog/pagination.tsx +38 -0
- package/src/pages/cart/cart-item.tsx +312 -0
- package/src/pages/cart/checkout-form.tsx +122 -0
- package/src/pages/cart/coupon-entry.tsx +90 -0
- package/src/pages/cart/estimate-shipping.tsx +183 -0
- package/src/pages/cart/wrapper.tsx +30 -0
- package/src/pages/checkout/checkout-alt-form/address-card.tsx +73 -0
- package/src/pages/checkout/checkout-alt-form/checkout-form.tsx +133 -0
- package/src/pages/checkout/checkout-alt-form/checkout-step.tsx +120 -0
- package/src/pages/checkout/checkout-alt-form/customer-information.tsx +94 -0
- package/src/pages/checkout/checkout-alt-form/delivery-address.tsx +170 -0
- package/src/pages/checkout/checkout-alt-form/delivery-date.tsx +114 -0
- package/src/pages/checkout/checkout-alt-form/delivery-options.tsx +186 -0
- package/src/pages/checkout/checkout-alt-form/edit-address-form.tsx +130 -0
- package/src/pages/checkout/checkout-alt-form/heading.tsx +50 -0
- package/src/pages/checkout/checkout-alt-form/index.ts +1 -0
- package/src/pages/checkout/checkout-alt-form/new-address-form.tsx +294 -0
- package/src/pages/checkout/checkout-alt-form/node.tsx +9 -0
- package/src/pages/checkout/checkout-alt-form/payment-details.tsx +344 -0
- package/src/pages/checkout/checkout-alt-form/safe-card-preview-data.tsx +36 -0
- package/src/pages/checkout/checkout-alt-form/types.ts +20 -0
- package/src/pages/checkout/checkout-alt-summary/cart-item.tsx +39 -0
- package/src/pages/checkout/checkout-alt-summary/checkout-alt-summary.tsx +40 -0
- package/src/pages/checkout/checkout-alt-summary/index.ts +1 -0
- package/src/pages/checkout/checkout-alt-summary/list-item.tsx +31 -0
- package/src/pages/confirmation/address.tsx +22 -0
- package/src/pages/confirmation/confirmation-summary.tsx +52 -0
- package/src/pages/confirmation/ordered-products.tsx +108 -0
- package/src/pages/product-details/available-shops.tsx +48 -0
- package/src/pages/product-details/bopis/find-in-store-button.tsx +63 -0
- package/src/pages/product-details/bopis/find-in-store-modal.tsx +257 -0
- package/src/pages/product-details/bopis/pickup-option-select.tsx +127 -0
- package/src/pages/product-details/bopis/search-header.tsx +69 -0
- package/src/pages/product-details/checkbox-label.tsx +20 -0
- package/src/pages/product-details/currency.ts +64 -0
- package/src/pages/product-details/frequently-bought.tsx +90 -0
- package/src/pages/product-details/frequently-product-card.tsx +60 -0
- package/src/pages/product-details/product-comment.tsx +44 -0
- package/src/pages/product-details/product-description.tsx +22 -0
- package/src/pages/product-details/product-filter-card.tsx +257 -0
- package/src/pages/product-details/product-intro/product-intro-images.tsx +87 -0
- package/src/pages/product-details/product-intro/product-intro.tsx +250 -0
- package/src/pages/product-details/product-review.tsx +131 -0
- package/src/pages/product-details/product-tabs.tsx +51 -0
- package/src/pages/product-details/related-products.tsx +42 -0
- package/src/pages/product-details/types.ts +11 -0
- package/src/pages/product-list/breadcrumbs.tsx +39 -0
- package/src/pages/product-list/checkbox-label.tsx +20 -0
- package/src/pages/product-list/facet-group.tsx +125 -0
- package/src/pages/product-list/facet.tsx +36 -0
- package/src/pages/product-list/list-filter.tsx +40 -0
- package/src/pages/product-list/pagination.tsx +80 -0
- package/src/pages/product-list/product-list-context.tsx +302 -0
- package/src/pages/product-list/product-list-state.ts +187 -0
- package/src/pages/product-list/product-rating.tsx +16 -0
- package/src/pages/product-list/quick-view-dialog-content.tsx +205 -0
- package/src/pages/product-list/quick-view-dialog.tsx +54 -0
- package/src/pages/product-list/range-filter.tsx +125 -0
- package/src/pages/product-list/scrollbar.tsx +38 -0
- package/src/pages/product-list/search-bar.tsx +162 -0
- package/src/pages/product-list/selected-facets.tsx +80 -0
- package/src/pages/product-list/side-nav.tsx +49 -0
- package/src/pages/product-list/swatch.tsx +80 -0
- package/src/pages/product-list/types.ts +18 -0
- package/src/pages/product-list/use-product-list.ts +12 -0
- package/src/pages/product-list/useCategoryFilter.tsx +26 -0
- package/src/pages/product-list/utils/facet-helpers.ts +5 -0
- package/src/pages/product-list/utils/generate-breadcrumbs.ts +30 -0
- package/src/pages/product-list/utils/getCategoryFilterFromSlug.ts +153 -0
- package/src/pages/product-list/utils/product-list-helper.ts +111 -0
- package/src/pages/product-list/utils/product-list-types.ts +41 -0
- package/src/pages/product-list/utils/search-for-category.ts +76 -0
- package/src/pages/product-list/utils/sort-options.ts +44 -0
- package/src/pages/product-list/utils/use-previous-refiners.ts +14 -0
- package/src/pages/quickorder/order-upload.tsx +150 -0
- package/src/pages/quickorder/quick-order-form.tsx +343 -0
- package/src/pages/quickorder/quick-order-row.tsx +144 -0
- package/tsconfig.json +1 -0
- package/src/api-manager/datasources/e4/graphqlRequestSdk.ts +0 -43515
- package/src/config.ts +0 -47
- /package/src/{components/_components/hooks/useOverflowDetect.ts → hooks/use-overflow-detect.ts} +0 -0
- /package/src/{components/_components/hooks/useSettings.ts → hooks/use-settings.ts} +0 -0
|
@@ -31,7 +31,11 @@ export const useCreateMutation = <TInput, TOutput>(
|
|
|
31
31
|
body: JSON.stringify({ input, apiManagerPath }),
|
|
32
32
|
});
|
|
33
33
|
if (!response.ok) {
|
|
34
|
-
|
|
34
|
+
const error = await response.json();
|
|
35
|
+
let errorMsg = `${error.error}`;
|
|
36
|
+
if (error.message) errorMsg += ` - ${error.message}`;
|
|
37
|
+
|
|
38
|
+
throw new Error(errorMsg);
|
|
35
39
|
}
|
|
36
40
|
return response.json();
|
|
37
41
|
},
|
|
@@ -13,6 +13,7 @@ import { Mutex } from "async-mutex";
|
|
|
13
13
|
import { manuallyRetrieveSessionCookie } from "@/auth/next-auth-cookie-manager";
|
|
14
14
|
import { getSession } from "next-auth/react";
|
|
15
15
|
import jwt from "jsonwebtoken";
|
|
16
|
+
import signOut from "@/auth/signout";
|
|
16
17
|
|
|
17
18
|
const QUERY_ROUTE = "/api";
|
|
18
19
|
const mutex = new Mutex();
|
|
@@ -79,7 +80,6 @@ export const createQuery = <TInput, TOutput>(
|
|
|
79
80
|
queryFn,
|
|
80
81
|
enabled,
|
|
81
82
|
};
|
|
82
|
-
|
|
83
83
|
return data;
|
|
84
84
|
};
|
|
85
85
|
|
|
@@ -105,6 +105,11 @@ export const createQuery = <TInput, TOutput>(
|
|
|
105
105
|
body: JSON.stringify({ input, apiManagerPath }),
|
|
106
106
|
headers,
|
|
107
107
|
});
|
|
108
|
+
|
|
109
|
+
if (result.status === 401) {
|
|
110
|
+
// If unauthenticated , sign out the user
|
|
111
|
+
signOut();
|
|
112
|
+
}
|
|
108
113
|
return await result.json();
|
|
109
114
|
};
|
|
110
115
|
|
|
@@ -192,6 +197,9 @@ export const createQuery = <TInput, TOutput>(
|
|
|
192
197
|
|
|
193
198
|
const currentTime = Math.floor(Date.now() / 1000);
|
|
194
199
|
|
|
200
|
+
// Use this for testing - expires after 60 seconds (1 min) from issued-at time
|
|
201
|
+
// const isExpired = !!decoded && typeof decoded.iat === "number" && currentTime > decoded.iat + 60;
|
|
202
|
+
|
|
195
203
|
const isExpired =
|
|
196
204
|
!!decoded && typeof decoded.exp === "number" && decoded.exp < currentTime;
|
|
197
205
|
|
|
@@ -221,9 +229,7 @@ export const createQuery = <TInput, TOutput>(
|
|
|
221
229
|
headers.append("should-refresh-token", "true");
|
|
222
230
|
}
|
|
223
231
|
// Call do fetch with the headers
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
return response.json();
|
|
232
|
+
return await doFetch(input, apiManagerPath, headers);
|
|
227
233
|
} catch (error) {
|
|
228
234
|
// Handle API Error
|
|
229
235
|
console.error("Error fetching data:", error);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ProductPriceInput,
|
|
3
|
+
ProductPrice,
|
|
4
|
+
} from "@/api-manager/schemas/product.schema";
|
|
5
|
+
import { createApiPath, createQuery } from "../../create-query";
|
|
6
|
+
|
|
7
|
+
const apiPath = createApiPath("product", "getProductPrices");
|
|
8
|
+
|
|
9
|
+
const getProductPrices = createQuery<ProductPriceInput, ProductPrice[]>(
|
|
10
|
+
apiPath,
|
|
11
|
+
{
|
|
12
|
+
queryKey: "product-prices",
|
|
13
|
+
},
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
export default getProductPrices;
|
|
@@ -5,6 +5,7 @@ import { createApiPath, createQuery } from "../../create-query";
|
|
|
5
5
|
const apiPath = createApiPath("product", "searchProducts");
|
|
6
6
|
const searchProducts = createQuery<searchProductsInput, ProductSearchResult[]>(
|
|
7
7
|
apiPath,
|
|
8
|
+
{ disableProperties: ["searchText"] },
|
|
8
9
|
);
|
|
9
10
|
|
|
10
11
|
export default searchProducts;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
2
|
+
import {
|
|
3
|
+
Wishlist,
|
|
4
|
+
WishlistLinesInput,
|
|
5
|
+
} from "@/api-manager/schemas/user.schema";
|
|
6
|
+
import { createApiPath } from "../../create-query";
|
|
7
|
+
import { useCreateMutation } from "../../create-mutation";
|
|
8
|
+
import { getWishlistsQueryKey } from "../queries/get-wishlists";
|
|
9
|
+
|
|
10
|
+
const apiPath = createApiPath("user", "addProductsToWishlist");
|
|
11
|
+
|
|
12
|
+
const useAddToWishlist = () => {
|
|
13
|
+
const queryClient = useQueryClient();
|
|
14
|
+
|
|
15
|
+
return useCreateMutation<WishlistLinesInput, Wishlist>(apiPath, {
|
|
16
|
+
onSuccess: (_data, variables) => {
|
|
17
|
+
queryClient.invalidateQueries({
|
|
18
|
+
queryKey: [getWishlistsQueryKey, variables.Id],
|
|
19
|
+
});
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default useAddToWishlist;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
2
|
+
import {
|
|
3
|
+
CopyCartToWishlistInput,
|
|
4
|
+
Wishlist,
|
|
5
|
+
} from "@/api-manager/schemas/user.schema";
|
|
6
|
+
import { createApiPath } from "../../create-query";
|
|
7
|
+
import { useCreateMutation } from "../../create-mutation";
|
|
8
|
+
|
|
9
|
+
const apiPath = createApiPath("user", "copyCartToWishlist");
|
|
10
|
+
|
|
11
|
+
const useCopyCartToWishlist = () => {
|
|
12
|
+
const queryClient = useQueryClient();
|
|
13
|
+
|
|
14
|
+
return useCreateMutation<CopyCartToWishlistInput, Wishlist>(apiPath, {
|
|
15
|
+
onSuccess: (_data, _variables) => {
|
|
16
|
+
queryClient.invalidateQueries({
|
|
17
|
+
queryKey: ["wishlistDetails", _variables.Id],
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default useCopyCartToWishlist;
|
|
@@ -2,16 +2,16 @@ import { useQueryClient } from "@tanstack/react-query";
|
|
|
2
2
|
import { createApiPath } from "../../create-query";
|
|
3
3
|
import { useCreateMutation } from "../../create-mutation";
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from "
|
|
5
|
+
Wishlist,
|
|
6
|
+
WishlistCreateInput,
|
|
7
|
+
} from "@/api-manager/schemas/user.schema";
|
|
8
8
|
|
|
9
9
|
const apiPath = createApiPath("user", "createWishlist");
|
|
10
10
|
|
|
11
11
|
const useCreateWishlist = () => {
|
|
12
12
|
const queryClient = useQueryClient();
|
|
13
13
|
|
|
14
|
-
return useCreateMutation<
|
|
14
|
+
return useCreateMutation<WishlistCreateInput, Wishlist>(apiPath, {
|
|
15
15
|
onSuccess: () => {
|
|
16
16
|
queryClient.invalidateQueries({ queryKey: ["wishlists"] });
|
|
17
17
|
},
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { useQueryClient } from "@tanstack/react-query";
|
|
2
2
|
import { createApiPath } from "../../create-query";
|
|
3
3
|
import { useCreateMutation } from "../../create-mutation";
|
|
4
|
+
import { WishlistDetailInput } from "@/api-manager/schemas/user.schema";
|
|
5
|
+
import { getWishlistsQueryKey } from "../queries/get-wishlists";
|
|
4
6
|
|
|
5
7
|
const apiPath = createApiPath("user", "deleteWishlist");
|
|
6
8
|
|
|
7
9
|
const useDeleteWishlist = () => {
|
|
8
10
|
const queryClient = useQueryClient();
|
|
9
11
|
|
|
10
|
-
return useCreateMutation<
|
|
12
|
+
return useCreateMutation<WishlistDetailInput, void>(apiPath, {
|
|
11
13
|
onSuccess: () => {
|
|
12
|
-
queryClient.invalidateQueries({ queryKey: [
|
|
14
|
+
queryClient.invalidateQueries({ queryKey: [getWishlistsQueryKey] });
|
|
13
15
|
},
|
|
14
16
|
});
|
|
15
17
|
};
|
|
16
|
-
|
|
17
18
|
export default useDeleteWishlist;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
2
|
+
import { WishlistLinesInput } from "@/api-manager/schemas/user.schema";
|
|
3
|
+
import { createApiPath } from "../../create-query";
|
|
4
|
+
import { useCreateMutation } from "../../create-mutation";
|
|
5
|
+
import { getWishlistDetailsQueryKey } from "../queries/get-wishlist-details";
|
|
6
|
+
|
|
7
|
+
const apiPath = createApiPath("user", "removeProductsFromWishlist");
|
|
8
|
+
|
|
9
|
+
const useRemoveFromWishlist = () => {
|
|
10
|
+
const queryClient = useQueryClient();
|
|
11
|
+
|
|
12
|
+
return useCreateMutation<WishlistLinesInput, void>(apiPath, {
|
|
13
|
+
onSuccess: (_data, _variables) => {
|
|
14
|
+
queryClient.invalidateQueries({
|
|
15
|
+
queryKey: [getWishlistDetailsQueryKey, { Id: _variables.Id }],
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default useRemoveFromWishlist;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
2
|
+
import {
|
|
3
|
+
Wishlist,
|
|
4
|
+
WishlistLinesInput,
|
|
5
|
+
} from "@/api-manager/schemas/user.schema";
|
|
6
|
+
import { useCreateMutation } from "../../create-mutation";
|
|
7
|
+
import { createApiPath } from "../../create-query";
|
|
8
|
+
|
|
9
|
+
const apiPath = createApiPath("user", "updateWishlist");
|
|
10
|
+
|
|
11
|
+
const useUpdateWishlist = () => {
|
|
12
|
+
const queryClient = useQueryClient();
|
|
13
|
+
|
|
14
|
+
return useCreateMutation<WishlistLinesInput, Wishlist>(apiPath, {
|
|
15
|
+
onSuccess: (_data, _variables) => {
|
|
16
|
+
queryClient.invalidateQueries({
|
|
17
|
+
queryKey: ["wishlistDetails", _variables.Id],
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default useUpdateWishlist;
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ExtendedWishlist,
|
|
3
|
+
WishlistDetailInput,
|
|
4
|
+
} from "@/api-manager/schemas/user.schema";
|
|
1
5
|
import { createApiPath, createQuery } from "../../create-query";
|
|
2
|
-
import { WishList } from "../../../datasources/e4/graphqlRequestSdk";
|
|
3
6
|
|
|
7
|
+
export const getWishlistDetailsQueryKey = "wish-list-details";
|
|
4
8
|
const apiPath = createApiPath("user", "getWishlistDetails");
|
|
5
9
|
|
|
6
|
-
const getWishListDetails = createQuery<
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
const getWishListDetails = createQuery<WishlistDetailInput, ExtendedWishlist>(
|
|
11
|
+
apiPath,
|
|
12
|
+
{
|
|
13
|
+
queryKey: getWishlistDetailsQueryKey,
|
|
14
|
+
},
|
|
15
|
+
);
|
|
9
16
|
|
|
10
17
|
export default getWishListDetails;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Wishlist } from "@/api-manager/schemas/user.schema";
|
|
2
2
|
import { createApiPath, createQuery } from "../../create-query";
|
|
3
3
|
|
|
4
|
+
export const getWishlistsQueryKey = "wishlists";
|
|
4
5
|
const apiPath = createApiPath("user", "getWishlists");
|
|
5
6
|
|
|
6
|
-
const getWishlists = createQuery<null,
|
|
7
|
-
queryKey:
|
|
7
|
+
const getWishlists = createQuery<null, Wishlist[]>(apiPath, {
|
|
8
|
+
queryKey: getWishlistsQueryKey,
|
|
8
9
|
});
|
|
9
10
|
|
|
10
11
|
export default getWishlists;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as cartSchemas from "@/api-manager/schemas/cart.schema";
|
|
2
2
|
import * as productSchemas from "@/api-manager/schemas/product.schema";
|
|
3
|
+
import * as userSchemas from "@/api-manager/schemas/user.schema";
|
|
3
4
|
import { User, UserCounts } from "@/api-manager/schemas/user.schema";
|
|
4
5
|
import {
|
|
5
6
|
Session,
|
|
@@ -31,6 +32,7 @@ import {
|
|
|
31
32
|
SimpleProduct,
|
|
32
33
|
StateProvinceInfo,
|
|
33
34
|
ProductWarehouseInventoryAvailability,
|
|
35
|
+
ProductWarehouseInventoryInformation,
|
|
34
36
|
} from "@msdyn365-commerce/retail-proxy";
|
|
35
37
|
import {
|
|
36
38
|
CategoriesQuery,
|
|
@@ -52,16 +54,16 @@ export interface DatasourceApis {
|
|
|
52
54
|
organization: OrganizationApi;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
export abstract class Datasource
|
|
57
|
+
export abstract class Datasource {
|
|
56
58
|
public name: string;
|
|
57
|
-
abstract user: UserApi
|
|
58
|
-
abstract cart: CartApi
|
|
59
|
-
abstract product: ProductApi
|
|
60
|
-
abstract categories: CategoryApi
|
|
61
|
-
abstract order: OrderApi
|
|
62
|
-
abstract address: AddressApi
|
|
63
|
-
abstract organization: OrganizationApi
|
|
64
|
-
abstract session: SessionApi
|
|
59
|
+
abstract user: Partial<UserApi>;
|
|
60
|
+
abstract cart: Partial<CartApi>;
|
|
61
|
+
abstract product: Partial<ProductApi>;
|
|
62
|
+
abstract categories: Partial<CategoryApi>;
|
|
63
|
+
abstract order: Partial<OrderApi>;
|
|
64
|
+
abstract address: Partial<AddressApi>;
|
|
65
|
+
abstract organization: Partial<OrganizationApi>;
|
|
66
|
+
abstract session: Partial<SessionApi>;
|
|
65
67
|
|
|
66
68
|
constructor(name: string) {
|
|
67
69
|
this.name = name;
|
|
@@ -89,14 +91,34 @@ export interface OrganizationApi {
|
|
|
89
91
|
* User Data Actions
|
|
90
92
|
*/
|
|
91
93
|
export interface UserApi {
|
|
94
|
+
updateUser(user: userSchemas.User): Promise<userSchemas.User>;
|
|
95
|
+
getUser(): Promise<userSchemas.User | null>;
|
|
96
|
+
getUserCounts(userId: string): Promise<UserCounts>;
|
|
97
|
+
// wishlists
|
|
98
|
+
getWishlists(): Promise<userSchemas.Wishlist[]>;
|
|
99
|
+
getWishlistDetails(
|
|
100
|
+
input: userSchemas.WishlistDetailInput,
|
|
101
|
+
): Promise<userSchemas.ExtendedWishlist>;
|
|
102
|
+
createWishlist(
|
|
103
|
+
input: userSchemas.WishlistCreateInput,
|
|
104
|
+
): Promise<userSchemas.Wishlist>;
|
|
105
|
+
deleteWishlist(input: userSchemas.WishlistDetailInput): Promise<void>;
|
|
106
|
+
updateWishlist(
|
|
107
|
+
// input: userSchemas.UpdateWishlistInput, // used to change wishlist name
|
|
108
|
+
input: userSchemas.WishlistLinesInput,
|
|
109
|
+
): Promise<userSchemas.Wishlist>;
|
|
110
|
+
addProductsToWishlist(
|
|
111
|
+
input: userSchemas.WishlistLinesInput,
|
|
112
|
+
): Promise<userSchemas.Wishlist>;
|
|
113
|
+
removeProductsFromWishlist(
|
|
114
|
+
input: userSchemas.WishlistLinesInput,
|
|
115
|
+
): Promise<void>;
|
|
116
|
+
copyCartToWishlist(
|
|
117
|
+
input: userSchemas.CopyCartToWishlistInput,
|
|
118
|
+
): Promise<userSchemas.Wishlist>;
|
|
92
119
|
updateUser(user: User): Promise<User>;
|
|
93
120
|
getUser(): Promise<User | null>;
|
|
94
121
|
getUserCounts(userId: string): Promise<UserCounts>;
|
|
95
|
-
// wishlists
|
|
96
|
-
getWishlists(): Promise<WishList[]>;
|
|
97
|
-
getWishlistDetails(id: string): Promise<WishList>;
|
|
98
|
-
createWishlist(wishlist: CreateWishListInput): Promise<WishList>;
|
|
99
|
-
deleteWishlist(id: string): Promise<string>;
|
|
100
122
|
}
|
|
101
123
|
|
|
102
124
|
/**
|
|
@@ -142,6 +164,9 @@ export interface CartApi {
|
|
|
142
164
|
input: cartSchemas.RetrieveCardPaymentAcceptResultInput,
|
|
143
165
|
): Promise<CardPaymentAcceptResult>;
|
|
144
166
|
checkout(input: cartSchemas.CheckoutInput): Promise<SalesOrder>;
|
|
167
|
+
getCartLinesInventory(
|
|
168
|
+
input: cartSchemas.InventorySearchCartLinesCriteriaInput,
|
|
169
|
+
): Promise<ProductWarehouseInventoryInformation>;
|
|
145
170
|
}
|
|
146
171
|
|
|
147
172
|
/**
|
|
@@ -167,6 +192,9 @@ export interface ProductApi {
|
|
|
167
192
|
getInventory(
|
|
168
193
|
input: productSchemas.InventorySearchCriteriaInput,
|
|
169
194
|
): Promise<ProductWarehouseInventoryAvailability>;
|
|
195
|
+
getProductPrices(
|
|
196
|
+
input: productSchemas.ProductPriceInput,
|
|
197
|
+
): Promise<productSchemas.ProductPrice[]>;
|
|
170
198
|
}
|
|
171
199
|
|
|
172
200
|
/**
|
package/src/auth/auth-options.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "next";
|
|
9
9
|
import { getProviders } from "./providers";
|
|
10
10
|
import { deleteCartCookie } from "@/lib/cart-cookie-handler";
|
|
11
|
-
import {
|
|
11
|
+
import { getSecret } from "@evenicanpm/common-core/keyvault";
|
|
12
12
|
|
|
13
13
|
// Split providers into separate array so we can iterate them and match the provider ID
|
|
14
14
|
export type ExtendedJwtToken = JWT & {
|
|
@@ -20,7 +20,7 @@ export type ExtendedSession = Session & { token?: JWT };
|
|
|
20
20
|
|
|
21
21
|
const createAuthOptions = (): NextAuthOptions => {
|
|
22
22
|
const providers = getProviders();
|
|
23
|
-
const secret =
|
|
23
|
+
const secret = getSecret("NEXTAUTH_SECRET");
|
|
24
24
|
return {
|
|
25
25
|
providers,
|
|
26
26
|
secret,
|
package/src/auth/msal.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { PublicClientApplication, Configuration } from "@azure/msal-browser";
|
|
2
|
-
import { getConfig } from "@config";
|
|
3
2
|
|
|
4
3
|
const createMsalConfig = (): Configuration => {
|
|
5
4
|
return {
|
|
6
5
|
auth: {
|
|
7
|
-
clientId:
|
|
8
|
-
authority:
|
|
9
|
-
redirectUri:
|
|
10
|
-
postLogoutRedirectUri:
|
|
6
|
+
clientId: process.env.NEXT_PUBLIC_AZURE_AD_B2C_CLIENTID || "",
|
|
7
|
+
authority: process.env.NEXT_PUBLIC_AZURE_AD_B2C_LOGIN_AUTHORITY || "",
|
|
8
|
+
redirectUri: process.env.NEXT_PUBLIC_AZURE_AD_B2C_REDIRECT || "/",
|
|
9
|
+
postLogoutRedirectUri:
|
|
10
|
+
process.env.NEXT_PUBLIC_AZURE_AD_B2C_POST_LOGOUT_REDIRECT || "/",
|
|
11
11
|
knownAuthorities: [
|
|
12
|
-
|
|
12
|
+
process.env.NEXT_PUBLIC_AZURE_AD_B2C_KNOWN_AUTHORITY || "",
|
|
13
13
|
],
|
|
14
14
|
navigateToLoginRequestUrl: true,
|
|
15
15
|
},
|
|
@@ -44,11 +44,11 @@ const getMsalInstance = () => {
|
|
|
44
44
|
};
|
|
45
45
|
|
|
46
46
|
const getRequestConfig = (requestType?: string) => {
|
|
47
|
-
const editAuthority =
|
|
48
|
-
const resetAuthority =
|
|
47
|
+
const editAuthority = process.env.NEXT_PUBLIC_AZURE_AD_B2C_EDIT_AUTHORITY;
|
|
48
|
+
const resetAuthority = process.env.NEXT_PUBLIC_AZURE_AD_B2C_RESET_AUTHORITY;
|
|
49
49
|
|
|
50
50
|
const baseRequest = {
|
|
51
|
-
scopes: [
|
|
51
|
+
scopes: [process.env.NEXT_PUBLIC_AZURE_AD_B2C_API_PERMISSION],
|
|
52
52
|
authority: createMsalConfig().auth.authority,
|
|
53
53
|
};
|
|
54
54
|
|
|
@@ -6,6 +6,8 @@ import { ExtendedJwtToken } from "@/auth/auth-options";
|
|
|
6
6
|
const NEXT_AUTH_COOKIE_NAME = "next-auth.session-token";
|
|
7
7
|
const SECURE_COOKIE_PREFIX = "__Secure-";
|
|
8
8
|
|
|
9
|
+
import { getSecret } from "@evenicanpm/common-core/keyvault";
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* Retrieves and decodes the NextAuth session cookie from the request.
|
|
11
13
|
*
|
|
@@ -28,7 +30,7 @@ const manuallyRetrieveSessionCookie = async () => {
|
|
|
28
30
|
if (cookie) {
|
|
29
31
|
return decode({
|
|
30
32
|
token: cookie.value,
|
|
31
|
-
secret:
|
|
33
|
+
secret: getSecret("NEXTAUTH_SECRET") || "",
|
|
32
34
|
});
|
|
33
35
|
}
|
|
34
36
|
//If the cookie is not found, we need to see if there is a chunked cookie
|
|
@@ -49,7 +51,7 @@ const manuallyRetrieveSessionCookie = async () => {
|
|
|
49
51
|
if (cookieValues.length) {
|
|
50
52
|
return decode({
|
|
51
53
|
token: cookieValues.join(""),
|
|
52
|
-
secret:
|
|
54
|
+
secret: getSecret("NEXTAUTH_SECRET") || "",
|
|
53
55
|
});
|
|
54
56
|
}
|
|
55
57
|
|
|
@@ -73,7 +75,7 @@ const manuallySetSessionCookie = async (token: JWT | ExtendedJwtToken) => {
|
|
|
73
75
|
// Set the cookie with the name __Secure-next-auth.session-token
|
|
74
76
|
const value = await encode({
|
|
75
77
|
token,
|
|
76
|
-
secret:
|
|
78
|
+
secret: getSecret("NEXTAUTH_SECRET") || "",
|
|
77
79
|
});
|
|
78
80
|
cookieStore.set({
|
|
79
81
|
name: `${SECURE_COOKIE_PREFIX}${NEXT_AUTH_COOKIE_NAME}`,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { getConfig } from "@config";
|
|
2
1
|
import AzureADB2CProvider from "next-auth/providers/azure-ad-b2c";
|
|
3
2
|
|
|
4
3
|
// By default, NextAuth tries to use either PKCE or Client Secret-based authentication, depending on how the provider is configured.
|
|
@@ -6,9 +5,9 @@ import AzureADB2CProvider from "next-auth/providers/azure-ad-b2c";
|
|
|
6
5
|
// If clientSecret is missing, it assumes PKCE.
|
|
7
6
|
// But Azure AD B2C sometimes requires PKCE explicitly, so NextAuth needs to be told to always use PKCE.
|
|
8
7
|
const azureADB2CProvider = () => {
|
|
9
|
-
const CLIENT_ID =
|
|
10
|
-
const SCOPE = `${
|
|
11
|
-
const LOGIN_AUTHORITY =
|
|
8
|
+
const CLIENT_ID = process.env.NEXT_PUBLIC_AZURE_AD_B2C_CLIENTID || "";
|
|
9
|
+
const SCOPE = `${process.env.NEXT_PUBLIC_AZURE_AD_B2C_API_PERMISSION} offline_access openid`;
|
|
10
|
+
const LOGIN_AUTHORITY = process.env.NEXT_PUBLIC_AZURE_AD_B2C_LOGIN_AUTHORITY;
|
|
12
11
|
|
|
13
12
|
return AzureADB2CProvider({
|
|
14
13
|
clientId: CLIENT_ID,
|
package/src/cms/endpoints.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Formats } from "./interfaces/productData";
|
|
2
|
-
import { getConfig } from "@config";
|
|
3
2
|
|
|
4
3
|
const apiKeys = {
|
|
5
4
|
pages: "/cms/pages",
|
|
@@ -17,12 +16,12 @@ type ApiKeysType = typeof apiKeys;
|
|
|
17
16
|
type ApiKey = keyof ApiKeysType;
|
|
18
17
|
|
|
19
18
|
const getCmsApiUrl = (apiKey: ApiKey) => {
|
|
20
|
-
const cmsApiEndpoint =
|
|
19
|
+
const cmsApiEndpoint = process.env.NEXT_PUBLIC_E4_API_ENDPOINT;
|
|
21
20
|
return `${cmsApiEndpoint}${apiKeys[apiKey]}`;
|
|
22
21
|
};
|
|
23
22
|
|
|
24
23
|
const buildCmsMediaUrl = (mediaUrl: string) => {
|
|
25
|
-
const cmsEndpoint =
|
|
24
|
+
const cmsEndpoint = process.env.NEXT_PUBLIC_CMS_ENDPOINT;
|
|
26
25
|
|
|
27
26
|
if (mediaUrl === undefined || mediaUrl === null) {
|
|
28
27
|
return "";
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
// Template: Market1
|
|
2
2
|
import React from "react";
|
|
3
3
|
|
|
4
|
-
//
|
|
4
|
+
// ICONS
|
|
5
5
|
import { Light } from "../../Icons/index";
|
|
6
6
|
import { Box } from "@mui/system";
|
|
7
7
|
|
|
8
|
-
//
|
|
8
|
+
// GLOBAL COMPONENTS
|
|
9
9
|
import { Carousel } from "@/components/_components/carousel/index";
|
|
10
10
|
import { SectionCreator } from "@/components/_components/section-header/index";
|
|
11
|
-
import
|
|
11
|
+
import ProductCard1Wrapper from "@/components/_components/product-cards/product-card-1/product-card-1-wrapper";
|
|
12
12
|
|
|
13
|
-
//
|
|
13
|
+
// CMS
|
|
14
14
|
import { getImageUrl } from "@/cms/endpoints";
|
|
15
15
|
|
|
16
16
|
// API
|
|
17
17
|
import getProductByIds from "@/services/product/queries/get-product-by-ids";
|
|
18
18
|
import { getQueryClient } from "@/services/get-query-client";
|
|
19
19
|
import { SimpleProduct } from "@msdyn365-commerce/retail-proxy";
|
|
20
|
-
|
|
21
20
|
import { Product, ProductCarouselBlock } from "../../interfaces";
|
|
22
21
|
|
|
23
22
|
type CombinedProduct = Product & SimpleProduct;
|
|
@@ -63,7 +62,7 @@ export default async function ProductCarousel(data: ProductCarouselBlock) {
|
|
|
63
62
|
<Carousel responsive={responsive} height={445} autoplay={true}>
|
|
64
63
|
{combinedData?.map((item: CombinedProduct) => (
|
|
65
64
|
<Box pb={0.6} key={item.id}>
|
|
66
|
-
<
|
|
65
|
+
<ProductCard1Wrapper
|
|
67
66
|
id={item?.RecordId}
|
|
68
67
|
slug={item?.ItemId ?? ""}
|
|
69
68
|
title={item?.Name ?? ""}
|
|
@@ -71,6 +70,7 @@ export default async function ProductCarousel(data: ProductCarouselBlock) {
|
|
|
71
70
|
rating={0}
|
|
72
71
|
imgUrl={getImageUrl(item?.image?.[0]?.formats ?? {})}
|
|
73
72
|
discount={0}
|
|
73
|
+
mode="PLP"
|
|
74
74
|
//uom={item?.uom?.nodes[0].id}
|
|
75
75
|
/>
|
|
76
76
|
</Box>
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import NextImage from "next/image";
|
|
3
|
+
import NextImage, { ImageProps } from "next/image";
|
|
4
4
|
import styled from "@mui/material/styles/styled";
|
|
5
|
+
import { ComponentType } from "react";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
const LazyImage: ComponentType<ImageProps> = styled(NextImage)({
|
|
7
8
|
width: "100%",
|
|
8
9
|
height: "auto", //If we use CSS to change the size of image, we should include the styles 'width: "auto"' or 'height: "auto"' to maintain the aspect ratio.
|
|
9
10
|
});
|
|
11
|
+
|
|
12
|
+
export default LazyImage;
|
|
@@ -42,7 +42,6 @@ const MENU_ITEMS = [
|
|
|
42
42
|
interface Props {
|
|
43
43
|
mobile?: boolean;
|
|
44
44
|
}
|
|
45
|
-
|
|
46
45
|
const User = ({ mobile = false }: Props) => {
|
|
47
46
|
const { data: session, status } = useSession();
|
|
48
47
|
|
|
@@ -115,7 +114,7 @@ const User = ({ mobile = false }: Props) => {
|
|
|
115
114
|
|
|
116
115
|
const setAnchorElNull = () => setAnchorEl(null);
|
|
117
116
|
|
|
118
|
-
if (status === "loading") return
|
|
117
|
+
if (status === "loading") return <></>;
|
|
119
118
|
|
|
120
119
|
if (mobile) {
|
|
121
120
|
return (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ChevronRight from "@mui/icons-material/ChevronRight";
|
|
2
2
|
// GLOBAL CUSTOM HOOK
|
|
3
|
-
import useSettings from "@/
|
|
3
|
+
import useSettings from "@/hooks/use-settings";
|
|
4
4
|
// STYLED COMPONENTS
|
|
5
5
|
import { CategoryList, CategoryListItem } from "../styles";
|
|
6
6
|
|
|
@@ -5,7 +5,7 @@ import KeyboardArrowDown from "@mui/icons-material/KeyboardArrowDown";
|
|
|
5
5
|
// GLOBAL CUSTOM COMPONENTS
|
|
6
6
|
import FlexRowCenter from "@/components/_components/flex-box/flex-row-center";
|
|
7
7
|
// GLOBAL CUSTOM HOOKS
|
|
8
|
-
import useOverflowDetect from "@/
|
|
8
|
+
import useOverflowDetect from "@/hooks/use-overflow-detect";
|
|
9
9
|
// LOCAL CUSTOM COMPONENT
|
|
10
10
|
import CategoryList from "./category-list";
|
|
11
11
|
// STYLED COMPONENTS
|
|
@@ -7,8 +7,8 @@ import MenuItem from "@mui/material/MenuItem";
|
|
|
7
7
|
import ArrowLeft from "@mui/icons-material/ArrowLeft";
|
|
8
8
|
import ArrowRight from "@mui/icons-material/ArrowRight";
|
|
9
9
|
// GLOBAL CUSTOM HOOKS
|
|
10
|
-
import useOverflowDetect from "@/
|
|
11
|
-
import useSettings from "@/
|
|
10
|
+
import useOverflowDetect from "@/hooks/use-overflow-detect";
|
|
11
|
+
import useSettings from "@/hooks/use-settings";
|
|
12
12
|
// GLOBAL CUSTOM COMPONENTS
|
|
13
13
|
import { Span } from "@/components/_components/Typography";
|
|
14
14
|
import BazaarCard from "@/components/_components/BazaarCard";
|