@riosst100/pwa-marketplace 1.3.1 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/componentOverrideMapping.js +5 -0
- package/src/components/ShopByCategory/index.js +2 -0
- package/src/components/ShopByCategory/shopByCategory.js +69 -0
- package/src/components/ShopByCategory/shopByCategory.module.css +58 -0
- package/src/components/ShopByCategory/shopByCategory.shimmer.js +24 -0
- package/src/components/SubCategory/subCategory.js +31 -0
- package/src/overwrites/peregrine/lib/talons/Breadcrumbs/useBreadcrumbs.js +100 -0
- package/src/overwrites/peregrine/lib/talons/MegaMenu/megaMenu.gql.js +70 -0
- package/src/overwrites/peregrine/lib/talons/MegaMenu/useMegaMenu.js +199 -0
- package/src/overwrites/peregrine/lib/talons/RootComponents/Category/categoryContent.gql.js +70 -0
- package/src/overwrites/peregrine/lib/talons/RootComponents/Category/useCategoryContent.js +141 -0
- package/src/overwrites/venia-ui/lib/RootComponents/Category/categoryContent.js +222 -0
- package/src/overwrites/venia-ui/lib/components/Adapter/adapter.js +5 -2
- package/src/overwrites/venia-ui/lib/components/FilterSidebar/filterSidebar.js +157 -0
- package/src/overwrites/venia-ui/lib/components/MegaMenu/megaMenu.js +2 -1
- package/src/overwrites/venia-ui/lib/components/MegaMenu/megaMenuItem.js +1 -0
- package/src/overwrites/venia-ui/lib/components/MegaMenu/shopByColumn.js +75 -0
- package/src/overwrites/venia-ui/lib/components/MegaMenu/shopByColumn.module.css +28 -0
- package/src/overwrites/venia-ui/lib/components/MegaMenu/submenu.js +31 -0
- package/src/overwrites/venia-ui/lib/components/MegaMenu/submenuColumn.js +1 -0
- package/src/overwrites/venia-ui/lib/components/SearchBar/searchField.js +1 -1
- package/src/talons/MegaMenu/megaMenu.gql.js +70 -0
- package/src/talons/ShopByCategory/index.js +1 -0
- package/src/talons/ShopByCategory/shopByCategory.gql.js +38 -0
- package/src/talons/ShopByCategory/useShopByCategory.js +69 -0
- package/src/talons/SubCategory/subCategory.gql.js +15 -0
- package/src/talons/SubCategory/useSubCategory.js +52 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useLazyQuery, useQuery } from '@apollo/client';
|
|
3
|
+
|
|
4
|
+
import mergeOperations from '@magento/peregrine/lib/util/shallowMerge';
|
|
5
|
+
import { useEventingContext } from '@magento/peregrine/lib/context/eventing';
|
|
6
|
+
|
|
7
|
+
import DEFAULT_OPERATIONS from './categoryContent.gql';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Returns props necessary to render the categoryContent component.
|
|
11
|
+
*
|
|
12
|
+
* @param {object} props.data - The results of a getCategory GraphQL query.
|
|
13
|
+
*
|
|
14
|
+
* @returns {object} result
|
|
15
|
+
* @returns {string} result.categoryDescription - This category's description.
|
|
16
|
+
* @returns {string} result.categoryName - This category's name.
|
|
17
|
+
* @returns {object} result.filters - The filters object.
|
|
18
|
+
* @returns {object} result.items - The items in this category.
|
|
19
|
+
* @returns {number} result.totalPagesFromData - The total amount of pages for the query.
|
|
20
|
+
*/
|
|
21
|
+
export const useCategoryContent = props => {
|
|
22
|
+
const { categoryId, data, pageSize = 6 } = props;
|
|
23
|
+
|
|
24
|
+
const operations = mergeOperations(DEFAULT_OPERATIONS, props.operations);
|
|
25
|
+
|
|
26
|
+
const {
|
|
27
|
+
getCategoryContentQuery,
|
|
28
|
+
getProductFiltersByCategoryQuery,
|
|
29
|
+
getCategoryAvailableSortMethodsQuery
|
|
30
|
+
} = operations;
|
|
31
|
+
|
|
32
|
+
const placeholderItems = Array.from({ length: pageSize }).fill(null);
|
|
33
|
+
|
|
34
|
+
const [getFilters, { data: filterData }] = useLazyQuery(
|
|
35
|
+
getProductFiltersByCategoryQuery,
|
|
36
|
+
{
|
|
37
|
+
fetchPolicy: 'cache-and-network',
|
|
38
|
+
nextFetchPolicy: 'cache-first'
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const [getSortMethods, { data: sortData }] = useLazyQuery(
|
|
43
|
+
getCategoryAvailableSortMethodsQuery,
|
|
44
|
+
{
|
|
45
|
+
fetchPolicy: 'cache-and-network',
|
|
46
|
+
nextFetchPolicy: 'cache-first'
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const { data: categoryData, loading: categoryLoading } = useQuery(
|
|
51
|
+
getCategoryContentQuery,
|
|
52
|
+
{
|
|
53
|
+
fetchPolicy: 'cache-and-network',
|
|
54
|
+
nextFetchPolicy: 'cache-first',
|
|
55
|
+
skip: !categoryId,
|
|
56
|
+
variables: {
|
|
57
|
+
id: categoryId
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
console.log(categoryData)
|
|
63
|
+
|
|
64
|
+
const [, { dispatch }] = useEventingContext();
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (categoryId) {
|
|
68
|
+
getFilters({
|
|
69
|
+
variables: {
|
|
70
|
+
categoryIdFilter: {
|
|
71
|
+
eq: categoryId
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}, [categoryId, getFilters]);
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (categoryId) {
|
|
80
|
+
getSortMethods({
|
|
81
|
+
variables: {
|
|
82
|
+
categoryIdFilter: {
|
|
83
|
+
in: categoryId
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}, [categoryId, getSortMethods]);
|
|
89
|
+
|
|
90
|
+
const filters = filterData ? filterData.products.aggregations : null;
|
|
91
|
+
const items = data ? data.products.items : placeholderItems;
|
|
92
|
+
const children =
|
|
93
|
+
categoryData && categoryData.categories.items.length
|
|
94
|
+
? categoryData.categories.items[0].children
|
|
95
|
+
: null;
|
|
96
|
+
const parent =
|
|
97
|
+
categoryData && categoryData.categories.items.length
|
|
98
|
+
? categoryData.categories.items[0].parent
|
|
99
|
+
: null;
|
|
100
|
+
const totalPagesFromData = data
|
|
101
|
+
? data.products.page_info.total_pages
|
|
102
|
+
: null;
|
|
103
|
+
const totalCount = data ? data.products.total_count : null;
|
|
104
|
+
const categoryName =
|
|
105
|
+
categoryData && categoryData.categories.items.length
|
|
106
|
+
? categoryData.categories.items[0].name
|
|
107
|
+
: null;
|
|
108
|
+
const categoryDescription =
|
|
109
|
+
categoryData && categoryData.categories.items.length
|
|
110
|
+
? categoryData.categories.items[0].description
|
|
111
|
+
: null;
|
|
112
|
+
const availableSortMethods = sortData
|
|
113
|
+
? sortData.products.sort_fields.options
|
|
114
|
+
: null;
|
|
115
|
+
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
if (!categoryLoading && categoryData.categories.items.length > 0) {
|
|
118
|
+
dispatch({
|
|
119
|
+
type: 'CATEGORY_PAGE_VIEW',
|
|
120
|
+
payload: {
|
|
121
|
+
id: categoryData.categories.items[0].uid,
|
|
122
|
+
name: categoryData.categories.items[0].name,
|
|
123
|
+
url_key: categoryData.categories.items[0].url_key,
|
|
124
|
+
url_path: categoryData.categories.items[0].url_path
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}, [categoryData, dispatch, categoryLoading]);
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
availableSortMethods,
|
|
132
|
+
categoryName,
|
|
133
|
+
categoryDescription,
|
|
134
|
+
filters,
|
|
135
|
+
items,
|
|
136
|
+
totalCount,
|
|
137
|
+
totalPagesFromData,
|
|
138
|
+
children,
|
|
139
|
+
parent
|
|
140
|
+
};
|
|
141
|
+
};
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import React, { Fragment, Suspense, useMemo, useRef } from 'react';
|
|
2
|
+
import { FormattedMessage } from 'react-intl';
|
|
3
|
+
import { array, number, shape, string } from 'prop-types';
|
|
4
|
+
|
|
5
|
+
import { useIsInViewport } from '@magento/peregrine/lib/hooks/useIsInViewport';
|
|
6
|
+
import { useCategoryContent } from '@magento/peregrine/lib/talons/RootComponents/Category';
|
|
7
|
+
|
|
8
|
+
import { useStyle } from '@magento/venia-ui/lib/classify';
|
|
9
|
+
import Breadcrumbs from '@magento/venia-ui/lib/components/Breadcrumbs';
|
|
10
|
+
import FilterModalOpenButton, {
|
|
11
|
+
FilterModalOpenButtonShimmer
|
|
12
|
+
} from '@magento/venia-ui/lib/components/FilterModalOpenButton';
|
|
13
|
+
import { FilterSidebarShimmer } from '@magento/venia-ui/lib/components/FilterSidebar';
|
|
14
|
+
import Gallery, { GalleryShimmer } from '@magento/venia-ui/lib/components/Gallery';
|
|
15
|
+
import { StoreTitle } from '@magento/venia-ui/lib/components/Head';
|
|
16
|
+
import Pagination from '@magento/venia-ui/lib/components/Pagination';
|
|
17
|
+
import ProductSort, { ProductSortShimmer } from '@magento/venia-ui/lib/components/ProductSort';
|
|
18
|
+
import RichContent from '@magento/venia-ui/lib/components/RichContent';
|
|
19
|
+
import Shimmer from '@magento/venia-ui/lib/components/Shimmer';
|
|
20
|
+
import SortedByContainer, {
|
|
21
|
+
SortedByContainerShimmer
|
|
22
|
+
} from '@magento/venia-ui/lib/components/SortedByContainer';
|
|
23
|
+
import defaultClasses from '@magento/venia-ui/lib/RootComponents/Category/category.module.css';
|
|
24
|
+
import NoProductsFound from '@magento/venia-ui/lib/RootComponents/Category/NoProductsFound';
|
|
25
|
+
import SubCategory from '@riosst100/pwa-marketplace/src/components/SubCategory/subCategory';
|
|
26
|
+
|
|
27
|
+
const FilterModal = React.lazy(() => import('@magento/venia-ui/lib/components/FilterModal'));
|
|
28
|
+
const FilterSidebar = React.lazy(() =>
|
|
29
|
+
import('@magento/venia-ui/lib/components/FilterSidebar')
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const CategoryContent = props => {
|
|
33
|
+
const {
|
|
34
|
+
categoryId,
|
|
35
|
+
data,
|
|
36
|
+
isLoading,
|
|
37
|
+
pageControl,
|
|
38
|
+
sortProps,
|
|
39
|
+
pageSize
|
|
40
|
+
} = props;
|
|
41
|
+
const [currentSort] = sortProps;
|
|
42
|
+
|
|
43
|
+
const talonProps = useCategoryContent({
|
|
44
|
+
categoryId,
|
|
45
|
+
data,
|
|
46
|
+
pageSize
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const {
|
|
50
|
+
availableSortMethods,
|
|
51
|
+
categoryName,
|
|
52
|
+
categoryDescription,
|
|
53
|
+
filters,
|
|
54
|
+
items,
|
|
55
|
+
totalCount,
|
|
56
|
+
totalPagesFromData,
|
|
57
|
+
children,
|
|
58
|
+
parent
|
|
59
|
+
} = talonProps;
|
|
60
|
+
|
|
61
|
+
const sidebarRef = useRef(null);
|
|
62
|
+
const classes = useStyle(defaultClasses, props.classes);
|
|
63
|
+
const shouldRenderSidebarContent = useIsInViewport({
|
|
64
|
+
elementRef: sidebarRef
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const shouldShowFilterButtons = filters && filters.length;
|
|
68
|
+
const shouldShowFilterShimmer = filters === null;
|
|
69
|
+
|
|
70
|
+
// If there are no products we can hide the sort button.
|
|
71
|
+
const shouldShowSortButtons = totalPagesFromData && availableSortMethods;
|
|
72
|
+
const shouldShowSortShimmer = !totalPagesFromData && isLoading;
|
|
73
|
+
|
|
74
|
+
const maybeFilterButtons = shouldShowFilterButtons ? (
|
|
75
|
+
<FilterModalOpenButton filters={filters} />
|
|
76
|
+
) : shouldShowFilterShimmer ? (
|
|
77
|
+
<FilterModalOpenButtonShimmer />
|
|
78
|
+
) : null;
|
|
79
|
+
|
|
80
|
+
const filtersModal = shouldShowFilterButtons ? (
|
|
81
|
+
<FilterModal filters={filters} />
|
|
82
|
+
) : null;
|
|
83
|
+
|
|
84
|
+
const sidebar = shouldShowFilterButtons ? (
|
|
85
|
+
<FilterSidebar filters={filters} categoryName={categoryName} children={children} parent={parent} />
|
|
86
|
+
) : shouldShowFilterShimmer ? (
|
|
87
|
+
<FilterSidebarShimmer />
|
|
88
|
+
) : null;
|
|
89
|
+
|
|
90
|
+
const maybeSortButton = shouldShowSortButtons ? (
|
|
91
|
+
<ProductSort
|
|
92
|
+
sortProps={sortProps}
|
|
93
|
+
availableSortMethods={availableSortMethods}
|
|
94
|
+
/>
|
|
95
|
+
) : shouldShowSortShimmer ? (
|
|
96
|
+
<ProductSortShimmer />
|
|
97
|
+
) : null;
|
|
98
|
+
|
|
99
|
+
const maybeSortContainer = shouldShowSortButtons ? (
|
|
100
|
+
<SortedByContainer currentSort={currentSort} />
|
|
101
|
+
) : shouldShowSortShimmer ? (
|
|
102
|
+
<SortedByContainerShimmer />
|
|
103
|
+
) : null;
|
|
104
|
+
|
|
105
|
+
const categoryResultsHeading =
|
|
106
|
+
totalCount > 0 ? (
|
|
107
|
+
<FormattedMessage
|
|
108
|
+
id={'categoryContent.resultCount'}
|
|
109
|
+
values={{
|
|
110
|
+
count: totalCount
|
|
111
|
+
}}
|
|
112
|
+
defaultMessage={'{count} Results'}
|
|
113
|
+
/>
|
|
114
|
+
) : isLoading ? (
|
|
115
|
+
<Shimmer width={5} />
|
|
116
|
+
) : null;
|
|
117
|
+
|
|
118
|
+
const categoryDescriptionElement = categoryDescription ? (
|
|
119
|
+
<RichContent html={categoryDescription} />
|
|
120
|
+
) : null;
|
|
121
|
+
|
|
122
|
+
const content = useMemo(() => {
|
|
123
|
+
if (!totalPagesFromData && !isLoading) {
|
|
124
|
+
return <NoProductsFound categoryId={categoryId} />;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const gallery = totalPagesFromData ? (
|
|
128
|
+
<Gallery items={items} />
|
|
129
|
+
) : (
|
|
130
|
+
<GalleryShimmer items={items} />
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const pagination = totalPagesFromData ? (
|
|
134
|
+
<Pagination pageControl={pageControl} />
|
|
135
|
+
) : null;
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<Fragment>
|
|
139
|
+
<section className={classes.gallery}>{gallery}</section>
|
|
140
|
+
<div className={classes.pagination}>{pagination}</div>
|
|
141
|
+
</Fragment>
|
|
142
|
+
);
|
|
143
|
+
}, [
|
|
144
|
+
categoryId,
|
|
145
|
+
classes.gallery,
|
|
146
|
+
classes.pagination,
|
|
147
|
+
isLoading,
|
|
148
|
+
items,
|
|
149
|
+
pageControl,
|
|
150
|
+
totalPagesFromData
|
|
151
|
+
]);
|
|
152
|
+
|
|
153
|
+
const categoryTitle = categoryName ? categoryName : <Shimmer width={5} />;
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<Fragment>
|
|
157
|
+
<Breadcrumbs categoryId={categoryId} />
|
|
158
|
+
<SubCategory children={children} />
|
|
159
|
+
<StoreTitle>{categoryName}</StoreTitle>
|
|
160
|
+
<article className={classes.root} data-cy="CategoryContent-root">
|
|
161
|
+
<div className={classes.categoryHeader}>
|
|
162
|
+
<h1 aria-live="polite" className={classes.title}>
|
|
163
|
+
<div
|
|
164
|
+
className={classes.categoryTitle}
|
|
165
|
+
data-cy="CategoryContent-categoryTitle"
|
|
166
|
+
>
|
|
167
|
+
{categoryTitle}
|
|
168
|
+
</div>
|
|
169
|
+
</h1>
|
|
170
|
+
{categoryDescriptionElement}
|
|
171
|
+
</div>
|
|
172
|
+
<div className={classes.contentWrapper}>
|
|
173
|
+
<div ref={sidebarRef} className={classes.sidebar}>
|
|
174
|
+
<Suspense fallback={<FilterSidebarShimmer />}>
|
|
175
|
+
{shouldRenderSidebarContent ? sidebar : null}
|
|
176
|
+
</Suspense>
|
|
177
|
+
</div>
|
|
178
|
+
<div className={classes.categoryContent}>
|
|
179
|
+
<div className={classes.heading}>
|
|
180
|
+
<div
|
|
181
|
+
data-cy="CategoryContent-categoryInfo"
|
|
182
|
+
className={classes.categoryInfo}
|
|
183
|
+
>
|
|
184
|
+
{categoryResultsHeading}
|
|
185
|
+
</div>
|
|
186
|
+
<div className={classes.headerButtons}>
|
|
187
|
+
{maybeFilterButtons}
|
|
188
|
+
{maybeSortButton}
|
|
189
|
+
</div>
|
|
190
|
+
{maybeSortContainer}
|
|
191
|
+
</div>
|
|
192
|
+
{content}
|
|
193
|
+
<Suspense fallback={null}>{filtersModal}</Suspense>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
</article>
|
|
197
|
+
</Fragment>
|
|
198
|
+
);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
export default CategoryContent;
|
|
202
|
+
|
|
203
|
+
CategoryContent.propTypes = {
|
|
204
|
+
classes: shape({
|
|
205
|
+
gallery: string,
|
|
206
|
+
pagination: string,
|
|
207
|
+
root: string,
|
|
208
|
+
categoryHeader: string,
|
|
209
|
+
title: string,
|
|
210
|
+
categoryTitle: string,
|
|
211
|
+
sidebar: string,
|
|
212
|
+
categoryContent: string,
|
|
213
|
+
heading: string,
|
|
214
|
+
categoryInfo: string,
|
|
215
|
+
headerButtons: string
|
|
216
|
+
}),
|
|
217
|
+
// sortProps contains the following structure:
|
|
218
|
+
// [{sortDirection: string, sortAttribute: string, sortText: string},
|
|
219
|
+
// React.Dispatch<React.SetStateAction<{sortDirection: string, sortAttribute: string, sortText: string}]
|
|
220
|
+
sortProps: array,
|
|
221
|
+
pageSize: number
|
|
222
|
+
};
|
|
@@ -40,7 +40,10 @@ const Adapter = props => {
|
|
|
40
40
|
const match = location && location.pathname.split("/")[1];
|
|
41
41
|
let websiteCodeInUrl = websiteCodes.find((str) => str === match);
|
|
42
42
|
|
|
43
|
-
const { getWebsiteByUserIp } = useWebsiteByIp(websiteCodeInUrl);
|
|
43
|
+
// const { getWebsiteByUserIp } = useWebsiteByIp(websiteCodeInUrl);
|
|
44
|
+
const getWebsiteByUserIp = {
|
|
45
|
+
countryCode: 'SG'
|
|
46
|
+
}
|
|
44
47
|
|
|
45
48
|
useEffect(() => {
|
|
46
49
|
if (websiteCodeInUrl) {
|
|
@@ -88,7 +91,7 @@ const Adapter = props => {
|
|
|
88
91
|
);
|
|
89
92
|
}
|
|
90
93
|
}
|
|
91
|
-
}, [websiteCodeInUrl
|
|
94
|
+
}, [websiteCodeInUrl])
|
|
92
95
|
|
|
93
96
|
// TODO: Replace with app skeleton. See PWA-547.
|
|
94
97
|
if (!initialized) {
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import React, { useMemo, useCallback, useRef } from 'react';
|
|
2
|
+
import { FormattedMessage } from 'react-intl';
|
|
3
|
+
import { array, arrayOf, shape, string, number } from 'prop-types';
|
|
4
|
+
import { useFilterSidebar } from '@magento/peregrine/lib/talons/FilterSidebar';
|
|
5
|
+
|
|
6
|
+
import { useStyle } from '../../classify';
|
|
7
|
+
import LinkButton from '../LinkButton';
|
|
8
|
+
import CurrentFilters from '../FilterModal/CurrentFilters';
|
|
9
|
+
import FilterBlock from '../FilterModal/filterBlock';
|
|
10
|
+
import defaultClasses from './filterSidebar.module.css';
|
|
11
|
+
import ShopByCategory from '@riosst100/pwa-marketplace/src/components/ShopByCategory';
|
|
12
|
+
|
|
13
|
+
const SCROLL_OFFSET = 150;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A view that displays applicable and applied filters.
|
|
17
|
+
*
|
|
18
|
+
* @param {Object} props.filters - filters to display
|
|
19
|
+
*/
|
|
20
|
+
const FilterSidebar = props => {
|
|
21
|
+
const { categoryName, children, parent, filters, filterCountToOpen } = props;
|
|
22
|
+
|
|
23
|
+
const talonProps = useFilterSidebar({ filters });
|
|
24
|
+
const {
|
|
25
|
+
filterApi,
|
|
26
|
+
filterItems,
|
|
27
|
+
filterNames,
|
|
28
|
+
filterFrontendInput,
|
|
29
|
+
filterState,
|
|
30
|
+
handleApply,
|
|
31
|
+
handleReset
|
|
32
|
+
} = talonProps;
|
|
33
|
+
|
|
34
|
+
const filterRef = useRef();
|
|
35
|
+
const classes = useStyle(defaultClasses, props.classes);
|
|
36
|
+
|
|
37
|
+
const handleApplyFilter = useCallback(
|
|
38
|
+
(...args) => {
|
|
39
|
+
const filterElement = filterRef.current;
|
|
40
|
+
if (
|
|
41
|
+
filterElement &&
|
|
42
|
+
typeof filterElement.getBoundingClientRect === 'function'
|
|
43
|
+
) {
|
|
44
|
+
const filterTop = filterElement.getBoundingClientRect().top;
|
|
45
|
+
const windowScrollY =
|
|
46
|
+
window.scrollY + filterTop - SCROLL_OFFSET;
|
|
47
|
+
window.scrollTo(0, windowScrollY);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
handleApply(...args);
|
|
51
|
+
},
|
|
52
|
+
[handleApply, filterRef]
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const filtersList = useMemo(
|
|
56
|
+
() =>
|
|
57
|
+
Array.from(filterItems, ([group, items], iteration) => {
|
|
58
|
+
const blockState = filterState.get(group);
|
|
59
|
+
const groupName = filterNames.get(group);
|
|
60
|
+
const frontendInput = filterFrontendInput.get(group);
|
|
61
|
+
return (
|
|
62
|
+
<FilterBlock
|
|
63
|
+
key={group}
|
|
64
|
+
filterApi={filterApi}
|
|
65
|
+
filterState={blockState}
|
|
66
|
+
filterFrontendInput={frontendInput}
|
|
67
|
+
group={group}
|
|
68
|
+
items={items}
|
|
69
|
+
name={groupName}
|
|
70
|
+
onApply={handleApplyFilter}
|
|
71
|
+
initialOpen={iteration < filterCountToOpen}
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
74
|
+
}),
|
|
75
|
+
[
|
|
76
|
+
filterApi,
|
|
77
|
+
filterItems,
|
|
78
|
+
filterNames,
|
|
79
|
+
filterFrontendInput,
|
|
80
|
+
filterState,
|
|
81
|
+
filterCountToOpen,
|
|
82
|
+
handleApplyFilter
|
|
83
|
+
]
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const clearAll = filterState.size ? (
|
|
87
|
+
<div className={classes.action}>
|
|
88
|
+
<LinkButton
|
|
89
|
+
type="button"
|
|
90
|
+
onClick={handleReset}
|
|
91
|
+
data-cy="FilterSidebar-clearButton"
|
|
92
|
+
>
|
|
93
|
+
<FormattedMessage
|
|
94
|
+
id={'filterModal.action'}
|
|
95
|
+
defaultMessage={'Clear all'}
|
|
96
|
+
/>
|
|
97
|
+
</LinkButton>
|
|
98
|
+
</div>
|
|
99
|
+
) : null;
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<aside
|
|
103
|
+
className={classes.root}
|
|
104
|
+
ref={filterRef}
|
|
105
|
+
data-cy="FilterSidebar-root"
|
|
106
|
+
aria-busy="false"
|
|
107
|
+
>
|
|
108
|
+
<div className={classes.body}>
|
|
109
|
+
<div className={classes.header}>
|
|
110
|
+
<h2
|
|
111
|
+
data-cy="FilterSidebar-headerTitle"
|
|
112
|
+
className={classes.headerTitle}
|
|
113
|
+
>
|
|
114
|
+
<FormattedMessage
|
|
115
|
+
id={'filterModal.headerTitle'}
|
|
116
|
+
defaultMessage={'Filters'}
|
|
117
|
+
/>
|
|
118
|
+
</h2>
|
|
119
|
+
</div>
|
|
120
|
+
<CurrentFilters
|
|
121
|
+
filterApi={filterApi}
|
|
122
|
+
filterNames={filterNames}
|
|
123
|
+
filterState={filterState}
|
|
124
|
+
onRemove={handleApplyFilter}
|
|
125
|
+
/>
|
|
126
|
+
{clearAll}
|
|
127
|
+
<ul className={classes.blocks}>{filtersList}</ul>
|
|
128
|
+
<ul className={classes.blocks}><ShopByCategory categoryName={categoryName} children={children} parent={parent} /></ul>
|
|
129
|
+
</div>
|
|
130
|
+
</aside>
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
FilterSidebar.defaultProps = {
|
|
135
|
+
filterCountToOpen: 3
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
FilterSidebar.propTypes = {
|
|
139
|
+
classes: shape({
|
|
140
|
+
action: string,
|
|
141
|
+
blocks: string,
|
|
142
|
+
body: string,
|
|
143
|
+
header: string,
|
|
144
|
+
headerTitle: string,
|
|
145
|
+
root: string,
|
|
146
|
+
root_open: string
|
|
147
|
+
}),
|
|
148
|
+
filters: arrayOf(
|
|
149
|
+
shape({
|
|
150
|
+
attribute_code: string,
|
|
151
|
+
items: array
|
|
152
|
+
})
|
|
153
|
+
),
|
|
154
|
+
filterCountToOpen: number
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export default FilterSidebar;
|
|
@@ -2,6 +2,7 @@ import React, { useEffect, useRef, useState } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { useIsInViewport } from '@magento/peregrine/lib/hooks/useIsInViewport';
|
|
4
4
|
import { useMegaMenu } from '@magento/peregrine/lib/talons/MegaMenu/useMegaMenu';
|
|
5
|
+
// import { useMegaMenu } from '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/MegaMenu/useMegaMenu';
|
|
5
6
|
import { useStyle } from '@magento/venia-ui/lib/classify';
|
|
6
7
|
|
|
7
8
|
import MegaMenuItem from './megaMenuItem';
|
|
@@ -51,7 +52,7 @@ const MegaMenu = (props) => {
|
|
|
51
52
|
return () => {
|
|
52
53
|
window.removeEventListener('resize', handleResize);
|
|
53
54
|
};
|
|
54
|
-
});
|
|
55
|
+
}, [setMainNavWidth]);
|
|
55
56
|
|
|
56
57
|
const items = megaMenuData.children
|
|
57
58
|
? megaMenuData.children.map(category => {
|
|
@@ -67,6 +67,7 @@ const MegaMenuItem = props => {
|
|
|
67
67
|
isFocused={isFocused}
|
|
68
68
|
subMenuState={subMenuState}
|
|
69
69
|
items={category.children}
|
|
70
|
+
shopByItems={category.shop_by}
|
|
70
71
|
mainNavWidth={mainNavWidth}
|
|
71
72
|
handleCloseSubMenu={handleCloseSubMenu}
|
|
72
73
|
categoryUrlSuffix={categoryUrlSuffix}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Link } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
import resourceUrl from '@magento/peregrine/lib/util/makeUrl';
|
|
5
|
+
|
|
6
|
+
import { useStyle } from '@magento/venia-ui/lib/classify';
|
|
7
|
+
import defaultClasses from './shopByColumn.module.css';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
|
|
10
|
+
const ShopByColumn = props => {
|
|
11
|
+
const classes = useStyle(defaultClasses, props.classes);
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
shopBy
|
|
15
|
+
} = props;
|
|
16
|
+
|
|
17
|
+
// const categoryUrl = resourceUrl(
|
|
18
|
+
// `/${category.url_path}${categoryUrlSuffix || ''}`
|
|
19
|
+
// );
|
|
20
|
+
let items = null;
|
|
21
|
+
|
|
22
|
+
if (shopBy.items.length) {
|
|
23
|
+
const childrenItems = shopBy.items.map((shopByItem, index) => {
|
|
24
|
+
// const { url_path, isActive, name } = shopByItem;
|
|
25
|
+
const { name } = shopByItem;
|
|
26
|
+
// const categoryUrl = resourceUrl(
|
|
27
|
+
// `/${url_path}${categoryUrlSuffix || ''}`
|
|
28
|
+
// );
|
|
29
|
+
|
|
30
|
+
// setting keyboardProps if it is last child of that shopBy
|
|
31
|
+
const keyboardProps =
|
|
32
|
+
index === shopBy.items.length - 1
|
|
33
|
+
? props.keyboardProps
|
|
34
|
+
: {};
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<li key={index} className={classes.submenuChildItem}>
|
|
38
|
+
<Link
|
|
39
|
+
{...keyboardProps}
|
|
40
|
+
// className={isActive ? classes.linkActive : classes.link}
|
|
41
|
+
className={classes.link}
|
|
42
|
+
data-cy="MegaMenu-ShopByColumn-link"
|
|
43
|
+
// to={categoryUrl}
|
|
44
|
+
// onClick={onNavigate}
|
|
45
|
+
>
|
|
46
|
+
{name}
|
|
47
|
+
</Link>
|
|
48
|
+
</li>
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
items = <ul className={classes.submenuChild}>{childrenItems}</ul>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div className={classes.ShopByColumn}>
|
|
57
|
+
{/* <Link
|
|
58
|
+
{...keyboardProps}
|
|
59
|
+
className={classes.link}
|
|
60
|
+
data-cy="MegaMenu-ShopByColumn-link"
|
|
61
|
+
to={categoryUrl}
|
|
62
|
+
onClick={() => {
|
|
63
|
+
handleCloseSubMenu();
|
|
64
|
+
onNavigate();
|
|
65
|
+
}}
|
|
66
|
+
>
|
|
67
|
+
<span className={classes.heading}>{category.name}</span>
|
|
68
|
+
</Link> */}
|
|
69
|
+
<span className={classes.heading}>{shopBy.name}</span>
|
|
70
|
+
{items}
|
|
71
|
+
</div>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export default ShopByColumn;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
.shopByColumn {
|
|
2
|
+
composes: max-w-[235px] from global;
|
|
3
|
+
composes: p-5 from global;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.heading {
|
|
7
|
+
composes: font-semibold from global;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.link {
|
|
11
|
+
composes: whitespace-nowrap from global;
|
|
12
|
+
|
|
13
|
+
composes: focus_underline from global;
|
|
14
|
+
|
|
15
|
+
composes: hover_underline from global;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.linkActive {
|
|
19
|
+
composes: underline from global;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.submenuChild {
|
|
23
|
+
composes: mt-5 from global;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.submenuChildItem {
|
|
27
|
+
composes: mb-3 from global;
|
|
28
|
+
}
|