@sonic-equipment/ui 225.0.0 → 227.0.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/dist/exports.d.ts +5 -0
- package/dist/footer/connected-footer.js +3 -1
- package/dist/forms/partials/password-validation/password-validation.js +1 -1
- package/dist/index.js +6 -2
- package/dist/intl/translation-id.d.ts +1 -1
- package/dist/modals/dialog/dialog.d.ts +1 -0
- package/dist/modals/dialog/dialog.js +3 -2
- package/dist/notifications/announcements/connected-announcement-list.js +4 -4
- package/dist/pages/account/change-password-page/change-password-page.d.ts +6 -0
- package/dist/pages/account/change-password-page/change-password-page.js +57 -0
- package/dist/pages/account/components/change-password-form/change-password-form.d.ts +16 -0
- package/dist/pages/account/components/change-password-form/change-password-form.js +49 -0
- package/dist/pages/account/components/sign-in-form/sign-in-form.d.ts +3 -3
- package/dist/pages/account/components/sign-in-form/sign-in-form.js +4 -0
- package/dist/pages/account/sign-in-page/sign-in-page.js +51 -14
- package/dist/pages/my-sonic/actions/change-password/change-password-dialog.d.ts +4 -2
- package/dist/pages/my-sonic/actions/change-password/change-password-dialog.js +6 -6
- package/dist/pages/my-sonic/actions/change-password/change-password-dialog.module.css.js +3 -0
- package/dist/pages/my-sonic/actions/change-password/change-password.d.ts +4 -3
- package/dist/pages/my-sonic/actions/change-password/change-password.js +4 -12
- package/dist/pages/my-sonic/actions/change-password/connected-change-password-dialog.js +1 -1
- package/dist/pages/product/product-details-page/product-details.js +6 -2
- package/dist/shared/api/bff/hooks/use-fetch-products-prices.d.ts +2 -0
- package/dist/shared/api/bff/hooks/use-fetch-products-prices.js +14 -0
- package/dist/shared/api/bff/model/bff.model.d.ts +13 -0
- package/dist/shared/api/bff/services/bff-service.d.ts +11 -5
- package/dist/shared/api/bff/services/bff-service.js +52 -29
- package/dist/shared/api/shared/types.d.ts +6 -0
- package/dist/shared/api/storefront/hooks/authentication/use-sign-in.js +4 -7
- package/dist/shared/api/storefront/model/storefront.model.d.ts +4 -0
- package/dist/shared/api/storefront/services/account-service.d.ts +2 -2
- package/dist/shared/api/storefront/services/account-service.js +4 -6
- package/dist/shared/api/storefront/services/authentication-service.d.ts +20 -4
- package/dist/shared/api/storefront/services/authentication-service.js +100 -39
- package/dist/shared/api/storefront/services/cart-service.d.ts +3 -2
- package/dist/shared/api/storefront/services/cart-service.js +2 -1
- package/dist/shared/api/storefront/services/category-service.d.ts +6 -0
- package/dist/shared/api/storefront/services/category-service.js +19 -0
- package/dist/shared/api/storefront/services/translation-service.js +4 -0
- package/dist/shared/feature-flags/use-feature-flags.js +4 -2
- package/dist/styles.css +24 -20
- package/package.json +1 -1
|
@@ -33,7 +33,7 @@ function ConnectedChangePasswordDialog({ isOpen, onClose, }) {
|
|
|
33
33
|
});
|
|
34
34
|
onClose();
|
|
35
35
|
navigate(`${paths.SIGN_IN}${location?.pathname ? `?returnUrl=${encodeURIComponent(location.pathname + location.search)}` : ''}`);
|
|
36
|
-
},
|
|
36
|
+
}, userName: account?.email }));
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export { ConnectedChangePasswordDialog };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
import { useEffect } from 'react';
|
|
3
|
+
import { useRef, useEffect } from 'react';
|
|
4
4
|
import { ConnectedProductCard } from '../../../cards/product-card/connected-product-card.js';
|
|
5
5
|
import { CardCarousel } from '../../../carousel/card-carousel/card-carousel.js';
|
|
6
6
|
import { ProductUSPCarousel } from '../../../carousel/usp-carousel/product-usp-carousel.js';
|
|
@@ -17,9 +17,13 @@ import { ProductDetailsRecentlyViewedSection } from './components/product-detail
|
|
|
17
17
|
function ProductDetails({ data, priceComponent, }) {
|
|
18
18
|
const { breadCrumb, included, page, product, usps } = data;
|
|
19
19
|
const { mutate } = useMarkProductAsRecentlyViewed();
|
|
20
|
+
const isProductMarktedAsViewed = useRef(false);
|
|
20
21
|
useEffect(() => {
|
|
22
|
+
if (typeof window === 'undefined' || isProductMarktedAsViewed.current)
|
|
23
|
+
return;
|
|
24
|
+
isProductMarktedAsViewed.current = true;
|
|
21
25
|
mutate({ productId: product.id });
|
|
22
|
-
}, [mutate, product]);
|
|
26
|
+
}, [mutate, product.id]);
|
|
23
27
|
useDataLayer({
|
|
24
28
|
event: {
|
|
25
29
|
event: 'view_item',
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useQuery } from '@tanstack/react-query';
|
|
3
|
+
import { fetchProductsPrices } from '../services/bff-service.js';
|
|
4
|
+
|
|
5
|
+
function useFetchProductsPrices(args) {
|
|
6
|
+
return useQuery({
|
|
7
|
+
gcTime: 0,
|
|
8
|
+
queryFn: () => fetchProductsPrices(args),
|
|
9
|
+
queryKey: ['products-prices', args],
|
|
10
|
+
staleTime: 0,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { useFetchProductsPrices };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CurrencyCode } from '../../../../intl/types';
|
|
2
2
|
import { ImageType } from '../../../model/image';
|
|
3
|
+
import { UUID } from '../../../utils/uuid';
|
|
3
4
|
export interface PageModel {
|
|
4
5
|
alternateLanguageUrls: {
|
|
5
6
|
[key: string]: string;
|
|
@@ -212,4 +213,16 @@ export type NavigationLinkItem = NavigationLink | NavigationLinkGroup;
|
|
|
212
213
|
export declare const isNavigationLinkItem: (item?: unknown) => item is NavigationLinkItem;
|
|
213
214
|
export type NavigationItem = NavigationSection | NavigationLinkItem;
|
|
214
215
|
export type NavigationResponse = NavigationSection;
|
|
216
|
+
export interface ProductsPricesPrice {
|
|
217
|
+
grossAmount: number;
|
|
218
|
+
vatAmount: number;
|
|
219
|
+
}
|
|
220
|
+
export type ProductsPricesResponse = {
|
|
221
|
+
basicListPrice: ProductsPricesPrice;
|
|
222
|
+
basicSalePrice: ProductsPricesPrice | null;
|
|
223
|
+
currencyCode: CurrencyCode;
|
|
224
|
+
customerPrice: ProductsPricesPrice;
|
|
225
|
+
isOnSale: boolean;
|
|
226
|
+
productId: UUID;
|
|
227
|
+
}[];
|
|
215
228
|
export {};
|
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
import { CultureCode } from '../../../../intl/types';
|
|
2
2
|
import { ProductListingPageData } from '../../../../pages/product/product-listing-page/product-listing-page-data-types';
|
|
3
3
|
import { AnnouncementObject } from '../../../model/announcement';
|
|
4
|
+
import { UUID } from '../../../utils/uuid';
|
|
5
|
+
import { APIArguments } from '../../shared/types';
|
|
4
6
|
import { CartModel, PatchCartModel } from '../../storefront/model/storefront.model';
|
|
5
|
-
import { NavigationResponse, ProductDetailsPageDataResponse, ProductSummary } from '../model/bff.model';
|
|
7
|
+
import { NavigationResponse, ProductDetailsPageDataResponse, ProductsPricesResponse, ProductSummary } from '../model/bff.model';
|
|
6
8
|
export interface FetchAnnouncementsArgs {
|
|
7
9
|
cultureCode: CultureCode;
|
|
8
10
|
}
|
|
9
|
-
export declare function fetchAnnouncements({ cultureCode, }: FetchAnnouncementsArgs): Promise<AnnouncementObject[]>;
|
|
11
|
+
export declare function fetchAnnouncements({ cultureCode, headers, ignoreCache, }: FetchAnnouncementsArgs & APIArguments): Promise<AnnouncementObject[]>;
|
|
10
12
|
export interface FetchProductPageDataArgs {
|
|
11
13
|
cultureCode: CultureCode;
|
|
12
14
|
pageUrl: string;
|
|
13
15
|
}
|
|
14
|
-
export declare function fetchProductDetailsPageData({ cultureCode, pageUrl, }: FetchProductPageDataArgs): Promise<ProductDetailsPageDataResponse>;
|
|
15
|
-
export declare function fetchProductListingPageData({ cultureCode, pageUrl, }: FetchProductPageDataArgs): Promise<ProductListingPageData>;
|
|
16
|
+
export declare function fetchProductDetailsPageData({ cultureCode, headers, ignoreCache, pageUrl, }: FetchProductPageDataArgs & APIArguments): Promise<ProductDetailsPageDataResponse>;
|
|
17
|
+
export declare function fetchProductListingPageData({ cultureCode, headers, ignoreCache, pageUrl, }: FetchProductPageDataArgs & APIArguments): Promise<ProductListingPageData>;
|
|
16
18
|
export type NavigationLinkSource = 'shop' | 'marketing';
|
|
17
19
|
export interface FetchNavigationLinksArgs {
|
|
18
20
|
cultureCode: CultureCode;
|
|
19
21
|
source: NavigationLinkSource;
|
|
20
22
|
}
|
|
21
|
-
export declare function fetchNavigationLinks({ cultureCode, source, }: FetchNavigationLinksArgs): Promise<NavigationResponse>;
|
|
23
|
+
export declare function fetchNavigationLinks({ cultureCode, headers, ignoreCache, source, }: FetchNavigationLinksArgs & APIArguments): Promise<NavigationResponse>;
|
|
22
24
|
export declare function fetchRecentlyViewedProducts({ cultureCode, }: {
|
|
23
25
|
cultureCode: CultureCode;
|
|
24
26
|
}): Promise<ProductSummary[]>;
|
|
@@ -30,6 +32,10 @@ export declare function placeOrder({ cart, isPending, }: {
|
|
|
30
32
|
cart: PatchCartModel;
|
|
31
33
|
isPending?: boolean;
|
|
32
34
|
}): Promise<CartModel>;
|
|
35
|
+
export interface ProductsPricesArgs {
|
|
36
|
+
productIds: UUID[];
|
|
37
|
+
}
|
|
38
|
+
export declare function fetchProductsPrices({ headers, productIds, }: ProductsPricesArgs & APIArguments): Promise<ProductsPricesResponse>;
|
|
33
39
|
export declare function saveCartForLater({ cart }: {
|
|
34
40
|
cart: CartModel;
|
|
35
41
|
}): Promise<CartModel>;
|
|
@@ -3,12 +3,14 @@ import { request } from '../../../fetch/request.js';
|
|
|
3
3
|
import { isAnnouncementType, isAnnouncementSubtype } from '../../../model/announcement.js';
|
|
4
4
|
import { TIME } from '../../../utils/time.js';
|
|
5
5
|
|
|
6
|
-
async function fetchAnnouncements({ cultureCode, }) {
|
|
6
|
+
async function fetchAnnouncements({ cultureCode, headers, ignoreCache, }) {
|
|
7
7
|
const { body } = await request({
|
|
8
|
-
headers: { 'Current-Language-Id': cultureCode },
|
|
8
|
+
headers: { ...headers, 'Current-Language-Id': cultureCode },
|
|
9
9
|
next: {
|
|
10
|
-
revalidate: 1 * TIME.DAY,
|
|
11
|
-
tags:
|
|
10
|
+
revalidate: ignoreCache ? 0 : 1 * TIME.DAY,
|
|
11
|
+
tags: ignoreCache
|
|
12
|
+
? undefined
|
|
13
|
+
: ['announcements', `announcement-${cultureCode}`],
|
|
12
14
|
},
|
|
13
15
|
url: `${config.BFF_API_URL}/notification/announcement`,
|
|
14
16
|
});
|
|
@@ -32,31 +34,35 @@ async function fetchAnnouncements({ cultureCode, }) {
|
|
|
32
34
|
};
|
|
33
35
|
});
|
|
34
36
|
}
|
|
35
|
-
async function fetchProductDetailsPageData({ cultureCode, pageUrl, }) {
|
|
37
|
+
async function fetchProductDetailsPageData({ cultureCode, headers, ignoreCache, pageUrl, }) {
|
|
36
38
|
const { body } = await request({
|
|
37
|
-
headers: { 'Current-Language-Id': cultureCode },
|
|
39
|
+
headers: { 'Current-Language-Id': cultureCode, ...headers },
|
|
38
40
|
next: {
|
|
39
|
-
revalidate: Infinity,
|
|
40
|
-
tags:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
revalidate: ignoreCache ? 0 : Infinity,
|
|
42
|
+
tags: ignoreCache
|
|
43
|
+
? undefined
|
|
44
|
+
: [
|
|
45
|
+
'product-details',
|
|
46
|
+
`product-details-${pageUrl}`,
|
|
47
|
+
`product-details-${pageUrl}-${cultureCode}`,
|
|
48
|
+
],
|
|
45
49
|
},
|
|
46
50
|
url: `${config.BFF_API_URL}/pdp/?pageUrl=${pageUrl}`,
|
|
47
51
|
});
|
|
48
52
|
return body;
|
|
49
53
|
}
|
|
50
|
-
async function fetchProductListingPageData({ cultureCode, pageUrl, }) {
|
|
54
|
+
async function fetchProductListingPageData({ cultureCode, headers, ignoreCache, pageUrl, }) {
|
|
51
55
|
const { body } = await request({
|
|
52
|
-
headers: { 'Current-Language-Id': cultureCode },
|
|
56
|
+
headers: { 'Current-Language-Id': cultureCode, ...headers },
|
|
53
57
|
next: {
|
|
54
|
-
revalidate: Infinity,
|
|
55
|
-
tags:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
revalidate: ignoreCache ? 0 : Infinity,
|
|
59
|
+
tags: ignoreCache
|
|
60
|
+
? undefined
|
|
61
|
+
: [
|
|
62
|
+
'product-listing',
|
|
63
|
+
`product-listing-${pageUrl}`,
|
|
64
|
+
`product-listing-${pageUrl}-${cultureCode}`,
|
|
65
|
+
],
|
|
60
66
|
},
|
|
61
67
|
url: `${config.BFF_API_URL}/plp/?pageUrl=${pageUrl}`,
|
|
62
68
|
});
|
|
@@ -91,16 +97,18 @@ async function fetchProductListingPageData({ cultureCode, pageUrl, }) {
|
|
|
91
97
|
})),
|
|
92
98
|
};
|
|
93
99
|
}
|
|
94
|
-
async function fetchNavigationLinks({ cultureCode, source, }) {
|
|
100
|
+
async function fetchNavigationLinks({ cultureCode, headers, ignoreCache, source, }) {
|
|
95
101
|
const { body } = await request({
|
|
96
|
-
headers: { 'Current-Language-Id': cultureCode, Source: source },
|
|
102
|
+
headers: { 'Current-Language-Id': cultureCode, Source: source, ...headers },
|
|
97
103
|
next: {
|
|
98
|
-
revalidate: Infinity,
|
|
99
|
-
tags:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
revalidate: ignoreCache ? 0 : Infinity,
|
|
105
|
+
tags: ignoreCache
|
|
106
|
+
? undefined
|
|
107
|
+
: [
|
|
108
|
+
'navigation',
|
|
109
|
+
`navigation-${source}`,
|
|
110
|
+
`navigation-${source}-${cultureCode}`,
|
|
111
|
+
],
|
|
104
112
|
},
|
|
105
113
|
url: `${config.BFF_API_URL}/v2/navigation`,
|
|
106
114
|
});
|
|
@@ -143,6 +151,21 @@ async function placeOrder({ cart, isPending, }) {
|
|
|
143
151
|
});
|
|
144
152
|
return body;
|
|
145
153
|
}
|
|
154
|
+
async function fetchProductsPrices({ headers, productIds, }) {
|
|
155
|
+
if (productIds.length === 0)
|
|
156
|
+
return [];
|
|
157
|
+
const { body } = await request({
|
|
158
|
+
body: [...new Set(productIds)],
|
|
159
|
+
credentials: 'include',
|
|
160
|
+
headers: {
|
|
161
|
+
'Content-Type': 'application/json',
|
|
162
|
+
...headers,
|
|
163
|
+
},
|
|
164
|
+
method: 'POST',
|
|
165
|
+
url: `${config.BFF_API_URL}/api/v1/pricing`,
|
|
166
|
+
});
|
|
167
|
+
return body;
|
|
168
|
+
}
|
|
146
169
|
async function saveCartForLater({ cart }) {
|
|
147
170
|
// USER NEEDS TO BE LOGGED IN
|
|
148
171
|
const { body } = await request({
|
|
@@ -157,4 +180,4 @@ async function saveCartForLater({ cart }) {
|
|
|
157
180
|
return body;
|
|
158
181
|
}
|
|
159
182
|
|
|
160
|
-
export { fetchAnnouncements, fetchNavigationLinks, fetchProductDetailsPageData, fetchProductListingPageData, fetchRecentlyViewedProducts, patchCart, placeOrder, saveCartForLater };
|
|
183
|
+
export { fetchAnnouncements, fetchNavigationLinks, fetchProductDetailsPageData, fetchProductListingPageData, fetchProductsPrices, fetchRecentlyViewedProducts, patchCart, placeOrder, saveCartForLater };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useQueryClient, useMutation } from '@tanstack/react-query';
|
|
3
|
-
import {
|
|
4
|
-
import { signIn, createSession } from '../../services/authentication-service.js';
|
|
3
|
+
import { signIn, createSession, InvalidGrantError } from '../../services/authentication-service.js';
|
|
5
4
|
|
|
6
5
|
function useSignIn() {
|
|
7
6
|
const queryClient = useQueryClient();
|
|
@@ -19,11 +18,9 @@ function useSignIn() {
|
|
|
19
18
|
return body;
|
|
20
19
|
}
|
|
21
20
|
catch (error) {
|
|
22
|
-
if (
|
|
23
|
-
error
|
|
24
|
-
|
|
25
|
-
queryClient.resetQueries();
|
|
26
|
-
}
|
|
21
|
+
if (error instanceof InvalidGrantError)
|
|
22
|
+
throw error;
|
|
23
|
+
queryClient.resetQueries();
|
|
27
24
|
throw error;
|
|
28
25
|
}
|
|
29
26
|
},
|
|
@@ -169,6 +169,10 @@ export type PatchSessionModel = Partial<Omit<SessionModel, 'billTo' | 'shipTo'>
|
|
|
169
169
|
} | null;
|
|
170
170
|
shipToId?: string | null;
|
|
171
171
|
}>;
|
|
172
|
+
export interface SpirePageModel {
|
|
173
|
+
redirectTo: string | null;
|
|
174
|
+
statusCode: number;
|
|
175
|
+
}
|
|
172
176
|
export interface ShipToModel extends BaseModel {
|
|
173
177
|
address1: string;
|
|
174
178
|
address2: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BadRequestError } from '../../../fetch/request';
|
|
2
2
|
import { AccountModel } from '../model/storefront.model';
|
|
3
3
|
export declare function fetchCurrentAccount(): Promise<AccountModel>;
|
|
4
|
-
export declare class ExistingAccountError extends
|
|
4
|
+
export declare class ExistingAccountError extends BadRequestError {
|
|
5
5
|
constructor(error: Error);
|
|
6
6
|
}
|
|
7
7
|
export interface CreateAccountRequestBase {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { config } from '../../../../config.js';
|
|
2
|
-
import { request,
|
|
2
|
+
import { request, BadRequestError } from '../../../fetch/request.js';
|
|
3
3
|
|
|
4
4
|
async function fetchCurrentAccount() {
|
|
5
5
|
const { body } = await request({
|
|
@@ -7,7 +7,7 @@ async function fetchCurrentAccount() {
|
|
|
7
7
|
});
|
|
8
8
|
return body;
|
|
9
9
|
}
|
|
10
|
-
class ExistingAccountError extends
|
|
10
|
+
class ExistingAccountError extends BadRequestError {
|
|
11
11
|
constructor(error) {
|
|
12
12
|
super(error);
|
|
13
13
|
this.name = 'ExistingAccountError';
|
|
@@ -38,8 +38,7 @@ async function createAccount({ companyName, countryCode, email, firstName, isPri
|
|
|
38
38
|
return body;
|
|
39
39
|
}
|
|
40
40
|
catch (error) {
|
|
41
|
-
if (
|
|
42
|
-
error.status === 400 &&
|
|
41
|
+
if (error instanceof BadRequestError &&
|
|
43
42
|
error.body?.message === 'Email Address already exists')
|
|
44
43
|
throw new ExistingAccountError(error);
|
|
45
44
|
throw error;
|
|
@@ -73,8 +72,7 @@ async function patchCurrentAccount({ account, }) {
|
|
|
73
72
|
return body;
|
|
74
73
|
}
|
|
75
74
|
catch (error) {
|
|
76
|
-
if (
|
|
77
|
-
error.status === 400 &&
|
|
75
|
+
if (error instanceof BadRequestError &&
|
|
78
76
|
error.body?.message === 'Email Address already exists')
|
|
79
77
|
throw new ExistingAccountError(error);
|
|
80
78
|
throw error;
|
|
@@ -1,10 +1,26 @@
|
|
|
1
|
-
import { RequestError } from '../../../fetch/request';
|
|
1
|
+
import { BadRequestError, RequestError } from '../../../fetch/request';
|
|
2
|
+
import { APIArguments } from '../../shared/types';
|
|
2
3
|
import { PatchSessionModel, SessionModel } from '../model/storefront.model';
|
|
3
|
-
export declare function fetchSession(): Promise<SessionModel>;
|
|
4
|
-
export declare class InvalidPasswordError extends
|
|
4
|
+
export declare function fetchSession(args?: APIArguments): Promise<SessionModel>;
|
|
5
|
+
export declare class InvalidPasswordError extends BadRequestError {
|
|
5
6
|
constructor(error: RequestError);
|
|
6
7
|
}
|
|
7
|
-
export declare class NonUniquePasswordError extends
|
|
8
|
+
export declare class NonUniquePasswordError extends BadRequestError {
|
|
9
|
+
constructor(error: RequestError);
|
|
10
|
+
}
|
|
11
|
+
export declare class UserNotFoundError extends BadRequestError {
|
|
12
|
+
constructor(error: RequestError);
|
|
13
|
+
}
|
|
14
|
+
export declare class UnableToChangePasswordError extends BadRequestError {
|
|
15
|
+
constructor(error: RequestError);
|
|
16
|
+
}
|
|
17
|
+
export declare class InvalidGrantError extends BadRequestError {
|
|
18
|
+
constructor(error: RequestError);
|
|
19
|
+
}
|
|
20
|
+
export declare class InvalidEmailPasswordCombinationError extends InvalidGrantError {
|
|
21
|
+
constructor(error: RequestError);
|
|
22
|
+
}
|
|
23
|
+
export declare class AccountLockedOutError extends InvalidGrantError {
|
|
8
24
|
constructor(error: RequestError);
|
|
9
25
|
}
|
|
10
26
|
export declare function patchSession({ session, }: {
|
|
@@ -1,25 +1,56 @@
|
|
|
1
1
|
import { config } from '../../../../config.js';
|
|
2
|
-
import { request,
|
|
2
|
+
import { request, BadRequestError, UnauthorizedRequestError } from '../../../fetch/request.js';
|
|
3
3
|
|
|
4
|
-
async function fetchSession() {
|
|
4
|
+
async function fetchSession(args) {
|
|
5
5
|
const { body } = await request({
|
|
6
6
|
credentials: 'include',
|
|
7
|
+
headers: args?.headers,
|
|
7
8
|
url: `${config.SHOP_API_URL}/api/v1/sessions/current`,
|
|
8
9
|
});
|
|
9
10
|
return body;
|
|
10
11
|
}
|
|
11
|
-
class InvalidPasswordError extends
|
|
12
|
+
class InvalidPasswordError extends BadRequestError {
|
|
12
13
|
constructor(error) {
|
|
13
14
|
super(error.body?.message || error.message);
|
|
14
15
|
this.name = 'InvalidPasswordError';
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
|
-
class NonUniquePasswordError extends
|
|
18
|
+
class NonUniquePasswordError extends BadRequestError {
|
|
18
19
|
constructor(error) {
|
|
19
20
|
super(error.body?.message || error.message);
|
|
20
21
|
this.name = 'NonUniquePasswordError';
|
|
21
22
|
}
|
|
22
23
|
}
|
|
24
|
+
class UserNotFoundError extends BadRequestError {
|
|
25
|
+
constructor(error) {
|
|
26
|
+
super(error.body?.message || error.message);
|
|
27
|
+
this.name = 'UserNotFoundError';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
class UnableToChangePasswordError extends BadRequestError {
|
|
31
|
+
constructor(error) {
|
|
32
|
+
super(error.body?.message || error.message);
|
|
33
|
+
this.name = 'UnableToChangePasswordError';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
class InvalidGrantError extends BadRequestError {
|
|
37
|
+
constructor(error) {
|
|
38
|
+
super(error.body?.message || error.message);
|
|
39
|
+
this.name = 'InvalidGrantError';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
class InvalidEmailPasswordCombinationError extends InvalidGrantError {
|
|
43
|
+
constructor(error) {
|
|
44
|
+
super(error.body?.message || error.message);
|
|
45
|
+
this.name = 'InvalidEmailPasswordCombinationError';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
class AccountLockedOutError extends InvalidGrantError {
|
|
49
|
+
constructor(error) {
|
|
50
|
+
super(error.body?.message || error.message);
|
|
51
|
+
this.name = 'AccountLockedOutError';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
23
54
|
async function patchSession({ session, }) {
|
|
24
55
|
try {
|
|
25
56
|
const { body } = await request({
|
|
@@ -34,14 +65,16 @@ async function patchSession({ session, }) {
|
|
|
34
65
|
return body;
|
|
35
66
|
}
|
|
36
67
|
catch (error) {
|
|
37
|
-
if (
|
|
68
|
+
if (error instanceof BadRequestError) {
|
|
38
69
|
if (error.body?.message ===
|
|
39
|
-
'New Password is required and must be different than Current Password')
|
|
70
|
+
'New Password is required and must be different than Current Password')
|
|
40
71
|
throw new NonUniquePasswordError(error);
|
|
41
|
-
|
|
42
|
-
if (error.body?.message === 'Current Password is invalid') {
|
|
72
|
+
if (error.body?.message === 'Current Password is invalid')
|
|
43
73
|
throw new InvalidPasswordError(error);
|
|
44
|
-
|
|
74
|
+
if (error.body?.message === 'User not found.')
|
|
75
|
+
throw new UserNotFoundError(error);
|
|
76
|
+
if (error.body?.message === 'Unable to change Password at this time.')
|
|
77
|
+
throw new UnableToChangePasswordError(error);
|
|
45
78
|
}
|
|
46
79
|
throw error;
|
|
47
80
|
}
|
|
@@ -52,36 +85,64 @@ async function signIn({ password, userName, }) {
|
|
|
52
85
|
params.append('username', userName);
|
|
53
86
|
params.append('password', password);
|
|
54
87
|
params.append('scope', 'iscapi offline_access');
|
|
55
|
-
|
|
56
|
-
body
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
88
|
+
try {
|
|
89
|
+
const { body } = await request({
|
|
90
|
+
body: params.toString(),
|
|
91
|
+
headers: {
|
|
92
|
+
Authorization: `Basic ${btoa('isc:009AC476-B28E-4E33-8BAE-B5F103A142BC')}`,
|
|
93
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
94
|
+
},
|
|
95
|
+
method: 'POST',
|
|
96
|
+
url: `${config.SHOP_API_URL}/identity/connect/token`,
|
|
97
|
+
});
|
|
98
|
+
return body;
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
if (error instanceof BadRequestError &&
|
|
102
|
+
error.body?.error === 'invalid_grant') {
|
|
103
|
+
const description = error.body?.error_description;
|
|
104
|
+
if (description === 'Invalid Email/Password combination')
|
|
105
|
+
throw new InvalidEmailPasswordCombinationError(error);
|
|
106
|
+
if (description === 'Account is locked out')
|
|
107
|
+
throw new AccountLockedOutError(error);
|
|
108
|
+
throw new InvalidGrantError(error);
|
|
109
|
+
}
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
65
112
|
}
|
|
66
113
|
async function createSession({ accessToken, isGuest, keepMeSignedIn, password, rememberMe, returnUrl, userName, }) {
|
|
67
|
-
|
|
68
|
-
body
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
114
|
+
try {
|
|
115
|
+
const { body } = await request({
|
|
116
|
+
body: {
|
|
117
|
+
isGuest,
|
|
118
|
+
keepMeSignedIn,
|
|
119
|
+
password,
|
|
120
|
+
rememberMe,
|
|
121
|
+
returnUrl,
|
|
122
|
+
userName,
|
|
123
|
+
},
|
|
124
|
+
headers: {
|
|
125
|
+
Accept: 'application/json, text/plain, */*',
|
|
126
|
+
Authorization: `Bearer ${accessToken}`,
|
|
127
|
+
'Content-Type': 'application/json',
|
|
128
|
+
},
|
|
129
|
+
method: 'POST',
|
|
130
|
+
url: `${config.SHOP_API_URL}/api/v1/sessions`,
|
|
131
|
+
});
|
|
132
|
+
return body;
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
if (error instanceof BadRequestError &&
|
|
136
|
+
error.body?.error === 'invalid_grant') {
|
|
137
|
+
const description = error.body?.error_description;
|
|
138
|
+
if (description === 'Invalid Email/Password combination')
|
|
139
|
+
throw new InvalidEmailPasswordCombinationError(error);
|
|
140
|
+
if (description === 'Account is locked out')
|
|
141
|
+
throw new AccountLockedOutError(error);
|
|
142
|
+
throw new InvalidGrantError(error);
|
|
143
|
+
}
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
85
146
|
}
|
|
86
147
|
async function signOut() {
|
|
87
148
|
try {
|
|
@@ -91,7 +152,7 @@ async function signOut() {
|
|
|
91
152
|
});
|
|
92
153
|
}
|
|
93
154
|
catch (error) {
|
|
94
|
-
if (
|
|
155
|
+
if (error instanceof UnauthorizedRequestError)
|
|
95
156
|
return;
|
|
96
157
|
throw error;
|
|
97
158
|
}
|
|
@@ -111,4 +172,4 @@ async function recoverPassword({ userName, }) {
|
|
|
111
172
|
return body;
|
|
112
173
|
}
|
|
113
174
|
|
|
114
|
-
export { InvalidPasswordError, NonUniquePasswordError, createSession, fetchSession, patchSession, recoverPassword, signIn, signOut };
|
|
175
|
+
export { AccountLockedOutError, InvalidEmailPasswordCombinationError, InvalidGrantError, InvalidPasswordError, NonUniquePasswordError, UnableToChangePasswordError, UserNotFoundError, createSession, fetchSession, patchSession, recoverPassword, signIn, signOut };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { APIArguments } from '../../shared/types';
|
|
1
2
|
import { AdyenPaymentModel, CartLineModel, CartLineModel as ShopCartLineModel, CartModel, CheckoutAtpEntry, ProductAtp, PromotionModel } from '../model/storefront.model';
|
|
2
|
-
export declare function fetchCart({ forceRecalculation, id, }: {
|
|
3
|
+
export declare function fetchCart({ forceRecalculation, headers, id, }: {
|
|
3
4
|
forceRecalculation?: boolean;
|
|
4
5
|
id: string;
|
|
5
|
-
}): Promise<CartModel>;
|
|
6
|
+
} & APIArguments): Promise<CartModel>;
|
|
6
7
|
export declare function fetchCurrentCart({ forceRecalculation, }?: {
|
|
7
8
|
forceRecalculation?: boolean;
|
|
8
9
|
}): Promise<CartModel>;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { config } from '../../../../config.js';
|
|
2
2
|
import { request } from '../../../fetch/request.js';
|
|
3
3
|
|
|
4
|
-
async function fetchCart({ forceRecalculation = false, id, }) {
|
|
4
|
+
async function fetchCart({ forceRecalculation = false, headers, id, }) {
|
|
5
5
|
const { body } = await request({
|
|
6
6
|
credentials: 'include',
|
|
7
|
+
headers,
|
|
7
8
|
url: `${config.SHOP_API_URL}/api/v1/carts/${id}?expand=shipping%2Cvalidation%2CcartLines%2Crestrictions%2Ccarriers%2CpaymentOptions%2CcostCodes%2Chiddenproducts%2Ctax&forceRecalculation=${String(forceRecalculation)}&allowInvalidAddress=true`,
|
|
8
9
|
});
|
|
9
10
|
return body;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CultureCode } from '../../../../intl/types';
|
|
2
|
+
import { APIArguments } from '../../shared/types';
|
|
3
|
+
import { CategoryCollectionModel } from '../model/storefront.model';
|
|
4
|
+
export declare function fetchCategories({ headers, ignoreCache, languageCultureCode, }: {
|
|
5
|
+
languageCultureCode: CultureCode;
|
|
6
|
+
} & APIArguments): Promise<CategoryCollectionModel>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { config } from '../../../../config.js';
|
|
2
|
+
import { request } from '../../../fetch/request.js';
|
|
3
|
+
|
|
4
|
+
async function fetchCategories({ headers, ignoreCache, languageCultureCode, }) {
|
|
5
|
+
const { body } = await request({
|
|
6
|
+
credentials: 'include',
|
|
7
|
+
headers,
|
|
8
|
+
next: {
|
|
9
|
+
revalidate: ignoreCache ? 0 : Infinity,
|
|
10
|
+
tags: ignoreCache
|
|
11
|
+
? []
|
|
12
|
+
: ['categories', `categories-${languageCultureCode}`],
|
|
13
|
+
},
|
|
14
|
+
url: `${config.SHOP_API_URL}/api/v1/categories`,
|
|
15
|
+
});
|
|
16
|
+
return body;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { fetchCategories };
|
|
@@ -5,6 +5,10 @@ async function fetchTranslations(languageCode) {
|
|
|
5
5
|
const translations = {};
|
|
6
6
|
const { body } = await request({
|
|
7
7
|
credentials: 'include',
|
|
8
|
+
next: {
|
|
9
|
+
revalidate: Infinity,
|
|
10
|
+
tags: [`translations-${languageCode}`],
|
|
11
|
+
},
|
|
8
12
|
url: `${config.SHOP_API_URL}/api/v1/translationdictionaries?page=1&pageSize=9999&languageCode=${languageCode}`,
|
|
9
13
|
});
|
|
10
14
|
body.translationDictionaries?.forEach(dictionary => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useMemo } from 'react';
|
|
2
|
+
import { useContext, useMemo } from 'react';
|
|
3
3
|
import qs from 'query-string';
|
|
4
|
+
import { LocalStorageContext } from '../local-storage/local-storage-context.js';
|
|
4
5
|
|
|
5
6
|
const features = {
|
|
6
7
|
cartv1: 'cartV1',
|
|
@@ -11,6 +12,7 @@ const features = {
|
|
|
11
12
|
translations: 'translations',
|
|
12
13
|
};
|
|
13
14
|
function useFeatureFlags() {
|
|
15
|
+
const { localStorage } = useContext(LocalStorageContext) ?? {};
|
|
14
16
|
const { search } = typeof window === 'undefined'
|
|
15
17
|
? {
|
|
16
18
|
search: '',
|
|
@@ -41,7 +43,7 @@ function useFeatureFlags() {
|
|
|
41
43
|
...acc,
|
|
42
44
|
[value]: selected,
|
|
43
45
|
}), {});
|
|
44
|
-
}, [search]);
|
|
46
|
+
}, [search, localStorage]);
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
export { useFeatureFlags };
|