@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.
Files changed (42) hide show
  1. package/dist/exports.d.ts +5 -0
  2. package/dist/footer/connected-footer.js +3 -1
  3. package/dist/forms/partials/password-validation/password-validation.js +1 -1
  4. package/dist/index.js +6 -2
  5. package/dist/intl/translation-id.d.ts +1 -1
  6. package/dist/modals/dialog/dialog.d.ts +1 -0
  7. package/dist/modals/dialog/dialog.js +3 -2
  8. package/dist/notifications/announcements/connected-announcement-list.js +4 -4
  9. package/dist/pages/account/change-password-page/change-password-page.d.ts +6 -0
  10. package/dist/pages/account/change-password-page/change-password-page.js +57 -0
  11. package/dist/pages/account/components/change-password-form/change-password-form.d.ts +16 -0
  12. package/dist/pages/account/components/change-password-form/change-password-form.js +49 -0
  13. package/dist/pages/account/components/sign-in-form/sign-in-form.d.ts +3 -3
  14. package/dist/pages/account/components/sign-in-form/sign-in-form.js +4 -0
  15. package/dist/pages/account/sign-in-page/sign-in-page.js +51 -14
  16. package/dist/pages/my-sonic/actions/change-password/change-password-dialog.d.ts +4 -2
  17. package/dist/pages/my-sonic/actions/change-password/change-password-dialog.js +6 -6
  18. package/dist/pages/my-sonic/actions/change-password/change-password-dialog.module.css.js +3 -0
  19. package/dist/pages/my-sonic/actions/change-password/change-password.d.ts +4 -3
  20. package/dist/pages/my-sonic/actions/change-password/change-password.js +4 -12
  21. package/dist/pages/my-sonic/actions/change-password/connected-change-password-dialog.js +1 -1
  22. package/dist/pages/product/product-details-page/product-details.js +6 -2
  23. package/dist/shared/api/bff/hooks/use-fetch-products-prices.d.ts +2 -0
  24. package/dist/shared/api/bff/hooks/use-fetch-products-prices.js +14 -0
  25. package/dist/shared/api/bff/model/bff.model.d.ts +13 -0
  26. package/dist/shared/api/bff/services/bff-service.d.ts +11 -5
  27. package/dist/shared/api/bff/services/bff-service.js +52 -29
  28. package/dist/shared/api/shared/types.d.ts +6 -0
  29. package/dist/shared/api/storefront/hooks/authentication/use-sign-in.js +4 -7
  30. package/dist/shared/api/storefront/model/storefront.model.d.ts +4 -0
  31. package/dist/shared/api/storefront/services/account-service.d.ts +2 -2
  32. package/dist/shared/api/storefront/services/account-service.js +4 -6
  33. package/dist/shared/api/storefront/services/authentication-service.d.ts +20 -4
  34. package/dist/shared/api/storefront/services/authentication-service.js +100 -39
  35. package/dist/shared/api/storefront/services/cart-service.d.ts +3 -2
  36. package/dist/shared/api/storefront/services/cart-service.js +2 -1
  37. package/dist/shared/api/storefront/services/category-service.d.ts +6 -0
  38. package/dist/shared/api/storefront/services/category-service.js +19 -0
  39. package/dist/shared/api/storefront/services/translation-service.js +4 -0
  40. package/dist/shared/feature-flags/use-feature-flags.js +4 -2
  41. package/dist/styles.css +24 -20
  42. 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
- }, username: account?.email }));
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,2 @@
1
+ import { ProductsPricesArgs } from '../services/bff-service';
2
+ export declare function useFetchProductsPrices(args: ProductsPricesArgs): import("@tanstack/react-query").UseQueryResult<import("../model/bff.model").ProductsPricesResponse, Error>;
@@ -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: ['announcements', `announcement-${cultureCode}`],
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
- 'product-details',
42
- `product-details-${pageUrl}`,
43
- `product-details-${pageUrl}-${cultureCode}`,
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
- 'product-listing',
57
- `product-listing-${pageUrl}`,
58
- `product-listing-${pageUrl}-${cultureCode}`,
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
- 'navigation',
101
- `navigation-${source}`,
102
- `navigation-${source}-${cultureCode}`,
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 };
@@ -0,0 +1,6 @@
1
+ export interface APIArguments {
2
+ headers?: {
3
+ cookie?: string;
4
+ };
5
+ ignoreCache?: boolean;
6
+ }
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
  import { useQueryClient, useMutation } from '@tanstack/react-query';
3
- import { isRequestError } from '../../../../fetch/request.js';
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 (!(isRequestError(error) &&
23
- error.status === 400 &&
24
- error.body?.error === 'invalid_grant')) {
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 { RequestError } from '../../../fetch/request';
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 RequestError {
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, RequestError, isRequestError } from '../../../fetch/request.js';
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 RequestError {
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 (isRequestError(error) &&
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 (isRequestError(error) &&
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 Error {
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 Error {
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, isRequestError } from '../../../fetch/request.js';
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 Error {
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 Error {
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 (isRequestError(error) && error.status === 400) {
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
- const { body } = await request({
56
- body: params.toString(),
57
- headers: {
58
- Authorization: `Basic ${btoa('isc:009AC476-B28E-4E33-8BAE-B5F103A142BC')}`,
59
- 'Content-Type': 'application/x-www-form-urlencoded',
60
- },
61
- method: 'POST',
62
- url: `${config.SHOP_API_URL}/identity/connect/token`,
63
- });
64
- return body;
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
- const { body } = await request({
68
- body: {
69
- isGuest,
70
- keepMeSignedIn,
71
- password,
72
- rememberMe,
73
- returnUrl,
74
- userName,
75
- },
76
- headers: {
77
- Accept: 'application/json, text/plain, */*',
78
- Authorization: `Bearer ${accessToken}`,
79
- 'Content-Type': 'application/json',
80
- },
81
- method: 'POST',
82
- url: `${config.SHOP_API_URL}/api/v1/sessions`,
83
- });
84
- return body;
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 (isRequestError(error) && error.status === 401)
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 };