@riosst100/pwa-marketplace 1.5.4 → 1.5.6
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 +1 -0
- package/src/components/CollectibleGameSets/collectibleGameSets.js +37 -8
- package/src/components/CollectibleGameSets/collectibleGameSets.shimmer.js +50 -0
- package/src/components/CollectibleGameSets/index.js +1 -0
- package/src/components/CustomSortBy/customSortBy.js +198 -0
- package/src/components/CustomSortBy/customSortBy.module.css +68 -0
- package/src/components/CustomSortBy/customSortItem.js +57 -0
- package/src/components/CustomSortBy/customSortItem.module.css +23 -0
- package/src/components/CustomSortBy/index.js +1 -0
- package/src/components/FilterTop/CustomFilters/customFilters.module.css +0 -1
- package/src/components/ProductListTab/productListTab.js +1 -1
- package/src/components/SubCategory/subCategory.js +24 -6
- package/src/overwrites/peregrine/lib/talons/FilterSidebar/useFilterSidebar.js +252 -0
- package/src/overwrites/peregrine/lib/talons/RootComponents/Category/categoryContent.gql.js +3 -0
- package/src/overwrites/peregrine/lib/talons/RootComponents/Category/useCategoryContent.js +34 -5
- package/src/overwrites/venia-ui/lib/RootComponents/Category/categoryContent.js +31 -9
- package/src/overwrites/venia-ui/lib/components/Breadcrumbs/breadcrumbs.js +30 -5
- package/src/overwrites/venia-ui/lib/components/FilterModal/CurrentFilters/currentFilters.js +12 -10
- package/src/overwrites/venia-ui/lib/components/FilterModal/FilterList/filterList.js +1 -1
- package/src/overwrites/venia-ui/lib/components/FilterSidebar/filterSidebar.js +22 -14
- package/src/talons/CollectibleGameSets/collectibleGameSets.gql.js +1 -0
- package/src/talons/CollectibleGameSets/useCollectibleGameSets.js +17 -13
package/package.json
CHANGED
|
@@ -24,6 +24,7 @@ module.exports = componentOverrideMapping = {
|
|
|
24
24
|
[`@magento/peregrine/lib/talons/RootComponents/Category/useCategory.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/RootComponents/Category/useCategory.js',
|
|
25
25
|
[`@magento/peregrine/lib/talons/Breadcrumbs/useBreadcrumbs.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/Breadcrumbs/useBreadcrumbs.js',
|
|
26
26
|
[`@magento/peregrine/lib/talons/FilterModal/useFilterList.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/FilterModal/useFilterList.js',
|
|
27
|
+
[`@magento/peregrine/lib/talons/FilterSidebar/useFilterSidebar.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/FilterSidebar/useFilterSidebar.js',
|
|
27
28
|
[`@magento/venia-ui/lib/components/FilterSidebar/filterSidebar.js`]: '@riosst100/pwa-marketplace/src/overwrites/venia-ui/lib/components/FilterSidebar/filterSidebar.js',
|
|
28
29
|
[`@magento/venia-ui/lib/components/TextInput/index.js`]: '@riosst100/pwa-marketplace/src/overwrites/venia-ui/lib/components/TextInput/index.js',
|
|
29
30
|
[`@magento/venia-ui/lib/components/Pagination/index.js`]: '@riosst100/pwa-marketplace/src/overwrites/venia-ui/lib/components/Pagination/index.js',
|
|
@@ -10,31 +10,33 @@ import defaultClasses from './collectibleGameSets.module.css';
|
|
|
10
10
|
import { useStyle } from '@magento/venia-ui/lib/classify';
|
|
11
11
|
import cn from 'classnames';
|
|
12
12
|
import Divider from '@riosst100/pwa-marketplace/src/components/Divider';
|
|
13
|
+
import { CollectibleGameSetsShimmer } from '@riosst100/pwa-marketplace/src/components/CollectibleGameSets';
|
|
14
|
+
import ProductSort from '@riosst100/pwa-marketplace/src/overwrites/venia-ui/lib/components/ProductSort';
|
|
15
|
+
import CustomSortBy from '@riosst100/pwa-marketplace/src/components/CustomSortBy';
|
|
13
16
|
|
|
14
17
|
const CollectibleGameSets = props => {
|
|
15
18
|
|
|
16
|
-
const {
|
|
19
|
+
const { productType } = props;
|
|
17
20
|
|
|
18
21
|
const [active, setActive] = useState('all');
|
|
19
22
|
|
|
20
23
|
const classes = useStyle(defaultClasses);
|
|
21
24
|
|
|
22
|
-
const talonProps = useCollectibleGameSets({
|
|
25
|
+
const talonProps = useCollectibleGameSets({ productType });
|
|
23
26
|
|
|
24
|
-
const { error, loading, collectibleGameSets, categoryUrlSuffix, categoryUrlKey
|
|
27
|
+
const { error, loading, collectibleGameSets, categoryUrlSuffix, categoryUrlKey } = talonProps;
|
|
25
28
|
|
|
26
29
|
if (loading && !collectibleGameSets)
|
|
27
|
-
return
|
|
28
|
-
// return <SellerShimmer />;
|
|
30
|
+
return <CollectibleGameSetsShimmer />;
|
|
29
31
|
if (error && !collectibleGameSets) return <ErrorView />;
|
|
30
32
|
|
|
31
33
|
if (!collectibleGameSets) {
|
|
32
34
|
return (
|
|
33
35
|
<h1>
|
|
34
36
|
<FormattedMessage
|
|
35
|
-
id={'
|
|
37
|
+
id={'sets.notDataFound'}
|
|
36
38
|
defaultMessage={
|
|
37
|
-
'
|
|
39
|
+
'No data found.'
|
|
38
40
|
}
|
|
39
41
|
/>
|
|
40
42
|
</h1>
|
|
@@ -43,6 +45,8 @@ const CollectibleGameSets = props => {
|
|
|
43
45
|
|
|
44
46
|
const setsLengthArr = [];
|
|
45
47
|
|
|
48
|
+
const groupByYear = [];
|
|
49
|
+
|
|
46
50
|
const setRelases = collectibleGameSets.map((setRelease, index) => {
|
|
47
51
|
const { release_type, sets } = setRelease;
|
|
48
52
|
|
|
@@ -52,7 +56,9 @@ const CollectibleGameSets = props => {
|
|
|
52
56
|
|
|
53
57
|
if (sets.length) {
|
|
54
58
|
sets.map((set, index) => {
|
|
55
|
-
const { set_name, option_id, set_abbreviation } = set;
|
|
59
|
+
const { set_name, option_id, set_abbreviation, release_year } = set;
|
|
60
|
+
|
|
61
|
+
groupByYear[release_year] = set;
|
|
56
62
|
|
|
57
63
|
const categoryUrl = resourceUrl(
|
|
58
64
|
`/games/collectible-game/${categoryUrlKey}${categoryUrlSuffix || ''}?card_set[filter]=${set_name},${option_id}`
|
|
@@ -79,18 +85,41 @@ const CollectibleGameSets = props => {
|
|
|
79
85
|
);
|
|
80
86
|
});
|
|
81
87
|
|
|
88
|
+
console.log(groupByYear)
|
|
89
|
+
|
|
82
90
|
const handleActive = (val) => {
|
|
83
91
|
setActive(val);
|
|
84
92
|
}
|
|
85
93
|
|
|
86
94
|
const alpha = ['#', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
|
|
87
95
|
|
|
96
|
+
const [sortBy, setSortBy] = useState({
|
|
97
|
+
sortText: 'All (A-Z)',
|
|
98
|
+
value: 'all'
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const availableSortBy = [
|
|
102
|
+
{
|
|
103
|
+
'label': 'All (A-Z)',
|
|
104
|
+
'value': 'all'
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
'label': 'Newest',
|
|
108
|
+
'value': 'newest'
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
'label': 'All (Date)',
|
|
112
|
+
'value': 'all-date'
|
|
113
|
+
}
|
|
114
|
+
];
|
|
115
|
+
|
|
88
116
|
return (
|
|
89
117
|
<>
|
|
90
118
|
<h1 className='mx-auto relative block text-xl font-bold text-center pt-10 pb-4'>
|
|
91
119
|
{productType == "sealed-products" ? "Expansion Sets" : "All Sets"}
|
|
92
120
|
</h1>
|
|
93
121
|
<div className='border border-gray-100 px-6'>
|
|
122
|
+
<CustomSortBy sortProps={[sortBy, setSortBy]} availableSortMethods={availableSortBy} />
|
|
94
123
|
{productType != "sealed-products" ? (
|
|
95
124
|
<>
|
|
96
125
|
<section className='single_list-indexing-container relative m-auto py-10'>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { shape, string } from 'prop-types';
|
|
3
|
+
import { useStyle } from '@magento/venia-ui/lib/classify';
|
|
4
|
+
|
|
5
|
+
import Shimmer from '@magento/venia-ui/lib/components/Shimmer';
|
|
6
|
+
import defaultClasses from './collectibleGameSets.module.css';
|
|
7
|
+
import cn from 'classnames';
|
|
8
|
+
import Divider from '@riosst100/pwa-marketplace/src/components/Divider';
|
|
9
|
+
|
|
10
|
+
const CollectibleGameSets = props => {
|
|
11
|
+
const classes = useStyle(defaultClasses, props.classes);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
<h1 className='mx-auto relative block text-xl font-bold text-center pt-10 pb-4'><Shimmer width="25%" height="6vh" /></h1>
|
|
16
|
+
<div className='border border-gray-100 px-6'>
|
|
17
|
+
<center>
|
|
18
|
+
<section className='single_list-indexing-container relative m-auto py-10'>
|
|
19
|
+
<Shimmer width="95%" height="6vh" />
|
|
20
|
+
</section>
|
|
21
|
+
</center>
|
|
22
|
+
<Divider className="mb-5 px-4" />
|
|
23
|
+
<section className='singles-container'>
|
|
24
|
+
<div className={cn('singles-wrapper block -mx-4', classes.singlesWrapper)}>
|
|
25
|
+
<div className='singles_group-wrapper mb-4 px-2 inline-block w-full'>
|
|
26
|
+
<div className='singles_item_group_letter text-xl font-semibold border-b border-gray-100 pb-1 mb-2' ><Shimmer width="95%" height="100vh" /></div>
|
|
27
|
+
</div>
|
|
28
|
+
<div className='singles_group-wrapper mb-4 px-2 inline-block w-full'>
|
|
29
|
+
<div className='singles_item_group_letter text-xl font-semibold border-b border-gray-100 pb-1 mb-2' ><Shimmer width="95%" height="100vh" /></div>
|
|
30
|
+
</div>
|
|
31
|
+
<div className='singles_group-wrapper mb-4 px-2 inline-block w-full'>
|
|
32
|
+
<div className='singles_item_group_letter text-xl font-semibold border-b border-gray-100 pb-1 mb-2' ><Shimmer width="95%" height="100vh" /></div>
|
|
33
|
+
</div>
|
|
34
|
+
<div className='singles_group-wrapper mb-4 px-2 inline-block w-full'>
|
|
35
|
+
<div className='singles_item_group_letter text-xl font-semibold border-b border-gray-100 pb-1 mb-2' ><Shimmer width="95%" height="100vh" /></div>
|
|
36
|
+
</div>
|
|
37
|
+
<div className='singles_group-wrapper mb-4 px-2 inline-block w-full'>
|
|
38
|
+
<div className='singles_item_group_letter text-xl font-semibold border-b border-gray-100 pb-1 mb-2' ><Shimmer width="95%" height="100vh" /></div>
|
|
39
|
+
</div>
|
|
40
|
+
<div className='singles_group-wrapper mb-4 px-2 inline-block w-full'>
|
|
41
|
+
<div className='singles_item_group_letter text-xl font-semibold border-b border-gray-100 pb-1 mb-2' ><Shimmer width="95%" height="100vh" /></div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</section>
|
|
45
|
+
</div>
|
|
46
|
+
</>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default CollectibleGameSets;
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import React, { useMemo, useCallback } from 'react';
|
|
2
|
+
import { ChevronDown as ArrowDown } from 'react-feather';
|
|
3
|
+
import { FormattedMessage, useIntl } from 'react-intl';
|
|
4
|
+
import { array, arrayOf, shape, string } from 'prop-types';
|
|
5
|
+
import { useDropdown } from '@magento/peregrine/lib/hooks/useDropdown';
|
|
6
|
+
|
|
7
|
+
import { useStyle } from '@magento/venia-ui/lib/classify';
|
|
8
|
+
import SortItem from './customSortItem';
|
|
9
|
+
import defaultClasses from './customSortBy.module.css';
|
|
10
|
+
import Button from '@magento/venia-ui/lib/components/Button';
|
|
11
|
+
// import Icon from '@magento/venia-ui/lib/components/Icon';
|
|
12
|
+
import { ArrowUp2 } from 'iconsax-react';
|
|
13
|
+
import cn from 'classnames';
|
|
14
|
+
|
|
15
|
+
const CustomSortBy = props => {
|
|
16
|
+
const classes = useStyle(defaultClasses, props.classes);
|
|
17
|
+
const { availableSortMethods, sortProps } = props;
|
|
18
|
+
const [currentSort, setSort] = sortProps;
|
|
19
|
+
const { elementRef, expanded, setExpanded } = useDropdown();
|
|
20
|
+
const { formatMessage, locale } = useIntl();
|
|
21
|
+
|
|
22
|
+
const orderSortingList = useCallback(
|
|
23
|
+
list => {
|
|
24
|
+
return list.sort((a, b) => {
|
|
25
|
+
return a.text.localeCompare(b.text, locale, {
|
|
26
|
+
sensitivity: 'base'
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
[locale]
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const sortMethodsFromConfig = availableSortMethods
|
|
34
|
+
? availableSortMethods
|
|
35
|
+
.map(method => {
|
|
36
|
+
const { value, label } = method;
|
|
37
|
+
if (value !== 'price' && value !== 'position') {
|
|
38
|
+
return {
|
|
39
|
+
id: `sortItem.${value}`,
|
|
40
|
+
text: label,
|
|
41
|
+
attribute: value,
|
|
42
|
+
sortDirection: 'ASC'
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
.filter(method => !!method)
|
|
47
|
+
: null;
|
|
48
|
+
|
|
49
|
+
// click event for menu items
|
|
50
|
+
const handleItemClick = useCallback(
|
|
51
|
+
sortAttribute => {
|
|
52
|
+
setSort(prevSort => {
|
|
53
|
+
return {
|
|
54
|
+
sortText: sortAttribute.text,
|
|
55
|
+
value: sortAttribute.attribute,
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
setExpanded(false);
|
|
59
|
+
},
|
|
60
|
+
[setExpanded, setSort]
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const sortElements = useMemo(() => {
|
|
64
|
+
// should be not render item in collapsed mode.
|
|
65
|
+
if (!expanded) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const defaultSortMethods = [
|
|
70
|
+
{
|
|
71
|
+
id: 'sortItem.relevance',
|
|
72
|
+
text: formatMessage({
|
|
73
|
+
id: 'sortItem.relevance',
|
|
74
|
+
defaultMessage: 'Best Match'
|
|
75
|
+
}),
|
|
76
|
+
attribute: 'relevance',
|
|
77
|
+
sortDirection: 'DESC'
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: 'sortItem.priceDesc',
|
|
81
|
+
text: formatMessage({
|
|
82
|
+
id: 'sortItem.priceDesc',
|
|
83
|
+
defaultMessage: 'Price: High to Low'
|
|
84
|
+
}),
|
|
85
|
+
attribute: 'price',
|
|
86
|
+
sortDirection: 'DESC'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: 'sortItem.priceAsc',
|
|
90
|
+
text: formatMessage({
|
|
91
|
+
id: 'sortItem.priceAsc',
|
|
92
|
+
defaultMessage: 'Price: Low to High'
|
|
93
|
+
}),
|
|
94
|
+
attribute: 'price',
|
|
95
|
+
sortDirection: 'ASC'
|
|
96
|
+
}
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
const allSortingMethods = sortMethodsFromConfig
|
|
100
|
+
? sortMethodsFromConfig
|
|
101
|
+
: defaultSortMethods;
|
|
102
|
+
|
|
103
|
+
const itemElements = Array.from(allSortingMethods, sortItem => {
|
|
104
|
+
const { attribute, sortDirection } = sortItem;
|
|
105
|
+
const isActive =
|
|
106
|
+
currentSort.value === attribute;
|
|
107
|
+
|
|
108
|
+
const key = `${attribute}--${sortDirection}`;
|
|
109
|
+
return (
|
|
110
|
+
<li key={key} className={classes.menuItem}>
|
|
111
|
+
<SortItem
|
|
112
|
+
sortItem={sortItem}
|
|
113
|
+
active={isActive}
|
|
114
|
+
onClick={handleItemClick}
|
|
115
|
+
/>
|
|
116
|
+
</li>
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<div className={classes.menu}>
|
|
122
|
+
<ul className='flex flex-col gap-2'>{itemElements}</ul>
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}, [
|
|
126
|
+
classes.menu,
|
|
127
|
+
classes.menuItem,
|
|
128
|
+
currentSort.sortAttribute,
|
|
129
|
+
currentSort.sortDirection,
|
|
130
|
+
currentSort.sortFromSearch,
|
|
131
|
+
expanded,
|
|
132
|
+
formatMessage,
|
|
133
|
+
handleItemClick,
|
|
134
|
+
orderSortingList,
|
|
135
|
+
sortMethodsFromConfig
|
|
136
|
+
]);
|
|
137
|
+
|
|
138
|
+
// expand or collapse on click
|
|
139
|
+
const handleSortClick = () => {
|
|
140
|
+
setExpanded(!expanded);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const handleKeypress = e => {
|
|
144
|
+
if (e.code == 'Enter') {
|
|
145
|
+
setExpanded(expanded);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const result = expanded
|
|
149
|
+
? formatMessage({
|
|
150
|
+
id: 'productSort.sortButtonExpanded',
|
|
151
|
+
defaultMessage: 'Sort Button Expanded'
|
|
152
|
+
})
|
|
153
|
+
: formatMessage({
|
|
154
|
+
id: 'productSort.sortButtonCollapsed',
|
|
155
|
+
defaultMessage: 'Sort Button Collapsed'
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<div
|
|
160
|
+
ref={elementRef}
|
|
161
|
+
className={classes.root}
|
|
162
|
+
data-cy="CustomSortBy-root"
|
|
163
|
+
aria-busy="false"
|
|
164
|
+
>
|
|
165
|
+
<Button
|
|
166
|
+
priority={'low'}
|
|
167
|
+
classes={{
|
|
168
|
+
root_lowPriority: classes.sortButton
|
|
169
|
+
}}
|
|
170
|
+
onClick={handleSortClick}
|
|
171
|
+
data-cy="CustomSortBy-sortButton"
|
|
172
|
+
onKeyDown={handleKeypress}
|
|
173
|
+
aria-label={result}
|
|
174
|
+
className='border border-gray-100 border-solid rounded-[5px] p-2.5 flex gap-x-[15px]'
|
|
175
|
+
>
|
|
176
|
+
<span className={classes.mobileText}>
|
|
177
|
+
<FormattedMessage
|
|
178
|
+
id={'productSort.sortButton'}
|
|
179
|
+
defaultMessage={'Sort'}
|
|
180
|
+
/>
|
|
181
|
+
</span>
|
|
182
|
+
<span className={cn(classes.desktopText, 'flex items-center gap-[15px]')}>
|
|
183
|
+
<span className={classes.sortText}>
|
|
184
|
+
<FormattedMessage
|
|
185
|
+
id={'productSort.sortByButton'}
|
|
186
|
+
defaultMessage={'Sort by'}
|
|
187
|
+
/>
|
|
188
|
+
{currentSort.sortText}
|
|
189
|
+
</span>
|
|
190
|
+
<ArrowUp2 size={15} className={cn('text-gray-900 transition-all stroke-[#292D32]', expanded ? 'rotate-0' : 'rotate-180')} />
|
|
191
|
+
</span>
|
|
192
|
+
</Button>
|
|
193
|
+
{sortElements}
|
|
194
|
+
</div>
|
|
195
|
+
);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
export default CustomSortBy;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
.root {
|
|
2
|
+
composes: relative from global;
|
|
3
|
+
composes: ml-2xs from global;
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: row-reverse;
|
|
6
|
+
margin-top: 20px;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.menu {
|
|
10
|
+
composes: absolute from global;
|
|
11
|
+
composes: bg-clip-padding from global;
|
|
12
|
+
composes: bg-white from global;
|
|
13
|
+
composes: border from global;
|
|
14
|
+
composes: border-solid from global;
|
|
15
|
+
composes: border-gray-100 from global;
|
|
16
|
+
composes: list-none from global;
|
|
17
|
+
composes: mb-0 from global;
|
|
18
|
+
composes: min-w-[10rem] from global;
|
|
19
|
+
composes: mt-0.5 from global;
|
|
20
|
+
composes: mx-0 from global;
|
|
21
|
+
composes: right-0 from global;
|
|
22
|
+
composes: rounded from global;
|
|
23
|
+
composes: shadow-menu from global;
|
|
24
|
+
composes: text-colorDefault from global;
|
|
25
|
+
composes: text-left from global;
|
|
26
|
+
composes: top-[110%] from global;
|
|
27
|
+
composes: z-menu from global;
|
|
28
|
+
composes: p-2.5 from global;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.menuItem {
|
|
32
|
+
composes: hover_bg-gray-100 from global;
|
|
33
|
+
composes: rounded-[5px] from global;
|
|
34
|
+
composes: relative from global;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.sortButton {
|
|
38
|
+
composes: rounded-[5px] from global;
|
|
39
|
+
composes: p-2.5 from global;
|
|
40
|
+
|
|
41
|
+
composes: min-w-[154px] from global;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.desktopText {
|
|
45
|
+
composes: hidden from global;
|
|
46
|
+
|
|
47
|
+
composes: lg_inline-flex from global;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.sortText {
|
|
51
|
+
composes: leading-normal from global;
|
|
52
|
+
composes: text-colorDefault from global;
|
|
53
|
+
composes: text-base from global;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.desktopIconWrapper {
|
|
57
|
+
transform: translateX(10px);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.desktopIcon {
|
|
61
|
+
/* composes: icon from '../Icon/icon.module.css'; */
|
|
62
|
+
|
|
63
|
+
composes: stroke-gray-500 from global;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.mobileText {
|
|
67
|
+
composes: lg_hidden from global;
|
|
68
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import { Check } from 'react-feather';
|
|
3
|
+
import { bool, func, shape, string } from 'prop-types';
|
|
4
|
+
|
|
5
|
+
import { useStyle } from '@magento/venia-ui/lib/classify';
|
|
6
|
+
import defaultClasses from './customSortItem.module.css';
|
|
7
|
+
import cn from 'classnames';
|
|
8
|
+
|
|
9
|
+
const CustomSortItem = props => {
|
|
10
|
+
const { active, onClick, sortItem } = props;
|
|
11
|
+
const classes = useStyle(defaultClasses, props.classes);
|
|
12
|
+
|
|
13
|
+
const handleClick = useCallback(
|
|
14
|
+
e => {
|
|
15
|
+
// use only left click for selection
|
|
16
|
+
if (e.button === 0) {
|
|
17
|
+
onClick(sortItem);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
[sortItem, onClick]
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const handleKeyDown = useCallback(
|
|
24
|
+
e => {
|
|
25
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
26
|
+
e.preventDefault();
|
|
27
|
+
onClick(sortItem);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
[onClick, sortItem]
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<button
|
|
35
|
+
className={cn(classes.root, active ? `before_block before_h-[100%] before_w-[3px] before_bg-blue-700 before_left-[-10px] before_absolute` : '')}
|
|
36
|
+
data-cy={active ? 'CustomSortItem-activeButton' : 'CustomSortItem-button'}
|
|
37
|
+
onMouseDown={handleClick}
|
|
38
|
+
onKeyDown={handleKeyDown}
|
|
39
|
+
>
|
|
40
|
+
<span className={classes.content}>
|
|
41
|
+
<span className={classes.text}>{sortItem.text}</span>
|
|
42
|
+
</span>
|
|
43
|
+
</button>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
CustomSortItem.propTypes = {
|
|
48
|
+
active: bool,
|
|
49
|
+
classes: shape({
|
|
50
|
+
content: string,
|
|
51
|
+
root: string,
|
|
52
|
+
text: string
|
|
53
|
+
}),
|
|
54
|
+
onClick: func
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export default CustomSortItem;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.root {
|
|
2
|
+
composes: flex from global;
|
|
3
|
+
composes: items-center from global;
|
|
4
|
+
composes: w-full from global;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.content {
|
|
8
|
+
composes: items-center from global;
|
|
9
|
+
composes: grid from global;
|
|
10
|
+
composes: grid-cols-[1fr] from global;
|
|
11
|
+
composes: grid-flow-col from global;
|
|
12
|
+
composes: gap-3 from global;
|
|
13
|
+
composes: h-[30px] from global;
|
|
14
|
+
composes: px-3 from global;
|
|
15
|
+
composes: py-0 from global;
|
|
16
|
+
composes: w-full from global;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.text {
|
|
20
|
+
composes: text-left from global;
|
|
21
|
+
composes: whitespace-nowrap from global;
|
|
22
|
+
composes: text-base from global;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './customSortBy';
|
|
@@ -29,7 +29,7 @@ const ProductListTab = props => {
|
|
|
29
29
|
</span> */}
|
|
30
30
|
<nav>
|
|
31
31
|
<ul className={classes.buttonContainer}>
|
|
32
|
-
<li><button className={
|
|
32
|
+
<li><button className={classes.activeFirstButton}>All Products</button></li>
|
|
33
33
|
<li><button className={classes.middleButton}>Pre Order</button></li>
|
|
34
34
|
<li><button className={classes.lastButton}>Auctions</button></li>
|
|
35
35
|
</ul>
|
|
@@ -8,21 +8,39 @@ import { useFilterSidebar } from '@magento/peregrine/lib/talons/FilterSidebar';
|
|
|
8
8
|
import CollectibleGameSets from '@riosst100/pwa-marketplace/src/components/CollectibleGameSets/collectibleGameSets';
|
|
9
9
|
|
|
10
10
|
const SubCategory = props => {
|
|
11
|
-
|
|
11
|
+
const { children } = props;
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
const talonProps = useSubCategory({ children });
|
|
14
14
|
|
|
15
15
|
const classes = useStyle(defaultClasses, props.classes);
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
const {
|
|
18
|
+
normalizedData
|
|
19
|
+
} = talonProps;
|
|
20
|
+
|
|
21
|
+
const subCategory = [];
|
|
22
|
+
|
|
23
|
+
normalizedData && normalizedData.map(({ text, path }, index) => {
|
|
24
|
+
subCategory.push(
|
|
25
|
+
<Link
|
|
26
|
+
key={index}
|
|
27
|
+
to={resourceUrl(path)}
|
|
28
|
+
>
|
|
29
|
+
<li className={classes.item}>{text}</li>
|
|
30
|
+
</Link>
|
|
31
|
+
)
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return subCategory.length ? <ul className={classes.root}>{subCategory}</ul> : '';
|
|
35
|
+
|
|
36
|
+
// const [activeTab, setActiveTab] = useState('singles')
|
|
18
37
|
|
|
19
38
|
return (
|
|
20
39
|
<>
|
|
21
40
|
<ul className={classes.root}>
|
|
22
|
-
<li className={classes.item}
|
|
23
|
-
<li className={classes.item}
|
|
41
|
+
<li className={classes.item}>All Sets</li>
|
|
42
|
+
<li className={classes.item}>Expansion Sets</li>
|
|
24
43
|
</ul>
|
|
25
|
-
{activeTab == "singles" ? <CollectibleGameSets product_type={"singles"} /> : <CollectibleGameSets product_type={"sealed-products"} />}
|
|
26
44
|
</>
|
|
27
45
|
)
|
|
28
46
|
};
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { useQuery } from '@apollo/client';
|
|
3
|
+
import { useHistory, useLocation } from 'react-router-dom';
|
|
4
|
+
|
|
5
|
+
import { useAppContext } from '@magento/peregrine/lib/context/app';
|
|
6
|
+
|
|
7
|
+
import mergeOperations from '@magento/peregrine/lib/util/shallowMerge';
|
|
8
|
+
import { useFilterState } from '@magento/peregrine/lib/talons/FilterModal';
|
|
9
|
+
import {
|
|
10
|
+
getSearchFromState,
|
|
11
|
+
getStateFromSearch,
|
|
12
|
+
sortFiltersArray,
|
|
13
|
+
stripHtml
|
|
14
|
+
} from '@magento/peregrine/lib/talons/FilterModal/helpers';
|
|
15
|
+
|
|
16
|
+
import DEFAULT_OPERATIONS from '@magento/peregrine/lib/talons/FilterModal/filterModal.gql';
|
|
17
|
+
|
|
18
|
+
const DRAWER_NAME = 'filter';
|
|
19
|
+
|
|
20
|
+
export const useFilterSidebar = props => {
|
|
21
|
+
const { filters } = props;
|
|
22
|
+
|
|
23
|
+
const operations = mergeOperations(DEFAULT_OPERATIONS, props.operations);
|
|
24
|
+
const { getFilterInputsQuery } = operations;
|
|
25
|
+
|
|
26
|
+
const [isApplying, setIsApplying] = useState(false);
|
|
27
|
+
const [{ drawer }, { toggleDrawer, closeDrawer }] = useAppContext();
|
|
28
|
+
const [filterState, filterApi] = useFilterState();
|
|
29
|
+
const prevDrawer = useRef(null);
|
|
30
|
+
const isOpen = drawer === DRAWER_NAME;
|
|
31
|
+
|
|
32
|
+
const history = useHistory();
|
|
33
|
+
const { pathname, search } = useLocation();
|
|
34
|
+
|
|
35
|
+
const { data: introspectionData } = useQuery(getFilterInputsQuery);
|
|
36
|
+
|
|
37
|
+
const attributeCodes = useMemo(
|
|
38
|
+
() => filters.map(({ attribute_code }) => attribute_code),
|
|
39
|
+
[filters]
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// Create a set of disabled filters.
|
|
43
|
+
const DISABLED_FILTERS = useMemo(() => {
|
|
44
|
+
const disabled = new Set();
|
|
45
|
+
// Disable category filtering when not on a search page.
|
|
46
|
+
if (pathname !== '/search.html') {
|
|
47
|
+
// disabled.add('category_id');
|
|
48
|
+
// disabled.add('category_uid');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return disabled;
|
|
52
|
+
}, [pathname]);
|
|
53
|
+
|
|
54
|
+
// Get "allowed" filters by intersection of filter attribute codes and
|
|
55
|
+
// schema input field types. This restricts the displayed filters to those
|
|
56
|
+
// that the api will understand.
|
|
57
|
+
const possibleFilters = useMemo(() => {
|
|
58
|
+
const nextFilters = new Set();
|
|
59
|
+
const inputFields = introspectionData
|
|
60
|
+
? introspectionData.__type.inputFields
|
|
61
|
+
: [];
|
|
62
|
+
|
|
63
|
+
// perform mapping and filtering in the same cycle
|
|
64
|
+
for (const { name } of inputFields) {
|
|
65
|
+
const isValid = attributeCodes.includes(name);
|
|
66
|
+
const isEnabled = !DISABLED_FILTERS.has(name);
|
|
67
|
+
|
|
68
|
+
if (isValid && isEnabled) {
|
|
69
|
+
nextFilters.add(name);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return nextFilters;
|
|
74
|
+
}, [DISABLED_FILTERS, attributeCodes, introspectionData]);
|
|
75
|
+
|
|
76
|
+
const isBooleanFilter = options => {
|
|
77
|
+
const optionsString = JSON.stringify(options);
|
|
78
|
+
return (
|
|
79
|
+
options.length <= 2 &&
|
|
80
|
+
(optionsString.includes(
|
|
81
|
+
JSON.stringify({
|
|
82
|
+
__typename: 'AggregationOption',
|
|
83
|
+
label: '0',
|
|
84
|
+
value: '0'
|
|
85
|
+
})
|
|
86
|
+
) ||
|
|
87
|
+
optionsString.includes(
|
|
88
|
+
JSON.stringify({
|
|
89
|
+
__typename: 'AggregationOption',
|
|
90
|
+
label: '1',
|
|
91
|
+
value: '1'
|
|
92
|
+
})
|
|
93
|
+
))
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// iterate over filters once to set up all the collections we need
|
|
98
|
+
const [
|
|
99
|
+
filterNames,
|
|
100
|
+
filterKeys,
|
|
101
|
+
filterItems,
|
|
102
|
+
filterFrontendInput
|
|
103
|
+
] = useMemo(() => {
|
|
104
|
+
const names = new Map();
|
|
105
|
+
const keys = new Set();
|
|
106
|
+
const frontendInput = new Map();
|
|
107
|
+
const itemsByGroup = new Map();
|
|
108
|
+
|
|
109
|
+
const sortedFilters = sortFiltersArray([...filters]);
|
|
110
|
+
|
|
111
|
+
for (const filter of sortedFilters) {
|
|
112
|
+
const { options, label: name, attribute_code: group } = filter;
|
|
113
|
+
|
|
114
|
+
// If this aggregation is not a possible filter, just back out.
|
|
115
|
+
if (possibleFilters.has(group)) {
|
|
116
|
+
const items = [];
|
|
117
|
+
|
|
118
|
+
// add filter name
|
|
119
|
+
names.set(group, name);
|
|
120
|
+
|
|
121
|
+
// add filter key permutations
|
|
122
|
+
keys.add(`${group}[filter]`);
|
|
123
|
+
|
|
124
|
+
// TODO: Get all frontend input type from gql if other filter input types are needed
|
|
125
|
+
// See https://github.com/magento-commerce/magento2-pwa/pull/26
|
|
126
|
+
if (isBooleanFilter(options)) {
|
|
127
|
+
frontendInput.set(group, 'boolean');
|
|
128
|
+
// add items
|
|
129
|
+
items.push({
|
|
130
|
+
title: 'No',
|
|
131
|
+
value: '0',
|
|
132
|
+
label: name + ':' + 'No'
|
|
133
|
+
});
|
|
134
|
+
items.push({
|
|
135
|
+
title: 'Yes',
|
|
136
|
+
value: '1',
|
|
137
|
+
label: name + ':' + 'Yes'
|
|
138
|
+
});
|
|
139
|
+
} else {
|
|
140
|
+
// Add frontend input type
|
|
141
|
+
frontendInput.set(group, null);
|
|
142
|
+
// add items
|
|
143
|
+
for (const { label, value } of options) {
|
|
144
|
+
items.push({ title: stripHtml(label), value });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
itemsByGroup.set(group, items);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return [names, keys, itemsByGroup, frontendInput];
|
|
152
|
+
}, [filters, possibleFilters]);
|
|
153
|
+
|
|
154
|
+
// on apply, write filter state to location
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
if (isApplying) {
|
|
157
|
+
const nextSearch = getSearchFromState(
|
|
158
|
+
search,
|
|
159
|
+
filterKeys,
|
|
160
|
+
filterState
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// write filter state to history
|
|
164
|
+
history.push({ pathname, search: nextSearch });
|
|
165
|
+
|
|
166
|
+
// mark the operation as complete
|
|
167
|
+
setIsApplying(false);
|
|
168
|
+
}
|
|
169
|
+
}, [filterKeys, filterState, history, isApplying, pathname, search]);
|
|
170
|
+
|
|
171
|
+
const handleOpen = useCallback(() => {
|
|
172
|
+
toggleDrawer(DRAWER_NAME);
|
|
173
|
+
}, [toggleDrawer]);
|
|
174
|
+
|
|
175
|
+
const handleClose = useCallback(() => {
|
|
176
|
+
closeDrawer();
|
|
177
|
+
}, [closeDrawer]);
|
|
178
|
+
|
|
179
|
+
const handleApply = useCallback(() => {
|
|
180
|
+
setIsApplying(true);
|
|
181
|
+
handleClose();
|
|
182
|
+
}, [handleClose]);
|
|
183
|
+
|
|
184
|
+
const handleReset = useCallback(() => {
|
|
185
|
+
filterApi.clear();
|
|
186
|
+
setIsApplying(true);
|
|
187
|
+
}, [filterApi, setIsApplying]);
|
|
188
|
+
|
|
189
|
+
const handleKeyDownActions = useCallback(
|
|
190
|
+
event => {
|
|
191
|
+
// do not handle keyboard actions when the modal is closed
|
|
192
|
+
if (!isOpen) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
switch (event.keyCode) {
|
|
197
|
+
// when "Esc" key fired -> close the modal
|
|
198
|
+
case 27:
|
|
199
|
+
handleClose();
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
[isOpen, handleClose]
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
useEffect(() => {
|
|
207
|
+
const justOpened =
|
|
208
|
+
prevDrawer.current === null && drawer === DRAWER_NAME;
|
|
209
|
+
const justClosed =
|
|
210
|
+
prevDrawer.current === DRAWER_NAME && drawer === null;
|
|
211
|
+
|
|
212
|
+
// on drawer toggle, read filter state from location
|
|
213
|
+
if (justOpened || justClosed) {
|
|
214
|
+
const nextState = getStateFromSearch(
|
|
215
|
+
search,
|
|
216
|
+
filterKeys,
|
|
217
|
+
filterItems
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
filterApi.setItems(nextState);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// on drawer close, update the modal visibility state
|
|
224
|
+
if (justClosed) {
|
|
225
|
+
handleClose();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
prevDrawer.current = drawer;
|
|
229
|
+
}, [drawer, filterApi, filterItems, filterKeys, search, handleClose]);
|
|
230
|
+
|
|
231
|
+
useEffect(() => {
|
|
232
|
+
const nextState = getStateFromSearch(search, filterKeys, filterItems);
|
|
233
|
+
|
|
234
|
+
filterApi.setItems(nextState);
|
|
235
|
+
}, [filterApi, filterItems, filterKeys, search]);
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
filterApi,
|
|
239
|
+
filterItems,
|
|
240
|
+
filterKeys,
|
|
241
|
+
filterNames,
|
|
242
|
+
filterFrontendInput,
|
|
243
|
+
filterState,
|
|
244
|
+
handleApply,
|
|
245
|
+
handleClose,
|
|
246
|
+
handleKeyDownActions,
|
|
247
|
+
handleOpen,
|
|
248
|
+
handleReset,
|
|
249
|
+
isApplying,
|
|
250
|
+
isOpen
|
|
251
|
+
};
|
|
252
|
+
};
|
|
@@ -85,12 +85,44 @@ export const useCategoryContent = props => {
|
|
|
85
85
|
}
|
|
86
86
|
}, [categoryId, getSortMethods]);
|
|
87
87
|
|
|
88
|
-
const
|
|
88
|
+
const rawFilters = filterData ? filterData.products.aggregations : null;
|
|
89
89
|
const items = data ? data.products.items : placeholderItems;
|
|
90
|
+
const category =
|
|
91
|
+
categoryData && categoryData.categories.items.length
|
|
92
|
+
? categoryData.categories.items[0]
|
|
93
|
+
: null;
|
|
90
94
|
const children =
|
|
91
95
|
categoryData && categoryData.categories.items.length
|
|
92
96
|
? categoryData.categories.items[0].children
|
|
93
97
|
: null;
|
|
98
|
+
|
|
99
|
+
const filters = [];
|
|
100
|
+
|
|
101
|
+
rawFilters && rawFilters.map((filter, index) => {
|
|
102
|
+
|
|
103
|
+
const filterOptions = [];
|
|
104
|
+
let label = filter.label;
|
|
105
|
+
if (filter.attribute_code == "category_uid") {
|
|
106
|
+
children && children.map((category, index) => {
|
|
107
|
+
filterOptions.push({
|
|
108
|
+
'label': category.name,
|
|
109
|
+
'value': category.uid
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
label = category ? category.name : label;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const newFilter = {
|
|
117
|
+
attribute_code: filter.attribute_code,
|
|
118
|
+
count: filter.count,
|
|
119
|
+
label: label,
|
|
120
|
+
options: filterOptions.length ? filterOptions : filter.options
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
filters.push(newFilter);
|
|
124
|
+
});
|
|
125
|
+
|
|
94
126
|
const attributesBlock = categoryData && categoryData.categories.items.length
|
|
95
127
|
? categoryData.categories.items[0].attributes_block
|
|
96
128
|
: null;
|
|
@@ -102,10 +134,7 @@ export const useCategoryContent = props => {
|
|
|
102
134
|
? data.products.page_info.total_pages
|
|
103
135
|
: null;
|
|
104
136
|
const totalCount = data ? data.products.total_count : null;
|
|
105
|
-
|
|
106
|
-
categoryData && categoryData.categories.items.length
|
|
107
|
-
? categoryData.categories.items[0]
|
|
108
|
-
: null;
|
|
137
|
+
|
|
109
138
|
const categoryName =
|
|
110
139
|
categoryData && categoryData.categories.items.length
|
|
111
140
|
? categoryData.categories.items[0].name
|
|
@@ -94,7 +94,7 @@ const CategoryContent = props => {
|
|
|
94
94
|
) : null;
|
|
95
95
|
|
|
96
96
|
const sidebar = shouldShowFilterButtons ? (
|
|
97
|
-
<FilterSidebar filters={filters} />
|
|
97
|
+
<FilterSidebar children={children} filters={filters} allowedFilters={category ? category.allowed_filters : []} />
|
|
98
98
|
) : shouldShowFilterShimmer ? (
|
|
99
99
|
<FilterSidebarShimmer />
|
|
100
100
|
) : null;
|
|
@@ -174,12 +174,34 @@ const CategoryContent = props => {
|
|
|
174
174
|
const categoryTitle = categoryName ? categoryName : <Shimmer width={5} />;
|
|
175
175
|
|
|
176
176
|
const { search } = useLocation();
|
|
177
|
-
const
|
|
177
|
+
const allActiveFilters = getFiltersFromSearch(search);
|
|
178
|
+
|
|
179
|
+
const activeFilters = [];
|
|
180
|
+
|
|
181
|
+
if (allActiveFilters && allActiveFilters.size > 0) {
|
|
182
|
+
allActiveFilters.forEach((value, key) => {
|
|
183
|
+
value.forEach((value) => {
|
|
184
|
+
const filterArr = value.split(',');
|
|
185
|
+
|
|
186
|
+
const label = filterArr[0];
|
|
187
|
+
const optionId = filterArr[1];
|
|
188
|
+
if (key == "card_set") {
|
|
189
|
+
activeFilters.push(
|
|
190
|
+
{
|
|
191
|
+
'label': label
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
})
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const currentFilter = activeFilters && activeFilters.length ? activeFilters[activeFilters.length - 1].label : '';
|
|
178
200
|
|
|
179
201
|
return (
|
|
180
202
|
<Fragment>
|
|
181
|
-
<Breadcrumbs categoryId={categoryId} />
|
|
182
|
-
<StoreTitle>{categoryName}</StoreTitle>
|
|
203
|
+
<Breadcrumbs categoryId={categoryId} currentFilter={activeFilters} />
|
|
204
|
+
<StoreTitle>{currentFilter ? currentFilter : categoryName}</StoreTitle>
|
|
183
205
|
<article className={classes.root} data-cy="CategoryContent-root">
|
|
184
206
|
<div className={classes.categoryHeader}>
|
|
185
207
|
<h1 aria-live="polite" className={classes.title}>
|
|
@@ -187,16 +209,16 @@ const CategoryContent = props => {
|
|
|
187
209
|
className={classes.categoryTitle}
|
|
188
210
|
data-cy="CategoryContent-categoryTitle"
|
|
189
211
|
>
|
|
190
|
-
{categoryTitle}
|
|
212
|
+
{currentFilter ? currentFilter : categoryTitle}
|
|
191
213
|
</span>
|
|
192
214
|
</h1>
|
|
193
215
|
{categoryDescriptionElement}
|
|
194
216
|
</div>
|
|
195
|
-
{activeFilters.size <= 0 && category && category.custom_landing_page ? (
|
|
217
|
+
{/* {activeFilters.size <= 0 && category && category.custom_landing_page ? ( */}
|
|
196
218
|
<>
|
|
197
|
-
<SubCategory customLandingPage={category.custom_landing_page} />
|
|
219
|
+
<SubCategory children={children} customLandingPage={category ? category.custom_landing_page : ''} />
|
|
198
220
|
</>
|
|
199
|
-
) : (
|
|
221
|
+
{/* ) : ( */}
|
|
200
222
|
<>
|
|
201
223
|
{/* <SubCategory filters={filters} children={children} /> */}
|
|
202
224
|
<FilterTop filters={filters} category={category} />
|
|
@@ -232,7 +254,7 @@ const CategoryContent = props => {
|
|
|
232
254
|
</div>
|
|
233
255
|
</div>
|
|
234
256
|
</>
|
|
235
|
-
)}
|
|
257
|
+
{/* )} */}
|
|
236
258
|
</article>
|
|
237
259
|
</Fragment>
|
|
238
260
|
);
|
|
@@ -10,7 +10,8 @@ import Shimmer from '@riosst100/pwa-marketplace/src/overwrites/venia-ui/lib/comp
|
|
|
10
10
|
import defaultClasses from '@riosst100/pwa-marketplace/src/overwrites/venia-ui/lib/components/Breadcrumbs/breadcrumbs.module.css';
|
|
11
11
|
import { ArrowRight2 } from 'iconsax-react';
|
|
12
12
|
import cn from 'classnames';
|
|
13
|
-
|
|
13
|
+
import { getFiltersFromSearch } from '@magento/peregrine/lib/talons/FilterModal/helpers';
|
|
14
|
+
import { useLocation } from 'react-router-dom';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Breadcrumbs! Generates a sorted display of category links.
|
|
@@ -21,7 +22,7 @@ import cn from 'classnames';
|
|
|
21
22
|
const Breadcrumbs = props => {
|
|
22
23
|
const classes = useStyle(defaultClasses, props.classes);
|
|
23
24
|
|
|
24
|
-
const { categoryId, currentProduct } = props;
|
|
25
|
+
const { categoryId, currentProduct, currentFilter } = props;
|
|
25
26
|
|
|
26
27
|
const talonProps = useBreadcrumbs({ categoryId });
|
|
27
28
|
|
|
@@ -69,13 +70,36 @@ const Breadcrumbs = props => {
|
|
|
69
70
|
);
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
const filterBreadcrumbsElement = [];
|
|
74
|
+
|
|
75
|
+
currentFilter && currentFilter.length && currentFilter.map((filter, index) => {
|
|
76
|
+
currentProduct ? (
|
|
77
|
+
filterBreadcrumbsElement.push(
|
|
78
|
+
<Link
|
|
79
|
+
className={classes.link}
|
|
80
|
+
to={resourceUrl(currentCategoryPath)}
|
|
81
|
+
onClick={handleClick}
|
|
82
|
+
>
|
|
83
|
+
{filter.label}
|
|
84
|
+
</Link>
|
|
85
|
+
)
|
|
86
|
+
) : (
|
|
87
|
+
filterBreadcrumbsElement.push(
|
|
88
|
+
<>
|
|
89
|
+
<span className={classes.divider}>{DELIMITER}</span>
|
|
90
|
+
<span className={cn(classes.currentCategory, 'text-blue-700 font-medium')}>{filter.label}</span>
|
|
91
|
+
</>
|
|
92
|
+
)
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
|
|
72
96
|
// If we have a "currentProduct" it means we're on a PDP so we want the last
|
|
73
97
|
// category text to be a link. If we don't have a "currentProduct" we're on
|
|
74
98
|
// a category page so it should be regular text.
|
|
75
|
-
const currentCategoryLink = currentProduct ? (
|
|
99
|
+
const currentCategoryLink = currentProduct || currentFilter && currentFilter.length ? (
|
|
76
100
|
<Link
|
|
77
101
|
className={classes.link}
|
|
78
|
-
to={resourceUrl(currentCategoryPath)}
|
|
102
|
+
to={'/'+resourceUrl(currentCategoryPath)}
|
|
79
103
|
onClick={handleClick}
|
|
80
104
|
>
|
|
81
105
|
{currentCategory}
|
|
@@ -90,7 +114,7 @@ const Breadcrumbs = props => {
|
|
|
90
114
|
<span className={classes.text}>{currentProduct}</span>
|
|
91
115
|
</Fragment>
|
|
92
116
|
) : null;
|
|
93
|
-
|
|
117
|
+
|
|
94
118
|
return (
|
|
95
119
|
<div className={classes.root} aria-live="polite" aria-busy="false">
|
|
96
120
|
<Link className={classes.link} to="/">
|
|
@@ -99,6 +123,7 @@ const Breadcrumbs = props => {
|
|
|
99
123
|
{links}
|
|
100
124
|
<span className={classes.divider}>{DELIMITER}</span>
|
|
101
125
|
{currentCategoryLink}
|
|
126
|
+
{filterBreadcrumbsElement}
|
|
102
127
|
{currentProductNode}
|
|
103
128
|
</div>
|
|
104
129
|
);
|
|
@@ -20,16 +20,18 @@ const CurrentFilters = props => {
|
|
|
20
20
|
const { title, value } = item || {};
|
|
21
21
|
const key = `${group}::${title}_${value}`;
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
if (group != "card_set") {
|
|
24
|
+
elements.push(
|
|
25
|
+
<li key={key} className={classes.item}>
|
|
26
|
+
<CurrentFilter
|
|
27
|
+
group={group}
|
|
28
|
+
item={item}
|
|
29
|
+
removeItem={removeItem}
|
|
30
|
+
onRemove={onRemove}
|
|
31
|
+
/>
|
|
32
|
+
</li>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
33
35
|
}
|
|
34
36
|
}
|
|
35
37
|
|
|
@@ -19,7 +19,7 @@ const SCROLL_OFFSET = 150;
|
|
|
19
19
|
* @param {Object} props.filters - filters to display
|
|
20
20
|
*/
|
|
21
21
|
const FilterSidebar = props => {
|
|
22
|
-
const { filters, filterCountToOpen } = props;
|
|
22
|
+
const { filters, filterCountToOpen, allowedFilters } = props;
|
|
23
23
|
const talonProps = useFilterSidebar({ filters });
|
|
24
24
|
const {
|
|
25
25
|
filterApi,
|
|
@@ -52,25 +52,33 @@ const FilterSidebar = props => {
|
|
|
52
52
|
[handleApply, filterRef]
|
|
53
53
|
);
|
|
54
54
|
|
|
55
|
+
const allowedFiltersArr = [];
|
|
56
|
+
|
|
57
|
+
allowedFilters.length && allowedFilters.map((val, index) => {
|
|
58
|
+
allowedFiltersArr.push(val.code);
|
|
59
|
+
});
|
|
60
|
+
|
|
55
61
|
const filtersList = useMemo(
|
|
56
62
|
() =>
|
|
57
63
|
Array.from(filterItems, ([group, items], iteration) => {
|
|
58
64
|
const blockState = filterState.get(group);
|
|
59
65
|
const groupName = filterNames.get(group);
|
|
60
66
|
const frontendInput = filterFrontendInput.get(group);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
if (!allowedFiltersArr.length && group != "category_uid" || allowedFiltersArr.length && allowedFiltersArr.includes(group)) {
|
|
68
|
+
return (
|
|
69
|
+
<FilterBlock
|
|
70
|
+
key={group}
|
|
71
|
+
filterApi={filterApi}
|
|
72
|
+
filterState={blockState}
|
|
73
|
+
filterFrontendInput={frontendInput}
|
|
74
|
+
group={group}
|
|
75
|
+
items={items}
|
|
76
|
+
name={groupName}
|
|
77
|
+
onApply={handleApplyFilter}
|
|
78
|
+
initialOpen={iteration < filterCountToOpen}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
74
82
|
}),
|
|
75
83
|
[
|
|
76
84
|
filterApi,
|
|
@@ -8,7 +8,7 @@ import DEFAULT_OPERATIONS from './collectibleGameSets.gql';
|
|
|
8
8
|
|
|
9
9
|
export const useCollectibleGameSets = props => {
|
|
10
10
|
|
|
11
|
-
const {
|
|
11
|
+
const { productType } = props
|
|
12
12
|
|
|
13
13
|
const operations = mergeOperations(DEFAULT_OPERATIONS, null);
|
|
14
14
|
const { getStoreConfigData, getCollectibleGameQuery } = operations;
|
|
@@ -28,11 +28,10 @@ export const useCollectibleGameSets = props => {
|
|
|
28
28
|
const pathnameArr = pathname.split('/');
|
|
29
29
|
|
|
30
30
|
const categoryUrlKey = pathnameArr[pathnameArr.length - 1].replace('.html','');
|
|
31
|
-
const productType = product_type ? product_type : 'singles';
|
|
32
31
|
|
|
33
32
|
const categoryUrlSuffix = storeConfigData?.storeConfig?.category_url_suffix;
|
|
34
33
|
|
|
35
|
-
const { error, loading, data } = useQuery(getCollectibleGameQuery, {
|
|
34
|
+
const { error: allSetsError, loading: allSetsLoading, data: allSetsData } = useQuery(getCollectibleGameQuery, {
|
|
36
35
|
fetchPolicy: 'cache-and-network',
|
|
37
36
|
nextFetchPolicy: 'cache-first',
|
|
38
37
|
skip: !storeConfigData,
|
|
@@ -42,26 +41,31 @@ export const useCollectibleGameSets = props => {
|
|
|
42
41
|
}
|
|
43
42
|
});
|
|
44
43
|
|
|
45
|
-
const
|
|
44
|
+
const { error: expansionSetsError, loading: expansionSetsLoading, data: expansionSetsData } = useQuery(getCollectibleGameQuery, {
|
|
45
|
+
fetchPolicy: 'cache-and-network',
|
|
46
|
+
nextFetchPolicy: 'cache-first',
|
|
47
|
+
skip: !storeConfigData,
|
|
48
|
+
variables: {
|
|
49
|
+
categoryUrlKey: categoryUrlKey,
|
|
50
|
+
productType: productType
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const loading = !!allSetsData && allSetsLoading;
|
|
55
|
+
const error = !!allSetsData && allSetsError;
|
|
46
56
|
|
|
47
57
|
const collectibleGameSets = useMemo(() => {
|
|
48
|
-
if (!
|
|
58
|
+
if (!allSetsData) {
|
|
49
59
|
return null;
|
|
50
60
|
}
|
|
51
61
|
|
|
52
|
-
const collectibleGameSets =
|
|
53
|
-
|
|
62
|
+
const collectibleGameSets = productType == "sealed-products" ? expansionSetsData.collectibleGameSets : allSetsData.collectibleGameSets;
|
|
54
63
|
if (!collectibleGameSets) {
|
|
55
64
|
return null;
|
|
56
65
|
}
|
|
57
66
|
|
|
58
67
|
return collectibleGameSets;
|
|
59
|
-
}, [
|
|
60
|
-
|
|
61
|
-
// Update the page indicator if the GraphQL query is in flight.
|
|
62
|
-
useEffect(() => {
|
|
63
|
-
setPageLoading(isBackgroundLoading);
|
|
64
|
-
}, [isBackgroundLoading, setPageLoading]);
|
|
68
|
+
}, [allSetsData, expansionSetsData, categoryUrlKey, productType]);
|
|
65
69
|
|
|
66
70
|
return {
|
|
67
71
|
error,
|