@riosst100/pwa-marketplace 1.8.0 → 1.8.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/i18n/id_ID.json +508 -508
- package/package.json +1 -2
- package/src/components/CustomSubCategory/subCategory.js +0 -14
- package/src/components/FilterTop/FilterBlockList/filterTopItemGroup.module.css +1 -1
- package/src/components/FilterTop/filterTop.js +2 -2
- package/src/components/FilterTop/filterTop.module.css +1 -1
- package/src/components/FilterTopBackup/CustomFilters/customFilter.js +83 -83
- package/src/components/FilterTopBackup/CustomFilters/customFilter.module.css +21 -21
- package/src/components/FilterTopBackup/CustomFilters/customFilters.js +131 -131
- package/src/components/FilterTopBackup/CustomFilters/customFilters.module.css +22 -22
- package/src/components/FilterTopBackup/CustomFilters/index.js +1 -1
- package/src/components/FilterTopBackup/filterTop.js +14 -14
- package/src/components/FilterTopBackup/filterTop.module.css +22 -22
- package/src/components/FilterTopBackup/filterTop.shimmer.js +24 -24
- package/src/components/FilterTopBackup/index.js +2 -2
- package/src/components/Header/websiteSwitcher.shimmer.js +6 -6
- package/src/components/Header/websiteSwitcherItem.js +47 -47
- package/src/components/Header/websiteSwitcherItem.module.css +20 -20
- package/src/components/LegoSets/legoSets.js +21 -72
- package/src/components/PhoneTextInput/index.js +1 -1
- package/src/components/PhoneTextInput/phoneTextInput.js +62 -62
- package/src/components/ProductListTab/index.js +4 -4
- package/src/components/ProductListTab/productListTab.module.css +64 -64
- package/src/components/ProductListTab/productListTab.shimmer.js +24 -24
- package/src/components/SellerCountry/index.js +1 -1
- package/src/components/SellerCountry/sellerCountry.js +71 -71
- package/src/components/SellerCountry/sellerCountry.module.css +3 -3
- package/src/components/ShopByCategory/index.js +2 -2
- package/src/components/ShopByCategory/shopByCategory.js +69 -69
- package/src/components/ShopByCategory/shopByCategory.module.css +58 -58
- package/src/components/ShopByCategory/shopByCategory.shimmer.js +24 -24
- package/src/components/SubCategory/subCategory.js +1 -1
- package/src/components/WebsiteSwitcher/websiteSwitcher.shimmer.js +6 -6
- package/src/components/WebsiteSwitcher/websiteSwitcherItem.js +47 -47
- package/src/components/WebsiteSwitcher/websiteSwitcherItem.module.css +20 -20
- package/src/overwrites/peregrine/lib/talons/MegaMenu/megaMenu.gql.js +96 -96
- package/src/overwrites/peregrine/lib/talons/MegaMenu/useMegaMenu.js +199 -199
- package/src/overwrites/peregrine/lib/talons/MegaMenu/useMegaMenuItem.js +66 -66
- package/src/overwrites/peregrine/lib/talons/MegaMenu/useSubMenu.js +20 -20
- package/src/overwrites/peregrine/lib/talons/ProductFullDetail/useProductFullDetail.js +642 -642
- package/src/overwrites/peregrine/lib/talons/RootComponents/Category/category.gql.js +49 -49
- package/src/overwrites/peregrine/lib/talons/RootComponents/Category/useCategory.js +227 -227
- package/src/overwrites/peregrine/lib/talons/RootComponents/Product/product.gql.js +31 -31
- package/src/overwrites/peregrine/lib/talons/RootComponents/Product/productDetailFragment.gql.js +235 -235
- package/src/overwrites/venia-ui/lib/components/Header/cartTrigger.module.css +47 -47
- package/src/overwrites/venia-ui/lib/components/RadioGroup/radio.js +60 -60
- package/src/overwrites/venia-ui/lib/components/RadioGroup/radio.module.css +70 -70
- package/src/talons/AttributesBlock/attributesBlock.gql.js +15 -15
- package/src/talons/CustomFilters/customFilters.gql.js +45 -45
- package/src/talons/CustomFilters/useCustomFilters.js +5 -2
- package/src/talons/FilterTop/filterTop.gql.js +45 -45
- package/src/talons/FilterTop/index.js +1 -1
- package/src/talons/FilterTop/useFilterTop.js +9 -3
- package/src/talons/Header/websiteSwitcher.gql.js +45 -45
- package/src/talons/LegoSets/legoSets.gql.js +2 -2
- package/src/talons/LegoSets/useLegoSets.js +6 -56
- package/src/talons/SellerReview/sellerReview.gql.js +53 -53
- package/src/talons/ShopByCategory/index.js +1 -1
- package/src/talons/ShopByCategory/shopByCategory.gql.js +38 -38
- package/src/talons/ShopByCategory/useShopByCategory.js +69 -69
- package/src/talons/SubCategory/subCategory.gql.js +15 -15
- package/src/talons/SubCategory/useSubCategory.js +3 -3
- package/src/talons/WebsiteSwitcher/websiteSwitcher.gql.js +45 -45
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
import { gql } from '@apollo/client';
|
|
2
|
-
|
|
3
|
-
import { CategoryFragment, ProductsFragment } from './categoryFragments.gql';
|
|
4
|
-
|
|
5
|
-
export const GET_CATEGORY = gql`
|
|
6
|
-
query GetCategories(
|
|
7
|
-
$id: String!
|
|
8
|
-
$pageSize: Int!
|
|
9
|
-
$currentPage: Int!
|
|
10
|
-
$filters: ProductAttributeFilterInput!
|
|
11
|
-
$sort: ProductAttributeSortInput
|
|
12
|
-
) {
|
|
13
|
-
categories(filters: { category_uid: { in: [$id] } }) {
|
|
14
|
-
# eslint-disable-next-line @graphql-eslint/require-id-when-available
|
|
15
|
-
items {
|
|
16
|
-
uid
|
|
17
|
-
...CategoryFragment
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
products(
|
|
21
|
-
pageSize: $pageSize
|
|
22
|
-
currentPage: $currentPage
|
|
23
|
-
filter: $filters
|
|
24
|
-
sort: $sort
|
|
25
|
-
) {
|
|
26
|
-
...ProductsFragment
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
${CategoryFragment}
|
|
30
|
-
${ProductsFragment}
|
|
31
|
-
`;
|
|
32
|
-
|
|
33
|
-
export const GET_FILTER_INPUTS = gql`
|
|
34
|
-
query GetFilterInputsForCategory {
|
|
35
|
-
__type(name: "ProductAttributeFilterInput") {
|
|
36
|
-
inputFields {
|
|
37
|
-
name
|
|
38
|
-
type {
|
|
39
|
-
name
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
`;
|
|
45
|
-
|
|
46
|
-
export default {
|
|
47
|
-
getCategoryQuery: GET_CATEGORY,
|
|
48
|
-
getFilterInputsQuery: GET_FILTER_INPUTS
|
|
49
|
-
};
|
|
1
|
+
import { gql } from '@apollo/client';
|
|
2
|
+
|
|
3
|
+
import { CategoryFragment, ProductsFragment } from './categoryFragments.gql';
|
|
4
|
+
|
|
5
|
+
export const GET_CATEGORY = gql`
|
|
6
|
+
query GetCategories(
|
|
7
|
+
$id: String!
|
|
8
|
+
$pageSize: Int!
|
|
9
|
+
$currentPage: Int!
|
|
10
|
+
$filters: ProductAttributeFilterInput!
|
|
11
|
+
$sort: ProductAttributeSortInput
|
|
12
|
+
) {
|
|
13
|
+
categories(filters: { category_uid: { in: [$id] } }) {
|
|
14
|
+
# eslint-disable-next-line @graphql-eslint/require-id-when-available
|
|
15
|
+
items {
|
|
16
|
+
uid
|
|
17
|
+
...CategoryFragment
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
products(
|
|
21
|
+
pageSize: $pageSize
|
|
22
|
+
currentPage: $currentPage
|
|
23
|
+
filter: $filters
|
|
24
|
+
sort: $sort
|
|
25
|
+
) {
|
|
26
|
+
...ProductsFragment
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
${CategoryFragment}
|
|
30
|
+
${ProductsFragment}
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
export const GET_FILTER_INPUTS = gql`
|
|
34
|
+
query GetFilterInputsForCategory {
|
|
35
|
+
__type(name: "ProductAttributeFilterInput") {
|
|
36
|
+
inputFields {
|
|
37
|
+
name
|
|
38
|
+
type {
|
|
39
|
+
name
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
export default {
|
|
47
|
+
getCategoryQuery: GET_CATEGORY,
|
|
48
|
+
getFilterInputsQuery: GET_FILTER_INPUTS
|
|
49
|
+
};
|
|
@@ -1,227 +1,227 @@
|
|
|
1
|
-
import { useEffect, useMemo, useRef } from 'react';
|
|
2
|
-
import { useLocation } from 'react-router-dom';
|
|
3
|
-
import { useLazyQuery, useQuery } from '@apollo/client';
|
|
4
|
-
|
|
5
|
-
import mergeOperations from '@magento/peregrine/lib/util/shallowMerge';
|
|
6
|
-
import { useAppContext } from '@magento/peregrine/lib/context/app';
|
|
7
|
-
import { usePagination } from '@magento/peregrine/lib/hooks/usePagination';
|
|
8
|
-
import { useScrollTopOnChange } from '@magento/peregrine/lib/hooks/useScrollTopOnChange';
|
|
9
|
-
import { useSort } from '@magento/peregrine/lib/hooks/useSort';
|
|
10
|
-
import {
|
|
11
|
-
getFiltersFromSearch,
|
|
12
|
-
getFilterInput
|
|
13
|
-
} from '@magento/peregrine/lib/talons/FilterModal/helpers';
|
|
14
|
-
|
|
15
|
-
import DEFAULT_OPERATIONS from './category.gql';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* A [React Hook]{@link https://reactjs.org/docs/hooks-intro.html} that
|
|
19
|
-
* controls the logic for the Category Root Component.
|
|
20
|
-
*
|
|
21
|
-
* @kind function
|
|
22
|
-
*
|
|
23
|
-
* @param {object} props
|
|
24
|
-
* @param {String} props.id - Category uid.
|
|
25
|
-
* @param {GraphQLAST} props.operations.getCategoryQuery - Fetches category using a server query
|
|
26
|
-
* @param {GraphQLAST} props.operations.getFilterInputsQuery - Fetches "allowed" filters using a server query
|
|
27
|
-
* @param {GraphQLAST} props.queries.getStoreConfig - Fetches store configuration using a server query
|
|
28
|
-
*
|
|
29
|
-
* @returns {object} result
|
|
30
|
-
* @returns {object} result.error - Indicates a network error occurred.
|
|
31
|
-
* @returns {object} result.categoryData - Category data.
|
|
32
|
-
* @returns {bool} result.isLoading - Category data loading.
|
|
33
|
-
* @returns {string} result.metaDescription - Category meta description.
|
|
34
|
-
* @returns {object} result.pageControl - Category pagination state.
|
|
35
|
-
* @returns {array} result.sortProps - Category sorting parameters.
|
|
36
|
-
* @returns {number} result.pageSize - Category total pages.
|
|
37
|
-
*/
|
|
38
|
-
export const useCategory = props => {
|
|
39
|
-
const {
|
|
40
|
-
id,
|
|
41
|
-
queries: { getPageSize }
|
|
42
|
-
} = props;
|
|
43
|
-
|
|
44
|
-
const operations = mergeOperations(DEFAULT_OPERATIONS, props.operations);
|
|
45
|
-
const { getCategoryQuery, getFilterInputsQuery } = operations;
|
|
46
|
-
|
|
47
|
-
const { data: pageSizeData } = useQuery(getPageSize, {
|
|
48
|
-
fetchPolicy: 'cache-and-network',
|
|
49
|
-
nextFetchPolicy: 'cache-first'
|
|
50
|
-
});
|
|
51
|
-
const pageSize = pageSizeData && pageSizeData.storeConfig.grid_per_page;
|
|
52
|
-
|
|
53
|
-
const [paginationValues, paginationApi] = usePagination();
|
|
54
|
-
const { currentPage, totalPages } = paginationValues;
|
|
55
|
-
const { setCurrentPage, setTotalPages } = paginationApi;
|
|
56
|
-
|
|
57
|
-
const sortProps = useSort({ sortFromSearch: false });
|
|
58
|
-
const [currentSort] = sortProps;
|
|
59
|
-
|
|
60
|
-
// Keep track of the sort criteria so we can tell when they change.
|
|
61
|
-
const previousSort = useRef(currentSort);
|
|
62
|
-
|
|
63
|
-
const pageControl = {
|
|
64
|
-
currentPage,
|
|
65
|
-
setPage: setCurrentPage,
|
|
66
|
-
totalPages
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const [
|
|
70
|
-
,
|
|
71
|
-
{
|
|
72
|
-
actions: { setPageLoading }
|
|
73
|
-
}
|
|
74
|
-
] = useAppContext();
|
|
75
|
-
|
|
76
|
-
const [runQuery, queryResponse] = useLazyQuery(getCategoryQuery, {
|
|
77
|
-
fetchPolicy: 'cache-and-network',
|
|
78
|
-
nextFetchPolicy: 'cache-first'
|
|
79
|
-
});
|
|
80
|
-
const {
|
|
81
|
-
called: categoryCalled,
|
|
82
|
-
loading: categoryLoading,
|
|
83
|
-
error,
|
|
84
|
-
data
|
|
85
|
-
} = queryResponse;
|
|
86
|
-
const { search } = useLocation();
|
|
87
|
-
|
|
88
|
-
const isBackgroundLoading = !!data && categoryLoading;
|
|
89
|
-
|
|
90
|
-
// Update the page indicator if the GraphQL query is in flight.
|
|
91
|
-
useEffect(() => {
|
|
92
|
-
setPageLoading(isBackgroundLoading);
|
|
93
|
-
}, [isBackgroundLoading, setPageLoading]);
|
|
94
|
-
|
|
95
|
-
// Keep track of the search terms so we can tell when they change.
|
|
96
|
-
const previousSearch = useRef(search);
|
|
97
|
-
|
|
98
|
-
// Get "allowed" filters by intersection of schema and aggregations
|
|
99
|
-
const {
|
|
100
|
-
called: introspectionCalled,
|
|
101
|
-
data: introspectionData,
|
|
102
|
-
loading: introspectionLoading
|
|
103
|
-
} = useQuery(getFilterInputsQuery);
|
|
104
|
-
|
|
105
|
-
// Create a type map we can reference later to ensure we pass valid args
|
|
106
|
-
// to the graphql query.
|
|
107
|
-
// For example: { category_id: 'FilterEqualTypeInput', price: 'FilterRangeTypeInput' }
|
|
108
|
-
const filterTypeMap = useMemo(() => {
|
|
109
|
-
const typeMap = new Map();
|
|
110
|
-
if (introspectionData) {
|
|
111
|
-
introspectionData.__type.inputFields.forEach(({ name, type }) => {
|
|
112
|
-
typeMap.set(name, type.name);
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
return typeMap;
|
|
116
|
-
}, [introspectionData]);
|
|
117
|
-
|
|
118
|
-
// Run the category query immediately and whenever its variable values change.
|
|
119
|
-
useEffect(() => {
|
|
120
|
-
// Wait until we have the type map to fetch product data.
|
|
121
|
-
if (!filterTypeMap.size || !pageSize) {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const filters = getFiltersFromSearch(search);
|
|
126
|
-
|
|
127
|
-
// Construct the filter arg object.
|
|
128
|
-
const newFilters = {};
|
|
129
|
-
filters.forEach((values, key) => {
|
|
130
|
-
newFilters[key] = getFilterInput(values, filterTypeMap.get(key));
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Use the category uid for the current category page regardless of the
|
|
134
|
-
// applied filters. Follow-up in PWA-404.
|
|
135
|
-
newFilters['category_uid'] = { eq: id };
|
|
136
|
-
|
|
137
|
-
runQuery({
|
|
138
|
-
variables: {
|
|
139
|
-
currentPage: Number(currentPage),
|
|
140
|
-
id: id,
|
|
141
|
-
filters: newFilters,
|
|
142
|
-
pageSize: Number(pageSize),
|
|
143
|
-
sort: { [currentSort.sortAttribute]: currentSort.sortDirection }
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
}, [
|
|
147
|
-
currentPage,
|
|
148
|
-
currentSort,
|
|
149
|
-
filterTypeMap,
|
|
150
|
-
id,
|
|
151
|
-
pageSize,
|
|
152
|
-
runQuery,
|
|
153
|
-
search
|
|
154
|
-
]);
|
|
155
|
-
|
|
156
|
-
const totalPagesFromData = data
|
|
157
|
-
? data.products.page_info.total_pages
|
|
158
|
-
: null;
|
|
159
|
-
|
|
160
|
-
useEffect(() => {
|
|
161
|
-
setTotalPages(totalPagesFromData);
|
|
162
|
-
return () => {
|
|
163
|
-
setTotalPages(null);
|
|
164
|
-
};
|
|
165
|
-
}, [setTotalPages, totalPagesFromData]);
|
|
166
|
-
|
|
167
|
-
// If we get an error after loading we should try to reset to page 1.
|
|
168
|
-
// If we continue to have errors after that, render an error message.
|
|
169
|
-
useEffect(() => {
|
|
170
|
-
if (error && !categoryLoading && !data && currentPage !== 1) {
|
|
171
|
-
setCurrentPage(1);
|
|
172
|
-
}
|
|
173
|
-
}, [currentPage, error, categoryLoading, setCurrentPage, data]);
|
|
174
|
-
|
|
175
|
-
// Reset the current page back to one (1) when the search string, filters
|
|
176
|
-
// or sort criteria change.
|
|
177
|
-
useEffect(() => {
|
|
178
|
-
// We don't want to compare page value.
|
|
179
|
-
const prevSearch = new URLSearchParams(previousSearch.current);
|
|
180
|
-
const nextSearch = new URLSearchParams(search);
|
|
181
|
-
prevSearch.delete('page');
|
|
182
|
-
nextSearch.delete('page');
|
|
183
|
-
|
|
184
|
-
if (
|
|
185
|
-
prevSearch.toString() !== nextSearch.toString() ||
|
|
186
|
-
previousSort.current.sortAttribute.toString() !==
|
|
187
|
-
currentSort.sortAttribute.toString() ||
|
|
188
|
-
previousSort.current.sortDirection.toString() !==
|
|
189
|
-
currentSort.sortDirection.toString()
|
|
190
|
-
) {
|
|
191
|
-
// The search term changed.
|
|
192
|
-
setCurrentPage(1, true);
|
|
193
|
-
// And update the ref.
|
|
194
|
-
previousSearch.current = search;
|
|
195
|
-
previousSort.current = currentSort;
|
|
196
|
-
}
|
|
197
|
-
}, [currentSort, previousSearch, search, setCurrentPage]);
|
|
198
|
-
|
|
199
|
-
const categoryData = categoryLoading && !data ? null : data;
|
|
200
|
-
const categoryNotFound =
|
|
201
|
-
!categoryLoading && data && data.categories.items.length === 0;
|
|
202
|
-
const metaDescription =
|
|
203
|
-
data &&
|
|
204
|
-
data.categories.items[0] &&
|
|
205
|
-
data.categories.items[0].meta_description
|
|
206
|
-
? data.categories.items[0].meta_description
|
|
207
|
-
: '';
|
|
208
|
-
|
|
209
|
-
// When only categoryLoading is involved, noProductsFound component flashes for a moment
|
|
210
|
-
const loading =
|
|
211
|
-
(introspectionCalled && !categoryCalled) ||
|
|
212
|
-
(categoryLoading && !data) ||
|
|
213
|
-
introspectionLoading;
|
|
214
|
-
|
|
215
|
-
useScrollTopOnChange(currentPage);
|
|
216
|
-
|
|
217
|
-
return {
|
|
218
|
-
error,
|
|
219
|
-
categoryData,
|
|
220
|
-
loading,
|
|
221
|
-
metaDescription,
|
|
222
|
-
pageControl,
|
|
223
|
-
sortProps,
|
|
224
|
-
pageSize,
|
|
225
|
-
categoryNotFound
|
|
226
|
-
};
|
|
227
|
-
};
|
|
1
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { useLocation } from 'react-router-dom';
|
|
3
|
+
import { useLazyQuery, useQuery } from '@apollo/client';
|
|
4
|
+
|
|
5
|
+
import mergeOperations from '@magento/peregrine/lib/util/shallowMerge';
|
|
6
|
+
import { useAppContext } from '@magento/peregrine/lib/context/app';
|
|
7
|
+
import { usePagination } from '@magento/peregrine/lib/hooks/usePagination';
|
|
8
|
+
import { useScrollTopOnChange } from '@magento/peregrine/lib/hooks/useScrollTopOnChange';
|
|
9
|
+
import { useSort } from '@magento/peregrine/lib/hooks/useSort';
|
|
10
|
+
import {
|
|
11
|
+
getFiltersFromSearch,
|
|
12
|
+
getFilterInput
|
|
13
|
+
} from '@magento/peregrine/lib/talons/FilterModal/helpers';
|
|
14
|
+
|
|
15
|
+
import DEFAULT_OPERATIONS from './category.gql';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A [React Hook]{@link https://reactjs.org/docs/hooks-intro.html} that
|
|
19
|
+
* controls the logic for the Category Root Component.
|
|
20
|
+
*
|
|
21
|
+
* @kind function
|
|
22
|
+
*
|
|
23
|
+
* @param {object} props
|
|
24
|
+
* @param {String} props.id - Category uid.
|
|
25
|
+
* @param {GraphQLAST} props.operations.getCategoryQuery - Fetches category using a server query
|
|
26
|
+
* @param {GraphQLAST} props.operations.getFilterInputsQuery - Fetches "allowed" filters using a server query
|
|
27
|
+
* @param {GraphQLAST} props.queries.getStoreConfig - Fetches store configuration using a server query
|
|
28
|
+
*
|
|
29
|
+
* @returns {object} result
|
|
30
|
+
* @returns {object} result.error - Indicates a network error occurred.
|
|
31
|
+
* @returns {object} result.categoryData - Category data.
|
|
32
|
+
* @returns {bool} result.isLoading - Category data loading.
|
|
33
|
+
* @returns {string} result.metaDescription - Category meta description.
|
|
34
|
+
* @returns {object} result.pageControl - Category pagination state.
|
|
35
|
+
* @returns {array} result.sortProps - Category sorting parameters.
|
|
36
|
+
* @returns {number} result.pageSize - Category total pages.
|
|
37
|
+
*/
|
|
38
|
+
export const useCategory = props => {
|
|
39
|
+
const {
|
|
40
|
+
id,
|
|
41
|
+
queries: { getPageSize }
|
|
42
|
+
} = props;
|
|
43
|
+
|
|
44
|
+
const operations = mergeOperations(DEFAULT_OPERATIONS, props.operations);
|
|
45
|
+
const { getCategoryQuery, getFilterInputsQuery } = operations;
|
|
46
|
+
|
|
47
|
+
const { data: pageSizeData } = useQuery(getPageSize, {
|
|
48
|
+
fetchPolicy: 'cache-and-network',
|
|
49
|
+
nextFetchPolicy: 'cache-first'
|
|
50
|
+
});
|
|
51
|
+
const pageSize = pageSizeData && pageSizeData.storeConfig.grid_per_page;
|
|
52
|
+
|
|
53
|
+
const [paginationValues, paginationApi] = usePagination();
|
|
54
|
+
const { currentPage, totalPages } = paginationValues;
|
|
55
|
+
const { setCurrentPage, setTotalPages } = paginationApi;
|
|
56
|
+
|
|
57
|
+
const sortProps = useSort({ sortFromSearch: false });
|
|
58
|
+
const [currentSort] = sortProps;
|
|
59
|
+
|
|
60
|
+
// Keep track of the sort criteria so we can tell when they change.
|
|
61
|
+
const previousSort = useRef(currentSort);
|
|
62
|
+
|
|
63
|
+
const pageControl = {
|
|
64
|
+
currentPage,
|
|
65
|
+
setPage: setCurrentPage,
|
|
66
|
+
totalPages
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const [
|
|
70
|
+
,
|
|
71
|
+
{
|
|
72
|
+
actions: { setPageLoading }
|
|
73
|
+
}
|
|
74
|
+
] = useAppContext();
|
|
75
|
+
|
|
76
|
+
const [runQuery, queryResponse] = useLazyQuery(getCategoryQuery, {
|
|
77
|
+
fetchPolicy: 'cache-and-network',
|
|
78
|
+
nextFetchPolicy: 'cache-first'
|
|
79
|
+
});
|
|
80
|
+
const {
|
|
81
|
+
called: categoryCalled,
|
|
82
|
+
loading: categoryLoading,
|
|
83
|
+
error,
|
|
84
|
+
data
|
|
85
|
+
} = queryResponse;
|
|
86
|
+
const { search } = useLocation();
|
|
87
|
+
|
|
88
|
+
const isBackgroundLoading = !!data && categoryLoading;
|
|
89
|
+
|
|
90
|
+
// Update the page indicator if the GraphQL query is in flight.
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
setPageLoading(isBackgroundLoading);
|
|
93
|
+
}, [isBackgroundLoading, setPageLoading]);
|
|
94
|
+
|
|
95
|
+
// Keep track of the search terms so we can tell when they change.
|
|
96
|
+
const previousSearch = useRef(search);
|
|
97
|
+
|
|
98
|
+
// Get "allowed" filters by intersection of schema and aggregations
|
|
99
|
+
const {
|
|
100
|
+
called: introspectionCalled,
|
|
101
|
+
data: introspectionData,
|
|
102
|
+
loading: introspectionLoading
|
|
103
|
+
} = useQuery(getFilterInputsQuery);
|
|
104
|
+
|
|
105
|
+
// Create a type map we can reference later to ensure we pass valid args
|
|
106
|
+
// to the graphql query.
|
|
107
|
+
// For example: { category_id: 'FilterEqualTypeInput', price: 'FilterRangeTypeInput' }
|
|
108
|
+
const filterTypeMap = useMemo(() => {
|
|
109
|
+
const typeMap = new Map();
|
|
110
|
+
if (introspectionData) {
|
|
111
|
+
introspectionData.__type.inputFields.forEach(({ name, type }) => {
|
|
112
|
+
typeMap.set(name, type.name);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return typeMap;
|
|
116
|
+
}, [introspectionData]);
|
|
117
|
+
|
|
118
|
+
// Run the category query immediately and whenever its variable values change.
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
// Wait until we have the type map to fetch product data.
|
|
121
|
+
if (!filterTypeMap.size || !pageSize) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const filters = getFiltersFromSearch(search);
|
|
126
|
+
|
|
127
|
+
// Construct the filter arg object.
|
|
128
|
+
const newFilters = {};
|
|
129
|
+
filters.forEach((values, key) => {
|
|
130
|
+
newFilters[key] = getFilterInput(values, filterTypeMap.get(key));
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Use the category uid for the current category page regardless of the
|
|
134
|
+
// applied filters. Follow-up in PWA-404.
|
|
135
|
+
newFilters['category_uid'] = { eq: id };
|
|
136
|
+
|
|
137
|
+
runQuery({
|
|
138
|
+
variables: {
|
|
139
|
+
currentPage: Number(currentPage),
|
|
140
|
+
id: id,
|
|
141
|
+
filters: newFilters,
|
|
142
|
+
pageSize: Number(pageSize),
|
|
143
|
+
sort: { [currentSort.sortAttribute]: currentSort.sortDirection }
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}, [
|
|
147
|
+
currentPage,
|
|
148
|
+
currentSort,
|
|
149
|
+
filterTypeMap,
|
|
150
|
+
id,
|
|
151
|
+
pageSize,
|
|
152
|
+
runQuery,
|
|
153
|
+
search
|
|
154
|
+
]);
|
|
155
|
+
|
|
156
|
+
const totalPagesFromData = data
|
|
157
|
+
? data.products.page_info.total_pages
|
|
158
|
+
: null;
|
|
159
|
+
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
setTotalPages(totalPagesFromData);
|
|
162
|
+
return () => {
|
|
163
|
+
setTotalPages(null);
|
|
164
|
+
};
|
|
165
|
+
}, [setTotalPages, totalPagesFromData]);
|
|
166
|
+
|
|
167
|
+
// If we get an error after loading we should try to reset to page 1.
|
|
168
|
+
// If we continue to have errors after that, render an error message.
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
if (error && !categoryLoading && !data && currentPage !== 1) {
|
|
171
|
+
setCurrentPage(1);
|
|
172
|
+
}
|
|
173
|
+
}, [currentPage, error, categoryLoading, setCurrentPage, data]);
|
|
174
|
+
|
|
175
|
+
// Reset the current page back to one (1) when the search string, filters
|
|
176
|
+
// or sort criteria change.
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
// We don't want to compare page value.
|
|
179
|
+
const prevSearch = new URLSearchParams(previousSearch.current);
|
|
180
|
+
const nextSearch = new URLSearchParams(search);
|
|
181
|
+
prevSearch.delete('page');
|
|
182
|
+
nextSearch.delete('page');
|
|
183
|
+
|
|
184
|
+
if (
|
|
185
|
+
prevSearch.toString() !== nextSearch.toString() ||
|
|
186
|
+
previousSort.current.sortAttribute.toString() !==
|
|
187
|
+
currentSort.sortAttribute.toString() ||
|
|
188
|
+
previousSort.current.sortDirection.toString() !==
|
|
189
|
+
currentSort.sortDirection.toString()
|
|
190
|
+
) {
|
|
191
|
+
// The search term changed.
|
|
192
|
+
setCurrentPage(1, true);
|
|
193
|
+
// And update the ref.
|
|
194
|
+
previousSearch.current = search;
|
|
195
|
+
previousSort.current = currentSort;
|
|
196
|
+
}
|
|
197
|
+
}, [currentSort, previousSearch, search, setCurrentPage]);
|
|
198
|
+
|
|
199
|
+
const categoryData = categoryLoading && !data ? null : data;
|
|
200
|
+
const categoryNotFound =
|
|
201
|
+
!categoryLoading && data && data.categories.items.length === 0;
|
|
202
|
+
const metaDescription =
|
|
203
|
+
data &&
|
|
204
|
+
data.categories.items[0] &&
|
|
205
|
+
data.categories.items[0].meta_description
|
|
206
|
+
? data.categories.items[0].meta_description
|
|
207
|
+
: '';
|
|
208
|
+
|
|
209
|
+
// When only categoryLoading is involved, noProductsFound component flashes for a moment
|
|
210
|
+
const loading =
|
|
211
|
+
(introspectionCalled && !categoryCalled) ||
|
|
212
|
+
(categoryLoading && !data) ||
|
|
213
|
+
introspectionLoading;
|
|
214
|
+
|
|
215
|
+
useScrollTopOnChange(currentPage);
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
error,
|
|
219
|
+
categoryData,
|
|
220
|
+
loading,
|
|
221
|
+
metaDescription,
|
|
222
|
+
pageControl,
|
|
223
|
+
sortProps,
|
|
224
|
+
pageSize,
|
|
225
|
+
categoryNotFound
|
|
226
|
+
};
|
|
227
|
+
};
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import { gql } from '@apollo/client';
|
|
2
|
-
|
|
3
|
-
import { ProductDetailsFragment } from './productDetailFragment.gql';
|
|
4
|
-
|
|
5
|
-
export const GET_STORE_CONFIG_DATA = gql`
|
|
6
|
-
query getStoreConfigData {
|
|
7
|
-
# eslint-disable-next-line @graphql-eslint/require-id-when-available
|
|
8
|
-
storeConfig {
|
|
9
|
-
store_code
|
|
10
|
-
product_url_suffix
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
`;
|
|
14
|
-
|
|
15
|
-
export const GET_PRODUCT_DETAIL_QUERY = gql`
|
|
16
|
-
query getProductDetailForProductPage($urlKey: String!) {
|
|
17
|
-
products(filter: { url_key: { eq: $urlKey } }) {
|
|
18
|
-
items {
|
|
19
|
-
id
|
|
20
|
-
uid
|
|
21
|
-
...ProductDetailsFragment
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
${ProductDetailsFragment}
|
|
26
|
-
`;
|
|
27
|
-
|
|
28
|
-
export default {
|
|
29
|
-
getStoreConfigData: GET_STORE_CONFIG_DATA,
|
|
30
|
-
getProductDetailQuery: GET_PRODUCT_DETAIL_QUERY
|
|
31
|
-
};
|
|
1
|
+
import { gql } from '@apollo/client';
|
|
2
|
+
|
|
3
|
+
import { ProductDetailsFragment } from './productDetailFragment.gql';
|
|
4
|
+
|
|
5
|
+
export const GET_STORE_CONFIG_DATA = gql`
|
|
6
|
+
query getStoreConfigData {
|
|
7
|
+
# eslint-disable-next-line @graphql-eslint/require-id-when-available
|
|
8
|
+
storeConfig {
|
|
9
|
+
store_code
|
|
10
|
+
product_url_suffix
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
export const GET_PRODUCT_DETAIL_QUERY = gql`
|
|
16
|
+
query getProductDetailForProductPage($urlKey: String!) {
|
|
17
|
+
products(filter: { url_key: { eq: $urlKey } }) {
|
|
18
|
+
items {
|
|
19
|
+
id
|
|
20
|
+
uid
|
|
21
|
+
...ProductDetailsFragment
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
${ProductDetailsFragment}
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
export default {
|
|
29
|
+
getStoreConfigData: GET_STORE_CONFIG_DATA,
|
|
30
|
+
getProductDetailQuery: GET_PRODUCT_DETAIL_QUERY
|
|
31
|
+
};
|