@sonic-equipment/ui 0.0.27 → 0.0.28
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/algolia/algolia-provider.d.ts +1 -1
- package/dist/breadcrumbs/breadcrumb.stories.d.ts +2 -2
- package/dist/breadcrumbs/connected-breadcrumb.d.ts +1 -1
- package/dist/cards/category-card/category-card.d.ts +2 -5
- package/dist/cards/product-card/product-card.d.ts +2 -2
- package/dist/carousel/category-carousel/connected-category-carousel.d.ts +1 -0
- package/dist/index.d.ts +26 -51
- package/dist/index.js +266 -151
- package/dist/media/image/image.d.ts +2 -19
- package/dist/pages/product-listing-page/product-listing-page-data-types.d.ts +20 -0
- package/dist/pages/product-listing-page/product-listing-page-provider/product-listing-page-context.d.ts +9 -0
- package/dist/pages/product-listing-page/product-listing-page-provider/product-listing-page-provider.d.ts +8 -0
- package/dist/pages/product-listing-page/product-listing-page-provider/use-breadcrumb.d.ts +4 -0
- package/dist/pages/product-listing-page/product-listing-page-provider/use-subcategories.d.ts +4 -0
- package/dist/pages/product-listing-page/product-listing-page.d.ts +5 -3
- package/dist/pages/product-listing-page/product-listing-page.stories.d.ts +7 -10
- package/dist/pages/product-listing-page/types.d.ts +34 -0
- package/dist/pages/product-listing-page/use-fetch-product-listing-page/product-listing-page-data-response.d.ts +48 -0
- package/dist/pages/product-listing-page/use-fetch-product-listing-page/use-fetch-product-listing-page-data.d.ts +2 -0
- package/dist/pages/product-listing-page/use-fetch-product-listing-page/use-fetch-product-listing-page-data.stories.d.ts +20 -0
- package/dist/shared/fetch/ResponseError.d.ts +9 -0
- package/dist/shared/hooks/use-scroll-to.d.ts +1 -0
- package/dist/shared/types/category.d.ts +6 -0
- package/dist/shared/types/image.d.ts +20 -0
- package/dist/styles.css +13 -1
- package/package.json +26 -25
- package/dist/shared/providers/breadcrumb-provider.d.ts +0 -11
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { StoryObj } from '@storybook/react';
|
|
2
|
-
import {
|
|
2
|
+
import { ProductListingPageData } from 'pages/product-listing-page/product-listing-page-data-types';
|
|
3
3
|
import { Breadcrumb } from './breadcrumb';
|
|
4
4
|
declare const meta: {
|
|
5
5
|
component: typeof Breadcrumb;
|
|
@@ -15,5 +15,5 @@ export declare const FourLevelsMobile: Story;
|
|
|
15
15
|
export declare const TwoLevels: Story;
|
|
16
16
|
export declare const TwoLevelsMobile: Story;
|
|
17
17
|
export declare const Connected: StoryObj<{
|
|
18
|
-
|
|
18
|
+
data: ProductListingPageData;
|
|
19
19
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function ConnectedBreadcrumb(): import("react/jsx-runtime").JSX.Element;
|
|
1
|
+
export declare function ConnectedBreadcrumb(): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export interface CategoryCardProps {
|
|
3
|
-
href: string;
|
|
4
|
-
image: ImageProps;
|
|
1
|
+
import { Category } from 'shared/types/category';
|
|
2
|
+
export interface CategoryCardProps extends Category {
|
|
5
3
|
isSelected?: boolean;
|
|
6
|
-
title: string;
|
|
7
4
|
}
|
|
8
5
|
export declare function CategoryCard({ href, image, isSelected, title, }: CategoryCardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { MouseEvent, ReactElement } from 'react';
|
|
2
2
|
import { PressEvent } from 'react-aria-components';
|
|
3
|
-
import {
|
|
3
|
+
import type { ImageSource } from 'shared/types/image';
|
|
4
4
|
import type { ProductPrice as ProductPriceType } from 'shared/types/price';
|
|
5
5
|
export interface ProductCardProps {
|
|
6
6
|
addToCartButton: ReactElement;
|
|
7
7
|
favoriteButton?: ReactElement;
|
|
8
8
|
href: string;
|
|
9
|
-
image:
|
|
9
|
+
image: ImageSource;
|
|
10
10
|
/** @deprecated Use `onPress` instead */
|
|
11
11
|
onClick?: (e: MouseEvent) => void;
|
|
12
12
|
onPress?: (e: PressEvent) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function ConnectedCategoryCarousel(): import("react/jsx-runtime").JSX.Element | null;
|
package/dist/index.d.ts
CHANGED
|
@@ -13,9 +13,9 @@ declare const breakpoints: {
|
|
|
13
13
|
readonly xl: 1024;
|
|
14
14
|
readonly xxl: 1440;
|
|
15
15
|
};
|
|
16
|
-
type Breakpoint$
|
|
17
|
-
interface UseBreakpointReturnType extends Record<Breakpoint$
|
|
18
|
-
current: Breakpoint$
|
|
16
|
+
type Breakpoint$1 = keyof typeof breakpoints;
|
|
17
|
+
interface UseBreakpointReturnType extends Record<Breakpoint$1, boolean> {
|
|
18
|
+
current: Breakpoint$1;
|
|
19
19
|
}
|
|
20
20
|
declare const useBreakpoint: () => UseBreakpointReturnType;
|
|
21
21
|
|
|
@@ -32,17 +32,6 @@ declare const useDisclosure: (initialState?: boolean) => UseDisclosureReturnType
|
|
|
32
32
|
|
|
33
33
|
declare const useScrollLock: (lock: boolean) => void;
|
|
34
34
|
|
|
35
|
-
interface Link$1 {
|
|
36
|
-
href: string;
|
|
37
|
-
label: string;
|
|
38
|
-
}
|
|
39
|
-
interface Props$3 {
|
|
40
|
-
links: Link$1[];
|
|
41
|
-
updateLinks: (links: Link$1[]) => void;
|
|
42
|
-
}
|
|
43
|
-
declare function BreadcrumbProvider(props: Props$3): null;
|
|
44
|
-
declare function useBreadcrumb(): Props$3;
|
|
45
|
-
|
|
46
35
|
interface CartLine$1 {
|
|
47
36
|
id: string
|
|
48
37
|
productId: string | null
|
|
@@ -173,7 +162,7 @@ interface BreadcrumbProps {
|
|
|
173
162
|
}
|
|
174
163
|
declare function Breadcrumb({ links }: BreadcrumbProps): react_jsx_runtime.JSX.Element | null;
|
|
175
164
|
|
|
176
|
-
declare function ConnectedBreadcrumb(): react_jsx_runtime.JSX.Element;
|
|
165
|
+
declare function ConnectedBreadcrumb(): react_jsx_runtime.JSX.Element | null;
|
|
177
166
|
|
|
178
167
|
interface ButtonProps {
|
|
179
168
|
_pseudo?: 'none' | 'focus' | 'hover' | 'active';
|
|
@@ -232,25 +221,25 @@ interface Props {
|
|
|
232
221
|
}
|
|
233
222
|
declare const ConnectedAddToCartButton: ({ productId }: Props) => react_jsx_runtime.JSX.Element;
|
|
234
223
|
|
|
235
|
-
|
|
224
|
+
type Breakpoint = 'lg' | 'md' | 'sm'
|
|
225
|
+
|
|
226
|
+
type Sizes = Record<Breakpoint, number>
|
|
227
|
+
|
|
228
|
+
interface Source {
|
|
236
229
|
url: string
|
|
237
230
|
width: number
|
|
238
231
|
}
|
|
239
232
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
type Sizes$1 = Record<Breakpoint$1, number>
|
|
243
|
-
|
|
244
|
-
interface ImageProps$1 {
|
|
233
|
+
interface ImageSource {
|
|
245
234
|
alt: string
|
|
246
235
|
className?: string
|
|
247
236
|
fallbackSrc?: string
|
|
248
237
|
fit?: 'contain' | 'cover'
|
|
249
238
|
height?: number
|
|
250
239
|
loading?: 'lazy' | 'eager'
|
|
251
|
-
sizes?: Sizes
|
|
240
|
+
sizes?: Sizes
|
|
252
241
|
src: string
|
|
253
|
-
srcSet?: Source
|
|
242
|
+
srcSet?: Source[]
|
|
254
243
|
title: string
|
|
255
244
|
width?: number
|
|
256
245
|
}
|
|
@@ -265,7 +254,7 @@ interface ProductCardProps {
|
|
|
265
254
|
addToCartButton: ReactElement;
|
|
266
255
|
favoriteButton?: ReactElement;
|
|
267
256
|
href: string;
|
|
268
|
-
image:
|
|
257
|
+
image: ImageSource;
|
|
269
258
|
/** @deprecated Use `onPress` instead */
|
|
270
259
|
onClick?: (e: MouseEvent) => void;
|
|
271
260
|
onPress?: (e: PressEvent) => void;
|
|
@@ -276,13 +265,16 @@ interface ProductCardProps {
|
|
|
276
265
|
}
|
|
277
266
|
declare function ProductCard({ addToCartButton: AddToCartButton, favoriteButton: FavoriteButton, href, image: { alt, fit, src, title: imageTitle }, onClick, onPress, price, sku, tag, title, }: ProductCardProps): react_jsx_runtime.JSX.Element;
|
|
278
267
|
|
|
279
|
-
interface
|
|
268
|
+
interface Category {
|
|
280
269
|
href: string
|
|
281
|
-
image:
|
|
282
|
-
isSelected?: boolean
|
|
270
|
+
image: ImageSource
|
|
283
271
|
title: string
|
|
284
272
|
}
|
|
285
273
|
|
|
274
|
+
interface CategoryCardProps extends Category {
|
|
275
|
+
isSelected?: boolean
|
|
276
|
+
}
|
|
277
|
+
|
|
286
278
|
interface CategoryCarouselProps {
|
|
287
279
|
categories: CategoryCardProps[];
|
|
288
280
|
}
|
|
@@ -488,25 +480,7 @@ interface ProductOverviewGridProps {
|
|
|
488
480
|
}
|
|
489
481
|
declare function ProductOverviewGrid({ children }: ProductOverviewGridProps): react_jsx_runtime.JSX.Element;
|
|
490
482
|
|
|
491
|
-
|
|
492
|
-
url: string;
|
|
493
|
-
width: number;
|
|
494
|
-
}
|
|
495
|
-
type Breakpoint = 'lg' | 'md' | 'sm';
|
|
496
|
-
type Sizes = Record<Breakpoint, number>;
|
|
497
|
-
interface ImageProps {
|
|
498
|
-
alt: string;
|
|
499
|
-
className?: string;
|
|
500
|
-
fallbackSrc?: string;
|
|
501
|
-
fit?: 'contain' | 'cover';
|
|
502
|
-
height?: number;
|
|
503
|
-
loading?: 'lazy' | 'eager';
|
|
504
|
-
sizes?: Sizes;
|
|
505
|
-
src: string;
|
|
506
|
-
srcSet?: Source[];
|
|
507
|
-
title: string;
|
|
508
|
-
width?: number;
|
|
509
|
-
}
|
|
483
|
+
type ImageProps = ImageSource;
|
|
510
484
|
declare function Image({ alt, className, fallbackSrc, fit, height, loading, sizes: sizesProp, src, srcSet: srcSetProp, title, width, }: ImageProps): react_jsx_runtime.JSX.Element;
|
|
511
485
|
|
|
512
486
|
declare function PageLayout({ children, className, }: {
|
|
@@ -531,10 +505,11 @@ interface Filters {
|
|
|
531
505
|
};
|
|
532
506
|
}
|
|
533
507
|
type ProductListingPageProps = {
|
|
534
|
-
|
|
535
|
-
|
|
508
|
+
bffUrl: string;
|
|
509
|
+
pageUrl: string;
|
|
510
|
+
searchClient?: SearchClient;
|
|
536
511
|
};
|
|
537
|
-
declare function ProductListingPage({
|
|
512
|
+
declare function ProductListingPage({ bffUrl, pageUrl, searchClient, }: ProductListingPageProps): react_jsx_runtime.JSX.Element;
|
|
538
513
|
|
|
539
514
|
interface SidebarProps {
|
|
540
515
|
children: React.ReactNode;
|
|
@@ -588,7 +563,7 @@ interface AlgoliaContextType {
|
|
|
588
563
|
toggleOnline: VoidFunction;
|
|
589
564
|
}
|
|
590
565
|
interface AlgoliaProviderProps {
|
|
591
|
-
category: string[];
|
|
566
|
+
category: string[] | undefined;
|
|
592
567
|
children: ReactNode;
|
|
593
568
|
offlineSearchClient?: SearchClient;
|
|
594
569
|
online?: boolean;
|
|
@@ -602,4 +577,4 @@ declare function AlgoliaResultsCount(): string | null;
|
|
|
602
577
|
|
|
603
578
|
declare function AlgoliaSortBy(): react_jsx_runtime.JSX.Element | null;
|
|
604
579
|
|
|
605
|
-
export { Accordion, AddToCartButton, AlgoliaCategories, AlgoliaFilterPanel, type AlgoliaFilterPanelProps, AlgoliaFilterSection, AlgoliaMultiSelectFilterSection, AlgoliaPagination, AlgoliaProvider, AlgoliaResultsCount, AlgoliaSortBy, Breadcrumb, type BreadcrumbProps,
|
|
580
|
+
export { Accordion, AddToCartButton, AlgoliaCategories, AlgoliaFilterPanel, type AlgoliaFilterPanelProps, AlgoliaFilterSection, AlgoliaMultiSelectFilterSection, AlgoliaPagination, AlgoliaProvider, AlgoliaResultsCount, AlgoliaSortBy, Breadcrumb, type BreadcrumbProps, Button, type ButtonProps, type Cart, CartFilledIcon, type CartLine, CartOutlinedIcon, CartProvider, CategoryCarousel, type CategoryCarouselProps, Checkbox, type CheckboxProps$1 as CheckboxProps, ColorCheckbox, type ColorCheckboxProps, ConnectedAddToCartButton, ConnectedBreadcrumb, DehashedOutlinedIcon, FavoriteButton, type FavoriteButtonProps, FavoriteFilledIcon, FavoriteOutlinedIcon, FavoriteProvider, type FilterOption, type Filters, FormattedMessage, type FormattedMessageFunction, type FormattedMessageProps, GlobalStateProvider, GlobalStateProviderContext, HashedOutlinedIcon, IconButton, type IconButtonProps, Image, IntlProvider, LeftArrowFilledIcon, LinkButton, type LinkButtonProps, MultiSelect, type MultiSelectProps, NumberField, type NumberFieldSize, Page, PageLayout, type PageProps, type Product, ProductCard, type ProductCardProps, ProductListingPage, type ProductListingPageProps, ProductOverviewGrid, type ProductOverviewGridProps, ProductPrice, type ProductPriceProps, ProductSku, type ProductSkuProps, type RefinementListItem, RightArrowFilledIcon, Select, type SelectProps, ShowAll, type ShowAllProps, Sidebar, type SidebarProps, SidebarProvider, TextAlignedArrowIcon, TextField, createSonicSearchClient, useAlgolia, useBreakpoint, useCart, useDebouncedCallback, useDisclosure, useFavorite, useFormattedMessage, useGlobalState, useProductCartLine, useScrollLock };
|
package/dist/index.js
CHANGED
|
@@ -2,9 +2,10 @@ import React, { useState, useEffect, useRef, useCallback, createContext, useCont
|
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import { Breadcrumbs, Breadcrumb as Breadcrumb$1, Link, Button as Button$1, FieldError as FieldError$1, useContextProps, InputContext, Input as Input$1, Label as Label$1, NumberField as NumberField$1, Checkbox as Checkbox$1, Select as Select$1, SelectValue, Popover, ListBox, Section, Header, ListBoxItem, TextAreaContext, TextArea as TextArea$1, TextField as TextField$1 } from 'react-aria-components';
|
|
4
4
|
import clsx from 'clsx';
|
|
5
|
-
import { useCurrentRefinements, useClearRefinements, useRefinementList, useHits, useDynamicWidgets, usePagination,
|
|
5
|
+
import { useCurrentRefinements, useClearRefinements, useRefinementList, useHits, useDynamicWidgets, usePagination, InstantSearch, Configure, useSortBy } from 'react-instantsearch';
|
|
6
6
|
import { history } from 'instantsearch.js/es/lib/routers/index.js';
|
|
7
7
|
import { simple } from 'instantsearch.js/es/lib/stateMappings/index.js';
|
|
8
|
+
import { useQuery } from '@tanstack/react-query';
|
|
8
9
|
|
|
9
10
|
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
|
10
11
|
const breakpoints$1 = {
|
|
@@ -183,21 +184,6 @@ function useGlobalState(key, initialState) {
|
|
|
183
184
|
return [rerenderState, (value) => (state.value = value)];
|
|
184
185
|
}
|
|
185
186
|
|
|
186
|
-
function BreadcrumbProvider(props) {
|
|
187
|
-
const [, updateState] = useGlobalState('breadcrumb', props);
|
|
188
|
-
useEffect(() => {
|
|
189
|
-
updateState(props);
|
|
190
|
-
}, [props, updateState]);
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
function useBreadcrumb() {
|
|
194
|
-
const [state] = useGlobalState('breadcrumb');
|
|
195
|
-
if (!state) {
|
|
196
|
-
throw new Error('useBreadcrumb must be used together with the BreadcrumbProvider');
|
|
197
|
-
}
|
|
198
|
-
return state;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
187
|
function CartProvider(props) {
|
|
202
188
|
const [, updateState] = useGlobalState('cart', props);
|
|
203
189
|
useEffect(() => {
|
|
@@ -271,9 +257,27 @@ function BreadcrumbLong({ links }) {
|
|
|
271
257
|
return (jsxs(Breadcrumbs, { className: styles$x.breadcrumbs, children: [jsx(Breadcrumb$1, { className: styles$x.breadcrumb, children: jsx(Link, { className: styles$x.link, href: homeLink.href, children: jsx(HomeFilledIcon, { className: clsx(styles$x['home-icon'], styles$x.icon) }) }) }), linksWithoutFirst.map((link, index) => (jsx(Breadcrumb$1, { className: styles$x.breadcrumb, children: jsxs(Link, { className: styles$x.link, href: link.href, isDisabled: index === linksWithoutFirst.length - 1, children: [jsx(ChevronLeftFilledIcon, { className: clsx(styles$x['previous-icon'], styles$x.icon) }), link.label] }) }, index)))] }));
|
|
272
258
|
}
|
|
273
259
|
|
|
260
|
+
const ProductListingPageContext = createContext({
|
|
261
|
+
data: undefined,
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
function ProductListingPageProvider({ children, data, error, isError, isLoading, }) {
|
|
265
|
+
return (jsx(ProductListingPageContext.Provider, { value: { data, error, isError, isLoading }, children: children }));
|
|
266
|
+
}
|
|
267
|
+
function useProductListingPageProvider() {
|
|
268
|
+
return useContext(ProductListingPageContext);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function useBreadcrumb() {
|
|
272
|
+
const { data, isLoading } = useProductListingPageProvider();
|
|
273
|
+
return { breadCrumb: data?.breadCrumb, isLoading };
|
|
274
|
+
}
|
|
275
|
+
|
|
274
276
|
function ConnectedBreadcrumb() {
|
|
275
|
-
const {
|
|
276
|
-
|
|
277
|
+
const { breadCrumb } = useBreadcrumb();
|
|
278
|
+
if (!breadCrumb)
|
|
279
|
+
return null;
|
|
280
|
+
return jsx(Breadcrumb, { links: breadCrumb });
|
|
277
281
|
}
|
|
278
282
|
|
|
279
283
|
function TextAlignedArrowIcon(props) {
|
|
@@ -6000,7 +6004,7 @@ function ChevronRightFilledIcon(props) {
|
|
|
6000
6004
|
var styles$3 = {"pagination":"pagination-module-k4OgY","page-number-container":"pagination-module-oq89A"};
|
|
6001
6005
|
|
|
6002
6006
|
function Pagination({ currentPage, onChange, totalPages, }) {
|
|
6003
|
-
return (jsxs("div", { className: styles$3.pagination, children: [jsx(IconButton, { isDisabled: currentPage === 1, onPress: () => onChange(currentPage - 1), children: jsx(ChevronLeftFilledIcon, {}) }), jsxs("div", { className: styles$3['page-number-container'], children: [jsx(NumberField, { autoGrow: true, label: "current-page", maxValue: totalPages, minValue: 1, onChange: onChange, value: currentPage }), jsx(FormattedMessage, { id: "of" }), jsx("div", { children: totalPages })] }), jsx(IconButton, { isDisabled: currentPage >= totalPages, onPress: () => onChange(currentPage + 1), children: jsx(ChevronRightFilledIcon, {}) })] }));
|
|
6007
|
+
return (jsxs("div", { className: styles$3.pagination, children: [jsx(IconButton, { color: "secondary", isDisabled: currentPage === 1, onPress: () => onChange(currentPage - 1), children: jsx(ChevronLeftFilledIcon, {}) }), jsxs("div", { className: styles$3['page-number-container'], children: [jsx(NumberField, { autoGrow: true, label: "current-page", maxValue: totalPages, minValue: 1, onChange: onChange, value: currentPage }), jsx(FormattedMessage, { id: "of" }), jsx("div", { children: totalPages })] }), jsx(IconButton, { color: "secondary", isDisabled: currentPage >= totalPages, onPress: () => onChange(currentPage + 1), children: jsx(ChevronRightFilledIcon, {}) })] }));
|
|
6004
6008
|
}
|
|
6005
6009
|
|
|
6006
6010
|
function AlgoliaPagination({ onChange }) {
|
|
@@ -6012,6 +6016,102 @@ function AlgoliaPagination({ onChange }) {
|
|
|
6012
6016
|
return (jsx(Pagination, { currentPage: currentRefinement + 1, onChange: pageNumber => handlePageChange(pageNumber), totalPages: nbPages }));
|
|
6013
6017
|
}
|
|
6014
6018
|
|
|
6019
|
+
const queryStringRouting = {
|
|
6020
|
+
router: history({
|
|
6021
|
+
cleanUrlOnDispose: true,
|
|
6022
|
+
createURL({ location, qsModule: qs, routeState }) {
|
|
6023
|
+
const indexNames = Object.keys(routeState);
|
|
6024
|
+
if (indexNames.length === 0)
|
|
6025
|
+
return location.href;
|
|
6026
|
+
if (indexNames.length !== 1)
|
|
6027
|
+
throw new Error('Only one index is supported');
|
|
6028
|
+
const queryString = qs.parse(location.search.slice(1), {
|
|
6029
|
+
allowDots: true,
|
|
6030
|
+
duplicates: 'combine',
|
|
6031
|
+
});
|
|
6032
|
+
const state = routeState[indexNames[0]];
|
|
6033
|
+
queryString.filters = state.refinementList;
|
|
6034
|
+
queryString.sortBy = state.sortBy;
|
|
6035
|
+
const newQueryString = qs.stringify(queryString, {
|
|
6036
|
+
addQueryPrefix: true,
|
|
6037
|
+
allowDots: true,
|
|
6038
|
+
arrayFormat: 'repeat',
|
|
6039
|
+
});
|
|
6040
|
+
return `${location.href.split('?')[0]}${newQueryString}`;
|
|
6041
|
+
},
|
|
6042
|
+
parseURL({ location, qsModule: qs }) {
|
|
6043
|
+
const queryString = qs.parse(location.search.slice(1), {
|
|
6044
|
+
allowDots: true,
|
|
6045
|
+
duplicates: 'combine',
|
|
6046
|
+
});
|
|
6047
|
+
const refinementList = Object.keys(queryString.filters || {}).reduce((refinementList, filter) => {
|
|
6048
|
+
refinementList[filter] = [].concat(queryString.filters?.[filter]);
|
|
6049
|
+
return refinementList;
|
|
6050
|
+
}, {});
|
|
6051
|
+
const uiState = {
|
|
6052
|
+
dev_sonic_products_en: {
|
|
6053
|
+
refinementList,
|
|
6054
|
+
sortBy: queryString.sortBy?.toString(),
|
|
6055
|
+
},
|
|
6056
|
+
};
|
|
6057
|
+
return uiState;
|
|
6058
|
+
},
|
|
6059
|
+
windowTitle({ category, query }) {
|
|
6060
|
+
const queryTitle = query ? `Results for "${query}"` : 'Search';
|
|
6061
|
+
if (category) {
|
|
6062
|
+
return `${category} – ${queryTitle}`;
|
|
6063
|
+
}
|
|
6064
|
+
return queryTitle;
|
|
6065
|
+
},
|
|
6066
|
+
}),
|
|
6067
|
+
stateMapping: simple(),
|
|
6068
|
+
};
|
|
6069
|
+
|
|
6070
|
+
const AlgoliaContext = createContext({
|
|
6071
|
+
online: false,
|
|
6072
|
+
setOnline: () => { },
|
|
6073
|
+
toggleOnline: () => { },
|
|
6074
|
+
});
|
|
6075
|
+
function AlgoliaProvider({ category, children, offlineSearchClient, online: _online = true, routing = queryStringRouting, searchClient, }) {
|
|
6076
|
+
const [online, setOnline] = useState(_online);
|
|
6077
|
+
if (!category) {
|
|
6078
|
+
// TODO: Implement loading page
|
|
6079
|
+
return jsx("h1", { children: "Loading..." });
|
|
6080
|
+
}
|
|
6081
|
+
return (jsx(AlgoliaContext.Provider, { value: {
|
|
6082
|
+
online,
|
|
6083
|
+
setOnline,
|
|
6084
|
+
toggleOnline: () => setOnline(online => !online),
|
|
6085
|
+
}, children: jsxs(InstantSearch, { future: {
|
|
6086
|
+
persistHierarchicalRootCount: true,
|
|
6087
|
+
preserveSharedStateOnUnmount: true,
|
|
6088
|
+
}, indexName: "dev_sonic_products_en", routing: routing, searchClient: online ? searchClient : offlineSearchClient || searchClient, children: [jsx(Configure, { analytics: false, filters: category.length
|
|
6089
|
+
? `categoryPages: '${category.join(' > ')}'`
|
|
6090
|
+
: undefined, hitsPerPage: 9, maxValuesPerFacet: 100, ruleContexts: ['storefront'] }), children] }) }));
|
|
6091
|
+
}
|
|
6092
|
+
function useAlgolia() {
|
|
6093
|
+
return useContext(AlgoliaContext);
|
|
6094
|
+
}
|
|
6095
|
+
|
|
6096
|
+
const offlineSearchClient = {
|
|
6097
|
+
search(_queries, _requestOptions) {
|
|
6098
|
+
return fetch('data/algolia.json').then(response => response.json());
|
|
6099
|
+
},
|
|
6100
|
+
async searchForFacetValues(_queries, _requestOptions) {
|
|
6101
|
+
return [];
|
|
6102
|
+
},
|
|
6103
|
+
};
|
|
6104
|
+
|
|
6105
|
+
const createSonicSearchClient = (url) => ({
|
|
6106
|
+
async search(requests) {
|
|
6107
|
+
return fetch(url, {
|
|
6108
|
+
body: JSON.stringify({ requests }),
|
|
6109
|
+
headers: { 'Content-Type': 'application/json' },
|
|
6110
|
+
method: 'post',
|
|
6111
|
+
}).then(res => res.json());
|
|
6112
|
+
},
|
|
6113
|
+
});
|
|
6114
|
+
|
|
6015
6115
|
function AlgoliaSortBy() {
|
|
6016
6116
|
const { currentRefinement, options: algoliaOptions, refine, } = useSortBy({
|
|
6017
6117
|
items: [
|
|
@@ -6032,15 +6132,68 @@ function ConnectedProductCart({ productId, ...props }) {
|
|
|
6032
6132
|
return (jsx(ProductCard, { ...props, addToCartButton: jsx(ConnectedAddToCartButton, { productId: productId }) }));
|
|
6033
6133
|
}
|
|
6034
6134
|
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6135
|
+
function useSubcatagories() {
|
|
6136
|
+
const { data, isLoading } = useProductListingPageProvider();
|
|
6137
|
+
return { isLoading, subcategories: data?.subcategories };
|
|
6138
|
+
}
|
|
6139
|
+
|
|
6140
|
+
function ConnectedCategoryCarousel() {
|
|
6141
|
+
const { isLoading, subcategories } = useSubcatagories();
|
|
6142
|
+
if (isLoading || !subcategories)
|
|
6143
|
+
return null;
|
|
6144
|
+
return jsx(CategoryCarousel, { categories: subcategories });
|
|
6145
|
+
}
|
|
6146
|
+
|
|
6147
|
+
class ResponseError extends Error {
|
|
6148
|
+
constructor(response) {
|
|
6149
|
+
super(response.statusText);
|
|
6150
|
+
Object.defineProperty(this, "response", {
|
|
6151
|
+
enumerable: true,
|
|
6152
|
+
configurable: true,
|
|
6153
|
+
writable: true,
|
|
6154
|
+
value: void 0
|
|
6155
|
+
});
|
|
6156
|
+
Object.defineProperty(this, "status", {
|
|
6157
|
+
enumerable: true,
|
|
6158
|
+
configurable: true,
|
|
6159
|
+
writable: true,
|
|
6160
|
+
value: void 0
|
|
6161
|
+
});
|
|
6162
|
+
Object.defineProperty(this, "statusText", {
|
|
6163
|
+
enumerable: true,
|
|
6164
|
+
configurable: true,
|
|
6165
|
+
writable: true,
|
|
6166
|
+
value: void 0
|
|
6167
|
+
});
|
|
6168
|
+
Object.defineProperty(this, "type", {
|
|
6169
|
+
enumerable: true,
|
|
6170
|
+
configurable: true,
|
|
6171
|
+
writable: true,
|
|
6172
|
+
value: void 0
|
|
6173
|
+
});
|
|
6174
|
+
Object.defineProperty(this, "url", {
|
|
6175
|
+
enumerable: true,
|
|
6176
|
+
configurable: true,
|
|
6177
|
+
writable: true,
|
|
6178
|
+
value: void 0
|
|
6179
|
+
});
|
|
6180
|
+
this.message = response.statusText;
|
|
6181
|
+
this.name = 'ResponseError';
|
|
6182
|
+
this.response = response;
|
|
6183
|
+
this.status = response.status;
|
|
6184
|
+
this.statusText = response.statusText;
|
|
6185
|
+
this.type = response.type;
|
|
6186
|
+
this.url = response.url;
|
|
6187
|
+
}
|
|
6188
|
+
}
|
|
6189
|
+
function isResponseError(error) {
|
|
6190
|
+
return error instanceof ResponseError;
|
|
6191
|
+
}
|
|
6192
|
+
|
|
6193
|
+
const scrollToTop = (scrollOptions) => {
|
|
6041
6194
|
window.scrollTo({
|
|
6042
6195
|
behavior: 'smooth',
|
|
6043
|
-
top:
|
|
6196
|
+
top: 0,
|
|
6044
6197
|
});
|
|
6045
6198
|
};
|
|
6046
6199
|
|
|
@@ -6077,52 +6230,97 @@ const ToggleSidebarButton = () => {
|
|
|
6077
6230
|
return (jsx(Button, { color: "secondary", icon: jsx(FilterOutlinedIcon, {}), onPress: toggle, size: "sm", variant: "outline", children: isOpen ? (jsx(FormattedMessage, { id: "Hide filters" })) : (jsx(FormattedMessage, { id: "Show filters" })) }));
|
|
6078
6231
|
};
|
|
6079
6232
|
|
|
6233
|
+
function useFetchProductListingPageData(bffUrl, pageUrl) {
|
|
6234
|
+
return useQuery({
|
|
6235
|
+
queryFn: async () => {
|
|
6236
|
+
const response = await fetch(`${bffUrl}/api/v1/plp/?pageUrl=${pageUrl}`);
|
|
6237
|
+
if (!response.ok)
|
|
6238
|
+
throw new ResponseError(response);
|
|
6239
|
+
return (await response.json());
|
|
6240
|
+
},
|
|
6241
|
+
queryKey: [bffUrl, 'product-listing-page-data', pageUrl],
|
|
6242
|
+
retry: false,
|
|
6243
|
+
select: (data) => {
|
|
6244
|
+
return {
|
|
6245
|
+
banner: data.banner,
|
|
6246
|
+
breadCrumb: data.breadCrumb.map(breadCrumb => ({
|
|
6247
|
+
href: breadCrumb.url,
|
|
6248
|
+
label: breadCrumb.text,
|
|
6249
|
+
})),
|
|
6250
|
+
category: {
|
|
6251
|
+
href: data.categories.path,
|
|
6252
|
+
image: {
|
|
6253
|
+
alt: data.categories.imageAltText,
|
|
6254
|
+
src: data.categories.smallImagePath,
|
|
6255
|
+
title: data.categories.shortDescription,
|
|
6256
|
+
},
|
|
6257
|
+
title: data.categories.shortDescription,
|
|
6258
|
+
},
|
|
6259
|
+
subcategories: data?.categories?.subCategories?.map(subcategory => ({
|
|
6260
|
+
href: subcategory.path,
|
|
6261
|
+
image: {
|
|
6262
|
+
alt: subcategory.imageAltText,
|
|
6263
|
+
src: subcategory.smallImagePath,
|
|
6264
|
+
title: subcategory.shortDescription,
|
|
6265
|
+
},
|
|
6266
|
+
title: subcategory.shortDescription,
|
|
6267
|
+
})),
|
|
6268
|
+
};
|
|
6269
|
+
},
|
|
6270
|
+
});
|
|
6271
|
+
}
|
|
6272
|
+
|
|
6080
6273
|
var styles$1 = {"product-listing":"product-listing-page-module-dmIHF","header":"product-listing-page-module-Oz76Z","action-bar":"product-listing-page-module-XxGrr","sort":"product-listing-page-module-aQzHr","count":"product-listing-page-module-zx79v","categories":"product-listing-page-module-R4aOl","product-grid-container":"product-listing-page-module-ICkKg","product-grid":"product-listing-page-module-LHE7z","pagination":"product-listing-page-module-xsRaj"};
|
|
6081
6274
|
|
|
6082
|
-
|
|
6083
|
-
href: '#',
|
|
6084
|
-
image: {
|
|
6085
|
-
alt: 'Category 1',
|
|
6086
|
-
fit: 'contain',
|
|
6087
|
-
height: 96,
|
|
6088
|
-
src: '/images/pliers-md.png',
|
|
6089
|
-
title: 'Category 1',
|
|
6090
|
-
width: 96,
|
|
6091
|
-
},
|
|
6092
|
-
isSelected: false,
|
|
6093
|
-
title: 'Schroevendraaier',
|
|
6094
|
-
}));
|
|
6095
|
-
function ProductListingPage({ category, isLoading = false, }) {
|
|
6275
|
+
function ProductListingPage({ bffUrl, pageUrl, searchClient, }) {
|
|
6096
6276
|
const { toggle } = useSidebar();
|
|
6277
|
+
const { data, error, isError, isFetching } = useFetchProductListingPageData(bffUrl, pageUrl);
|
|
6278
|
+
if (isError) {
|
|
6279
|
+
if (!isResponseError(error))
|
|
6280
|
+
throw error;
|
|
6281
|
+
// TODO: Implement error page (404, 500, etc.)
|
|
6282
|
+
return (jsxs("h1", { children: [error.status, " - ", error.statusText] }));
|
|
6283
|
+
}
|
|
6284
|
+
if (!data || isFetching) {
|
|
6285
|
+
// TODO: Implement loading page
|
|
6286
|
+
return jsx("h1", { children: "Loading..." });
|
|
6287
|
+
}
|
|
6288
|
+
const category = data?.breadCrumb.slice(1).map(breadCrumb => breadCrumb.label);
|
|
6289
|
+
return (jsx(ProductListingPageProvider, { data: data, error: error, isError: isError, isLoading: isFetching, children: jsx(AlgoliaProvider, { category: category, offlineSearchClient: offlineSearchClient, searchClient: searchClient ||
|
|
6290
|
+
createSonicSearchClient(`${bffUrl}${bffUrl.endsWith('/') ? '' : '/'}search`), children: jsxs(Page, { className: styles$1['product-listing'], title: category.slice().pop(), children: [jsx("section", { className: styles$1.categories, children: jsx(ConnectedCategoryCarousel, {}) }), jsxs("section", { className: styles$1['action-bar'], children: [jsx("div", { children: jsx(ToggleSidebarButton, {}) }), jsx("span", { className: styles$1.count, children: jsx(AlgoliaResultsCount, {}) }), jsx("div", { className: styles$1.sort, children: jsx(AlgoliaSortBy, {}) })] }), jsx("section", { children: jsxs("div", { className: styles$1['product-grid-container'], children: [jsx(Sidebar, { children: jsx(AlgoliaFilterPanel, { onShowProducts: toggle }) }), jsxs("div", { className: styles$1['product-grid'], children: [jsx(ProductOverview, {}), jsx("div", { className: styles$1.pagination, children: jsx(AlgoliaPagination, { onChange: () => scrollToTop() }) })] })] }) })] }) }) }));
|
|
6291
|
+
}
|
|
6292
|
+
function ProductOverview() {
|
|
6097
6293
|
const { hits: productHits } = useHits();
|
|
6098
6294
|
const baseUrl = location.href.split('?')[0];
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6295
|
+
return (jsx(ProductOverviewGrid, { children: productHits.map(productHit => (jsx(ConnectedProductCart, { href: `${baseUrl}${baseUrl.endsWith('/') ? '' : '/'}${productHit.id}-${productHit.name.replace(/ /g, '-')}`, image: {
|
|
6296
|
+
alt: productHit.name,
|
|
6297
|
+
fit: 'contain',
|
|
6298
|
+
sizes: { lg: 288, md: 204, sm: 122 },
|
|
6299
|
+
src: productHit.images?.find(image => image.quality === 'large')
|
|
6300
|
+
?.url || '',
|
|
6301
|
+
srcSet: [
|
|
6302
|
+
{
|
|
6303
|
+
url: productHit.images?.find(image => image.quality === 'small')
|
|
6304
|
+
?.url || '',
|
|
6305
|
+
width: 122,
|
|
6306
|
+
},
|
|
6307
|
+
{
|
|
6308
|
+
url: productHit.images?.find(image => image.quality === 'medium')
|
|
6309
|
+
?.url || '',
|
|
6310
|
+
width: 204,
|
|
6311
|
+
},
|
|
6312
|
+
{
|
|
6313
|
+
url: productHit.images?.find(image => image.quality === 'large')
|
|
6314
|
+
?.url || '',
|
|
6315
|
+
width: 288,
|
|
6316
|
+
},
|
|
6317
|
+
],
|
|
6318
|
+
title: productHit.name,
|
|
6319
|
+
}, price: {
|
|
6320
|
+
current: productHit.discountedPrice,
|
|
6321
|
+
includeVat: false,
|
|
6322
|
+
original: productHit.price,
|
|
6323
|
+
}, productId: productHit.id, sku: productHit.ean, tag: "new", title: productHit.name }, productHit.objectID))) }));
|
|
6126
6324
|
}
|
|
6127
6325
|
|
|
6128
6326
|
var styles = {"sidebar-container":"sidebar-provider-module-rjeCL","transition":"sidebar-provider-module-C0cKR","sidebar-background":"sidebar-provider-module-VRgS9","is-open":"sidebar-provider-module-lxq2-"};
|
|
@@ -6164,87 +6362,4 @@ function SidebarProvider({ children }) {
|
|
|
6164
6362
|
}), onClick: closeTransitions }), children] }) }));
|
|
6165
6363
|
}
|
|
6166
6364
|
|
|
6167
|
-
|
|
6168
|
-
async search(requests) {
|
|
6169
|
-
return fetch(url, {
|
|
6170
|
-
body: JSON.stringify({ requests }),
|
|
6171
|
-
headers: { 'Content-Type': 'application/json' },
|
|
6172
|
-
method: 'post',
|
|
6173
|
-
}).then(res => res.json());
|
|
6174
|
-
},
|
|
6175
|
-
});
|
|
6176
|
-
|
|
6177
|
-
const queryStringRouting = {
|
|
6178
|
-
router: history({
|
|
6179
|
-
cleanUrlOnDispose: true,
|
|
6180
|
-
createURL({ location, qsModule: qs, routeState }) {
|
|
6181
|
-
const indexNames = Object.keys(routeState);
|
|
6182
|
-
if (indexNames.length === 0)
|
|
6183
|
-
return location.href;
|
|
6184
|
-
if (indexNames.length !== 1)
|
|
6185
|
-
throw new Error('Only one index is supported');
|
|
6186
|
-
const queryString = qs.parse(location.search.slice(1), {
|
|
6187
|
-
allowDots: true,
|
|
6188
|
-
duplicates: 'combine',
|
|
6189
|
-
});
|
|
6190
|
-
const state = routeState[indexNames[0]];
|
|
6191
|
-
queryString.filters = state.refinementList;
|
|
6192
|
-
queryString.sortBy = state.sortBy;
|
|
6193
|
-
const newQueryString = qs.stringify(queryString, {
|
|
6194
|
-
addQueryPrefix: true,
|
|
6195
|
-
allowDots: true,
|
|
6196
|
-
arrayFormat: 'repeat',
|
|
6197
|
-
});
|
|
6198
|
-
return `${location.href.split('?')[0]}${newQueryString}`;
|
|
6199
|
-
},
|
|
6200
|
-
parseURL({ location, qsModule: qs }) {
|
|
6201
|
-
const queryString = qs.parse(location.search.slice(1), {
|
|
6202
|
-
allowDots: true,
|
|
6203
|
-
duplicates: 'combine',
|
|
6204
|
-
});
|
|
6205
|
-
const refinementList = Object.keys(queryString.filters || {}).reduce((refinementList, filter) => {
|
|
6206
|
-
refinementList[filter] = [].concat(queryString.filters?.[filter]);
|
|
6207
|
-
return refinementList;
|
|
6208
|
-
}, {});
|
|
6209
|
-
const uiState = {
|
|
6210
|
-
dev_sonic_products_en: {
|
|
6211
|
-
refinementList,
|
|
6212
|
-
sortBy: queryString.sortBy?.toString(),
|
|
6213
|
-
},
|
|
6214
|
-
};
|
|
6215
|
-
return uiState;
|
|
6216
|
-
},
|
|
6217
|
-
windowTitle({ category, query }) {
|
|
6218
|
-
const queryTitle = query ? `Results for "${query}"` : 'Search';
|
|
6219
|
-
if (category) {
|
|
6220
|
-
return `${category} – ${queryTitle}`;
|
|
6221
|
-
}
|
|
6222
|
-
return queryTitle;
|
|
6223
|
-
},
|
|
6224
|
-
}),
|
|
6225
|
-
stateMapping: simple(),
|
|
6226
|
-
};
|
|
6227
|
-
|
|
6228
|
-
const AlgoliaContext = createContext({
|
|
6229
|
-
online: false,
|
|
6230
|
-
setOnline: () => { },
|
|
6231
|
-
toggleOnline: () => { },
|
|
6232
|
-
});
|
|
6233
|
-
function AlgoliaProvider({ category, children, offlineSearchClient, online: _online = true, routing = queryStringRouting, searchClient, }) {
|
|
6234
|
-
const [online, setOnline] = useState(_online);
|
|
6235
|
-
return (jsx(AlgoliaContext.Provider, { value: {
|
|
6236
|
-
online,
|
|
6237
|
-
setOnline,
|
|
6238
|
-
toggleOnline: () => setOnline(online => !online),
|
|
6239
|
-
}, children: jsxs(InstantSearch, { future: {
|
|
6240
|
-
persistHierarchicalRootCount: true,
|
|
6241
|
-
preserveSharedStateOnUnmount: true,
|
|
6242
|
-
}, indexName: "dev_sonic_products_en", routing: routing, searchClient: online ? searchClient : offlineSearchClient || searchClient, children: [jsx(Configure, { analytics: false, filters: category.length
|
|
6243
|
-
? `categoryPages: '${category.join(' > ')}'`
|
|
6244
|
-
: undefined, hitsPerPage: 9, maxValuesPerFacet: 100, ruleContexts: ['storefront'] }), children] }) }));
|
|
6245
|
-
}
|
|
6246
|
-
function useAlgolia() {
|
|
6247
|
-
return useContext(AlgoliaContext);
|
|
6248
|
-
}
|
|
6249
|
-
|
|
6250
|
-
export { Accordion, AddToCartButton, AlgoliaCategories, AlgoliaFilterPanel, AlgoliaFilterSection, AlgoliaMultiSelectFilterSection, AlgoliaPagination, AlgoliaProvider, AlgoliaResultsCount, AlgoliaSortBy, Breadcrumb, BreadcrumbProvider, Button, CartFilledIcon, CartOutlinedIcon, CartProvider, CategoryCarousel, Checkbox, ColorCheckbox, ConnectedAddToCartButton, ConnectedBreadcrumb, DehashedOutlinedIcon, FavoriteButton, FavoriteFilledIcon, FavoriteOutlinedIcon, FavoriteProvider, FormattedMessage, GlobalStateProvider, GlobalStateProviderContext, HashedOutlinedIcon, IconButton, Image, IntlProvider, LeftArrowFilledIcon, LinkButton, MultiSelect, NumberField, Page, PageLayout, ProductCard, ProductListingPage, ProductOverviewGrid, ProductPrice, ProductSku, RightArrowFilledIcon, Select, ShowAll, Sidebar, SidebarProvider, TextAlignedArrowIcon, TextField, createSonicSearchClient, useAlgolia, useBreadcrumb, useBreakpoint, useCart, useDebouncedCallback, useDisclosure, useFavorite, useFormattedMessage, useGlobalState, useProductCartLine, useScrollLock };
|
|
6365
|
+
export { Accordion, AddToCartButton, AlgoliaCategories, AlgoliaFilterPanel, AlgoliaFilterSection, AlgoliaMultiSelectFilterSection, AlgoliaPagination, AlgoliaProvider, AlgoliaResultsCount, AlgoliaSortBy, Breadcrumb, Button, CartFilledIcon, CartOutlinedIcon, CartProvider, CategoryCarousel, Checkbox, ColorCheckbox, ConnectedAddToCartButton, ConnectedBreadcrumb, DehashedOutlinedIcon, FavoriteButton, FavoriteFilledIcon, FavoriteOutlinedIcon, FavoriteProvider, FormattedMessage, GlobalStateProvider, GlobalStateProviderContext, HashedOutlinedIcon, IconButton, Image, IntlProvider, LeftArrowFilledIcon, LinkButton, MultiSelect, NumberField, Page, PageLayout, ProductCard, ProductListingPage, ProductOverviewGrid, ProductPrice, ProductSku, RightArrowFilledIcon, Select, ShowAll, Sidebar, SidebarProvider, TextAlignedArrowIcon, TextField, createSonicSearchClient, useAlgolia, useBreakpoint, useCart, useDebouncedCallback, useDisclosure, useFavorite, useFormattedMessage, useGlobalState, useProductCartLine, useScrollLock };
|
|
@@ -1,21 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
width: number;
|
|
4
|
-
}
|
|
5
|
-
type Breakpoint = 'lg' | 'md' | 'sm';
|
|
6
|
-
type Sizes = Record<Breakpoint, number>;
|
|
7
|
-
export interface ImageProps {
|
|
8
|
-
alt: string;
|
|
9
|
-
className?: string;
|
|
10
|
-
fallbackSrc?: string;
|
|
11
|
-
fit?: 'contain' | 'cover';
|
|
12
|
-
height?: number;
|
|
13
|
-
loading?: 'lazy' | 'eager';
|
|
14
|
-
sizes?: Sizes;
|
|
15
|
-
src: string;
|
|
16
|
-
srcSet?: Source[];
|
|
17
|
-
title: string;
|
|
18
|
-
width?: number;
|
|
19
|
-
}
|
|
1
|
+
import type { ImageSource } from 'shared/types/image';
|
|
2
|
+
type ImageProps = ImageSource;
|
|
20
3
|
export declare function Image({ alt, className, fallbackSrc, fit, height, loading, sizes: sizesProp, src, srcSet: srcSetProp, title, width, }: ImageProps): import("react/jsx-runtime").JSX.Element;
|
|
21
4
|
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Category } from 'shared/types/category';
|
|
2
|
+
export interface BannerItem {
|
|
3
|
+
alt: string;
|
|
4
|
+
srcSet: {
|
|
5
|
+
src: string;
|
|
6
|
+
width: number;
|
|
7
|
+
}[];
|
|
8
|
+
}
|
|
9
|
+
export interface Link {
|
|
10
|
+
href: string;
|
|
11
|
+
label: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ProductListingPageData {
|
|
14
|
+
banner: {
|
|
15
|
+
top: BannerItem[];
|
|
16
|
+
};
|
|
17
|
+
breadCrumb: Link[];
|
|
18
|
+
category: Category;
|
|
19
|
+
subcategories: Category[] | undefined;
|
|
20
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { ProductListingPageData } from 'pages/product-listing-page/product-listing-page-data-types';
|
|
3
|
+
export interface ProductListingPageContextType {
|
|
4
|
+
data: ProductListingPageData | undefined;
|
|
5
|
+
error?: Error | null;
|
|
6
|
+
isError?: boolean;
|
|
7
|
+
isLoading?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare const ProductListingPageContext: React.Context<ProductListingPageContextType>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { ProductListingPageContextType } from './product-listing-page-context';
|
|
3
|
+
interface ProductListingPageProviderProps extends ProductListingPageContextType {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
}
|
|
6
|
+
export declare function ProductListingPageProvider({ children, data, error, isError, isLoading, }: ProductListingPageProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare function useProductListingPageProvider(): ProductListingPageContextType;
|
|
8
|
+
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SearchClient } from 'algoliasearch/lite';
|
|
1
2
|
export interface Filters {
|
|
2
3
|
color: {
|
|
3
4
|
options: {
|
|
@@ -8,7 +9,8 @@ export interface Filters {
|
|
|
8
9
|
};
|
|
9
10
|
}
|
|
10
11
|
export type ProductListingPageProps = {
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
bffUrl: string;
|
|
13
|
+
pageUrl: string;
|
|
14
|
+
searchClient?: SearchClient;
|
|
13
15
|
};
|
|
14
|
-
export declare function ProductListingPage({
|
|
16
|
+
export declare function ProductListingPage({ bffUrl, pageUrl, searchClient, }: ProductListingPageProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
import { ComponentProps } from 'react';
|
|
2
2
|
import { StoryObj } from '@storybook/react';
|
|
3
3
|
import { ProductListingPage } from './product-listing-page';
|
|
4
|
+
type StoryProps = Omit<ComponentProps<typeof ProductListingPage>, 'searchClient'> & {
|
|
5
|
+
bff: boolean;
|
|
6
|
+
online: boolean;
|
|
7
|
+
};
|
|
4
8
|
declare const meta: {
|
|
5
9
|
args: {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
isLoading: false;
|
|
10
|
+
bff: true;
|
|
11
|
+
bffUrl: string;
|
|
9
12
|
online: false;
|
|
13
|
+
pageUrl: string;
|
|
10
14
|
};
|
|
11
|
-
component: typeof ProductListingPage;
|
|
12
15
|
parameters: {
|
|
13
16
|
layout: string;
|
|
14
17
|
};
|
|
15
18
|
title: string;
|
|
16
19
|
};
|
|
17
20
|
export default meta;
|
|
18
|
-
type StoryProps = ComponentProps<typeof ProductListingPage> & {
|
|
19
|
-
BFF: boolean;
|
|
20
|
-
online: boolean;
|
|
21
|
-
};
|
|
22
21
|
type Story = StoryObj<StoryProps>;
|
|
23
22
|
export declare const Default: Story;
|
|
24
|
-
export declare const Loading: Story;
|
|
25
|
-
export declare const WithActiveFilters: Story;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface ProductHit {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
alternativeNumber: string;
|
|
4
|
+
categories: string[];
|
|
5
|
+
categoryPageId: string[];
|
|
6
|
+
consumerPrice: number;
|
|
7
|
+
discountedPrice: number;
|
|
8
|
+
drawerQuantity: string;
|
|
9
|
+
ean: string;
|
|
10
|
+
height: number;
|
|
11
|
+
hierarchicalCategories: {
|
|
12
|
+
lvl0: string;
|
|
13
|
+
lvl1: string;
|
|
14
|
+
};
|
|
15
|
+
id: string;
|
|
16
|
+
images: {
|
|
17
|
+
quality: string;
|
|
18
|
+
url: string;
|
|
19
|
+
}[];
|
|
20
|
+
labels: string[];
|
|
21
|
+
length: number;
|
|
22
|
+
listPrice: number;
|
|
23
|
+
moreInformation: string;
|
|
24
|
+
name: string;
|
|
25
|
+
price: number;
|
|
26
|
+
relatedProducts: string;
|
|
27
|
+
restrictionGroups: string[];
|
|
28
|
+
salePrice: number;
|
|
29
|
+
slug: string;
|
|
30
|
+
storefrontId: string;
|
|
31
|
+
storefrontSlug: string;
|
|
32
|
+
weight: number;
|
|
33
|
+
width: number;
|
|
34
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface Category {
|
|
2
|
+
activateOn: string;
|
|
3
|
+
deactivateOn: string | null;
|
|
4
|
+
htmlContent: string;
|
|
5
|
+
id: string;
|
|
6
|
+
imageAltText: string;
|
|
7
|
+
isDynamic: boolean;
|
|
8
|
+
isFeatured: boolean;
|
|
9
|
+
largeImagePath: string;
|
|
10
|
+
metaDescription: string;
|
|
11
|
+
metaKeywords: string;
|
|
12
|
+
mobileBannerImageUrl: string;
|
|
13
|
+
mobilePrimaryText: string;
|
|
14
|
+
mobileSecondaryText: string;
|
|
15
|
+
mobileTextColor: string;
|
|
16
|
+
mobileTextJustification: string;
|
|
17
|
+
name: string;
|
|
18
|
+
path: string;
|
|
19
|
+
properties: {
|
|
20
|
+
pimId: string | null;
|
|
21
|
+
};
|
|
22
|
+
shortDescription: string;
|
|
23
|
+
smallImagePath: string;
|
|
24
|
+
sortOrder: number;
|
|
25
|
+
subCategories: Category[] | null;
|
|
26
|
+
uri: null;
|
|
27
|
+
urlSegment: string;
|
|
28
|
+
}
|
|
29
|
+
export interface BannerItem {
|
|
30
|
+
alt: string;
|
|
31
|
+
srcSet: {
|
|
32
|
+
src: string;
|
|
33
|
+
width: number;
|
|
34
|
+
}[];
|
|
35
|
+
}
|
|
36
|
+
export interface Banner {
|
|
37
|
+
top: BannerItem[];
|
|
38
|
+
}
|
|
39
|
+
export interface BreadCrumb {
|
|
40
|
+
categoryId: string;
|
|
41
|
+
text: string;
|
|
42
|
+
url: string;
|
|
43
|
+
}
|
|
44
|
+
export interface ProductListingPageDataResponse {
|
|
45
|
+
banner: Banner;
|
|
46
|
+
breadCrumb: BreadCrumb[];
|
|
47
|
+
categories: Category;
|
|
48
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { StoryObj } from '@storybook/react';
|
|
2
|
+
interface StoryProps {
|
|
3
|
+
bffUrl: string;
|
|
4
|
+
pageUrl: string;
|
|
5
|
+
}
|
|
6
|
+
declare function UseFetchProductListingPageDataStory(args: StoryProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
declare const meta: {
|
|
8
|
+
args: {
|
|
9
|
+
bffUrl: string;
|
|
10
|
+
pageUrl: string;
|
|
11
|
+
};
|
|
12
|
+
component: typeof UseFetchProductListingPageDataStory;
|
|
13
|
+
parameters: {
|
|
14
|
+
layout: string;
|
|
15
|
+
};
|
|
16
|
+
title: string;
|
|
17
|
+
};
|
|
18
|
+
export default meta;
|
|
19
|
+
type Story = StoryObj<typeof meta>;
|
|
20
|
+
export declare const Default: Story;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare class ResponseError extends Error {
|
|
2
|
+
response: Response;
|
|
3
|
+
status: number;
|
|
4
|
+
statusText: string;
|
|
5
|
+
type: ResponseType;
|
|
6
|
+
url: string;
|
|
7
|
+
constructor(response: Response);
|
|
8
|
+
}
|
|
9
|
+
export declare function isResponseError(error: unknown): error is ResponseError;
|
|
@@ -3,5 +3,6 @@ interface ScrollOptions {
|
|
|
3
3
|
behavior?: ScrollBehavior;
|
|
4
4
|
scrollPadding?: number;
|
|
5
5
|
}
|
|
6
|
+
export declare const scrollToTop: (scrollOptions?: ScrollToOptions) => void;
|
|
6
7
|
export declare const useScrollTo: (ref: RefObject<HTMLElement>, scrollOptions?: ScrollOptions) => () => void;
|
|
7
8
|
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type Breakpoint = 'lg' | 'md' | 'sm';
|
|
2
|
+
type Sizes = Record<Breakpoint, number>;
|
|
3
|
+
interface Source {
|
|
4
|
+
url: string;
|
|
5
|
+
width: number;
|
|
6
|
+
}
|
|
7
|
+
export interface ImageSource {
|
|
8
|
+
alt: string;
|
|
9
|
+
className?: string;
|
|
10
|
+
fallbackSrc?: string;
|
|
11
|
+
fit?: 'contain' | 'cover';
|
|
12
|
+
height?: number;
|
|
13
|
+
loading?: 'lazy' | 'eager';
|
|
14
|
+
sizes?: Sizes;
|
|
15
|
+
src: string;
|
|
16
|
+
srcSet?: Source[];
|
|
17
|
+
title: string;
|
|
18
|
+
width?: number;
|
|
19
|
+
}
|
|
20
|
+
export {};
|
package/dist/styles.css
CHANGED
|
@@ -933,6 +933,7 @@
|
|
|
933
933
|
display: grid;
|
|
934
934
|
max-width: 136px;
|
|
935
935
|
cursor: pointer;
|
|
936
|
+
padding-inline: 10px;
|
|
936
937
|
place-items: center;
|
|
937
938
|
}
|
|
938
939
|
|
|
@@ -990,6 +991,11 @@
|
|
|
990
991
|
}
|
|
991
992
|
}
|
|
992
993
|
|
|
994
|
+
@media (width >= 1024px) {.category-card-module-4NUjH {
|
|
995
|
+
padding-inline: 0
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
|
|
993
999
|
@media (width >= 1440px) {.category-card-module-4NUjH {
|
|
994
1000
|
max-width: 144px
|
|
995
1001
|
}
|
|
@@ -1362,7 +1368,12 @@
|
|
|
1362
1368
|
.carousel-module-ealh- .carousel-module-k7Z4S.carousel-module-5SGYn .carousel-module-Hi-0z {
|
|
1363
1369
|
top: 50%;
|
|
1364
1370
|
}
|
|
1365
|
-
@media (width <
|
|
1371
|
+
@media (width < 1024px) {
|
|
1372
|
+
.carousel-module-ealh- {
|
|
1373
|
+
width: calc(100% + 20px);
|
|
1374
|
+
margin-left: -10px
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1366
1377
|
.carousel-module-ealh- .carousel-module-Hi-0z {
|
|
1367
1378
|
display: none;
|
|
1368
1379
|
}
|
|
@@ -2197,6 +2208,7 @@
|
|
|
2197
2208
|
align-items: center;
|
|
2198
2209
|
justify-content: space-between;
|
|
2199
2210
|
margin-bottom: var(--space-24);
|
|
2211
|
+
row-gap: var(--space-8);
|
|
2200
2212
|
}
|
|
2201
2213
|
.product-listing-page-module-dmIHF .product-listing-page-module-XxGrr .product-listing-page-module-aQzHr {
|
|
2202
2214
|
display: flex;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sonic-equipment/ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.28",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"engines": {
|
|
@@ -45,27 +45,27 @@
|
|
|
45
45
|
"react-instantsearch-core": "^7"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@chromatic-com/storybook": "^1.
|
|
48
|
+
"@chromatic-com/storybook": "^1.5.0",
|
|
49
49
|
"@csstools/postcss-global-data": "^2.1.1",
|
|
50
50
|
"@rollup/plugin-alias": "^5.1.0",
|
|
51
|
-
"@rollup/plugin-commonjs": "^
|
|
51
|
+
"@rollup/plugin-commonjs": "^26.0.1",
|
|
52
52
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
53
53
|
"@rollup/plugin-typescript": "^11.1.6",
|
|
54
|
-
"@storybook/addon-docs": "^8.1.
|
|
55
|
-
"@storybook/addon-essentials": "^8.1.
|
|
56
|
-
"@storybook/addon-interactions": "^8.1.
|
|
57
|
-
"@storybook/addon-links": "^8.1.
|
|
58
|
-
"@storybook/addon-viewport": "^8.1.
|
|
59
|
-
"@storybook/blocks": "^8.1.
|
|
60
|
-
"@storybook/preview-api": "^8.1.
|
|
61
|
-
"@storybook/react": "^8.1.
|
|
62
|
-
"@storybook/react-vite": "^8.1.
|
|
63
|
-
"@storybook/test": "^8.1.
|
|
64
|
-
"@types/react": "^18.3.
|
|
54
|
+
"@storybook/addon-docs": "^8.1.9",
|
|
55
|
+
"@storybook/addon-essentials": "^8.1.9",
|
|
56
|
+
"@storybook/addon-interactions": "^8.1.9",
|
|
57
|
+
"@storybook/addon-links": "^8.1.9",
|
|
58
|
+
"@storybook/addon-viewport": "^8.1.9",
|
|
59
|
+
"@storybook/blocks": "^8.1.9",
|
|
60
|
+
"@storybook/preview-api": "^8.1.9",
|
|
61
|
+
"@storybook/react": "^8.1.9",
|
|
62
|
+
"@storybook/react-vite": "^8.1.9",
|
|
63
|
+
"@storybook/test": "^8.1.9",
|
|
64
|
+
"@types/react": "^18.3.3",
|
|
65
65
|
"@types/react-dom": "^18.3.0",
|
|
66
|
-
"@typescript-eslint/eslint-plugin": "^7.
|
|
67
|
-
"@typescript-eslint/parser": "^7.
|
|
68
|
-
"@vitejs/plugin-react": "^4.3.
|
|
66
|
+
"@typescript-eslint/eslint-plugin": "^7.13.0",
|
|
67
|
+
"@typescript-eslint/parser": "^7.13.0",
|
|
68
|
+
"@vitejs/plugin-react": "^4.3.1",
|
|
69
69
|
"autoprefixer": "^10.4.19",
|
|
70
70
|
"concurrently": "^8.2.2",
|
|
71
71
|
"eslint": "^8.57.0",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"eslint-plugin-mdx": "^3.1.5",
|
|
76
76
|
"eslint-plugin-no-relative-import-paths": "^1.5.4",
|
|
77
77
|
"eslint-plugin-prettier": "^5.1.3",
|
|
78
|
-
"eslint-plugin-react": "^7.34.
|
|
78
|
+
"eslint-plugin-react": "^7.34.2",
|
|
79
79
|
"eslint-plugin-react-hooks": "^4.6.2",
|
|
80
80
|
"eslint-plugin-simple-import-sort": "^12.1.0",
|
|
81
81
|
"eslint-plugin-sort-destructure-keys": "^2.0.0",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"eslint-plugin-unused-imports": "^3.2.0",
|
|
86
86
|
"http-server": "^14.1.1",
|
|
87
87
|
"husky": "^9.0.11",
|
|
88
|
-
"instantsearch.js": "^4.
|
|
88
|
+
"instantsearch.js": "^4.71.1",
|
|
89
89
|
"postcss": "^8.4.38",
|
|
90
90
|
"postcss-custom-media": "^10.0.6",
|
|
91
91
|
"postcss-import": "^16.1.0",
|
|
@@ -98,13 +98,13 @@
|
|
|
98
98
|
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
99
99
|
"rollup-plugin-postcss": "^4.0.2",
|
|
100
100
|
"rollup-plugin-ts": "^3.4.5",
|
|
101
|
-
"storybook": "^8.1.
|
|
102
|
-
"stylelint": "^16.
|
|
101
|
+
"storybook": "^8.1.9",
|
|
102
|
+
"stylelint": "^16.6.1",
|
|
103
103
|
"stylelint-config-css-modules": "^4.4.0",
|
|
104
104
|
"stylelint-config-idiomatic-order": "^10.0.0",
|
|
105
105
|
"stylelint-config-standard": "^36.0.0",
|
|
106
106
|
"typescript": "^5.4.5",
|
|
107
|
-
"vite": "^5.
|
|
107
|
+
"vite": "^5.3.1",
|
|
108
108
|
"vite-tsconfig-paths": "^4.3.2"
|
|
109
109
|
},
|
|
110
110
|
"dependencies": {
|
|
@@ -113,12 +113,13 @@
|
|
|
113
113
|
"@algolia/autocomplete-plugin-recent-searches": "^1.17.2",
|
|
114
114
|
"@algolia/autocomplete-preset-algolia": "^1.17.2",
|
|
115
115
|
"@algolia/client-search": "^4.23.3",
|
|
116
|
+
"@tanstack/react-query": "^5.45.0",
|
|
116
117
|
"algoliasearch": "^4.23.3",
|
|
117
118
|
"clsx": "^2.1.1",
|
|
118
|
-
"instantsearch.js": "^4.
|
|
119
|
+
"instantsearch.js": "^4.71.1",
|
|
119
120
|
"react-aria-components": "^1.2.1",
|
|
120
|
-
"react-instantsearch": "^7.
|
|
121
|
-
"swiper": "^11.1.
|
|
121
|
+
"react-instantsearch": "^7.11.1",
|
|
122
|
+
"swiper": "^11.1.4"
|
|
122
123
|
},
|
|
123
124
|
"publishConfig": {
|
|
124
125
|
"access": "public"
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export interface Link {
|
|
2
|
-
href: string;
|
|
3
|
-
label: string;
|
|
4
|
-
}
|
|
5
|
-
interface Props {
|
|
6
|
-
links: Link[];
|
|
7
|
-
updateLinks: (links: Link[]) => void;
|
|
8
|
-
}
|
|
9
|
-
export declare function BreadcrumbProvider(props: Props): null;
|
|
10
|
-
export declare function useBreadcrumb(): Props;
|
|
11
|
-
export {};
|