@sonic-equipment/ui 225.0.0 → 226.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 CHANGED
@@ -318,9 +318,11 @@ export * from './shared/api/bff/hooks/use-fetch-favorites';
318
318
  export * from './shared/api/bff/hooks/use-fetch-navigation-links';
319
319
  export * from './shared/api/bff/hooks/use-fetch-product-details-page-data';
320
320
  export * from './shared/api/bff/hooks/use-fetch-product-listing-page-data';
321
+ export * from './shared/api/bff/hooks/use-fetch-products-prices';
321
322
  export * from './shared/api/bff/hooks/use-fetch-recently-viewed-products';
322
323
  export * from './shared/api/bff/services/bff-service';
323
324
  export * from './shared/api/shared/hooks/use-awaitable-mutation';
325
+ export * from './shared/api/shared/types';
324
326
  export * from './shared/api/storefront/hooks/account/use-create-account';
325
327
  export * from './shared/api/storefront/hooks/account/use-create-guest-account';
326
328
  export * from './shared/api/storefront/hooks/account/use-fetch-current-account';
@@ -381,6 +383,7 @@ export * from './shared/api/storefront/hooks/wishlist/use-fetch-wishlists';
381
383
  export * from './shared/api/storefront/services/account-service';
382
384
  export * from './shared/api/storefront/services/authentication-service';
383
385
  export * from './shared/api/storefront/services/cart-service';
386
+ export * from './shared/api/storefront/services/category-service';
384
387
  export * from './shared/api/storefront/services/customer-service';
385
388
  export * from './shared/api/storefront/services/finance-service';
386
389
  export * from './shared/api/storefront/services/order-service';
@@ -5,17 +5,19 @@ import { FormattedMessage } from '../intl/formatted-message.js';
5
5
  import { useCultureCode } from '../intl/use-culture-code.js';
6
6
  import { useFetchNavigationLinks } from '../shared/api/bff/hooks/use-fetch-navigation-links.js';
7
7
  import { isNavigationSection } from '../shared/api/bff/model/bff.model.js';
8
+ import { useIsAuthenticated } from '../shared/api/storefront/hooks/authentication/use-is-authenticated.js';
8
9
  import { Footer } from './footer.js';
9
10
 
10
11
  function ConnectedFooter({ className, onCountryLanguageChange, source, }) {
11
12
  const cultureCode = useCultureCode();
12
13
  const { data } = useFetchNavigationLinks({ cultureCode, source });
14
+ const isAuthenticated = useIsAuthenticated();
13
15
  if (data && data.key !== 'navigation')
14
16
  throw new Error('Invalid navigation data');
15
17
  const footerNavigationSection = data?.items
16
18
  .filter(isNavigationSection)
17
19
  .find(item => item.key === 'footer');
18
- return (jsx(Footer, { className: className, copyright: jsx(FormattedMessage, { id: "Copyright \u00A9 Sonic Equipment B.V." }), countrySelector: jsx(ConnectedCountrySelector, { defaultCountryCode: "NL", defaultLanguageCode: "EN", onChange: onCountryLanguageChange }), footerNavigationSection: footerNavigationSection }));
20
+ return (jsx(Footer, { className: className, copyright: jsx(FormattedMessage, { id: "Copyright \u00A9 Sonic Equipment B.V." }), countrySelector: jsx(ConnectedCountrySelector, { defaultCountryCode: "NL", defaultLanguageCode: "EN", onChange: onCountryLanguageChange, showCountry: isAuthenticated === false }), footerNavigationSection: footerNavigationSection }));
19
21
  }
20
22
 
21
23
  export { ConnectedFooter };
package/dist/index.js CHANGED
@@ -318,8 +318,9 @@ export { useFetchFavorites } from './shared/api/bff/hooks/use-fetch-favorites.js
318
318
  export { useFetchNavigationLinks } from './shared/api/bff/hooks/use-fetch-navigation-links.js';
319
319
  export { useFetchProductDetailsPageData } from './shared/api/bff/hooks/use-fetch-product-details-page-data.js';
320
320
  export { useFetchProductListingPageData } from './shared/api/bff/hooks/use-fetch-product-listing-page-data.js';
321
+ export { useFetchProductsPrices } from './shared/api/bff/hooks/use-fetch-products-prices.js';
321
322
  export { useFetchRecentlyViewedProducts } from './shared/api/bff/hooks/use-fetch-recently-viewed-products.js';
322
- export { fetchAnnouncements, fetchNavigationLinks, fetchProductDetailsPageData, fetchProductListingPageData, fetchRecentlyViewedProducts, patchCart, placeOrder, saveCartForLater } from './shared/api/bff/services/bff-service.js';
323
+ export { fetchAnnouncements, fetchNavigationLinks, fetchProductDetailsPageData, fetchProductListingPageData, fetchProductsPrices, fetchRecentlyViewedProducts, patchCart, placeOrder, saveCartForLater } from './shared/api/bff/services/bff-service.js';
323
324
  export { useAwaitableMutation } from './shared/api/shared/hooks/use-awaitable-mutation.js';
324
325
  export { useCreateAccount } from './shared/api/storefront/hooks/account/use-create-account.js';
325
326
  export { useCreateGuestAccount } from './shared/api/storefront/hooks/account/use-create-guest-account.js';
@@ -381,6 +382,7 @@ export { useFetchWishLists } from './shared/api/storefront/hooks/wishlist/use-fe
381
382
  export { ExistingAccountError, createAccount, createGuestAccount, fetchCurrentAccount, patchCurrentAccount } from './shared/api/storefront/services/account-service.js';
382
383
  export { InvalidPasswordError, NonUniquePasswordError, createSession, fetchSession, patchSession, recoverPassword, signIn, signOut } from './shared/api/storefront/services/authentication-service.js';
383
384
  export { addBulkProductsToCurrentCart, addProductToCurrentCart, convertToMinorUnits, deleteCartLineById, deleteCurrentCart, fetchCart, fetchCurrentCart, fetchCurrentCartLines, fetchCurrentCartProductAtp, fetchCurrentCartPromotions, fetchCurrentCheckoutAtp, getAdyenPaymentDetails, patchCartLineById, postAdyenPayment } from './shared/api/storefront/services/cart-service.js';
385
+ export { fetchCategories } from './shared/api/storefront/services/category-service.js';
384
386
  export { fetchBillToAddress, fetchBillToAddresses, fetchCurrentBillToAddress, fetchCurrentShipToAddress, fetchFulfillmentMethods, fetchPagedShipToAddresses, fetchShipToAddress, fetchShipToAddresses, patchBillToAddress, patchShipToAddress, postShipToAddress } from './shared/api/storefront/services/customer-service.js';
385
387
  export { validateVATNumber } from './shared/api/storefront/services/finance-service.js';
386
388
  export { fetchOrderById, fetchOrders } from './shared/api/storefront/services/order-service.js';
@@ -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,6 +1,7 @@
1
1
  import { 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 function fetchSession(args?: APIArguments): Promise<SessionModel>;
4
5
  export declare class InvalidPasswordError extends Error {
5
6
  constructor(error: RequestError);
6
7
  }
@@ -1,9 +1,10 @@
1
1
  import { config } from '../../../../config.js';
2
2
  import { request, isRequestError } 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;
@@ -0,0 +1,7 @@
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, languageCultureCode, sessionId, }: {
5
+ languageCultureCode?: CultureCode;
6
+ sessionId?: string;
7
+ } & APIArguments): Promise<CategoryCollectionModel>;
@@ -0,0 +1,27 @@
1
+ import { config } from '../../../../config.js';
2
+ import { request } from '../../../fetch/request.js';
3
+
4
+ async function fetchCategories({ headers, languageCultureCode, sessionId, }) {
5
+ const url = new URL(`${config.SHOP_API_URL}/api/v1/categories`);
6
+ if (languageCultureCode)
7
+ url.searchParams.append('locale', languageCultureCode);
8
+ if (sessionId)
9
+ url.searchParams.append('sessionId', sessionId);
10
+ const tags = ['categories'];
11
+ if (languageCultureCode)
12
+ tags.push(`categories-${languageCultureCode}`);
13
+ if (sessionId)
14
+ tags.push(`categories-sid-${sessionId}`);
15
+ const { body } = await request({
16
+ credentials: 'include',
17
+ headers,
18
+ next: {
19
+ revalidate: sessionId ? 0 : Infinity,
20
+ tags,
21
+ },
22
+ url: url.toString(),
23
+ });
24
+ return body;
25
+ }
26
+
27
+ 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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonic-equipment/ui",
3
- "version": "225.0.0",
3
+ "version": "226.0.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "engines": {