Skip to content

Commit 147064e

Browse files
author
Marcin Kwiatkowski
authored
refactor: refactored useFacet composable (#587)
1 parent c0f3aeb commit 147064e

File tree

8 files changed

+247
-5
lines changed

8 files changed

+247
-5
lines changed

packages/composables/src/composables/useFacet/_utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// @depracated - moved to theme
2+
13
import { SearchData } from '../../types';
24

35
const buildBreadcrumbsList = (rootCat, bc) => {

packages/composables/src/composables/useFacet/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ const constructSortObject = (sortData: string) => {
5858
return baseData.length > 0 ? Object.fromEntries([baseData]) : {};
5959
};
6060

61+
/**
62+
* @deprecated since version <version?>
63+
*
64+
* @see <add docs link>
65+
*/
6166
const factoryParams = {
6267
// eslint-disable-next-line @typescript-eslint/no-unused-vars
6368
search: async (context: Context, params: ComposableFunctionArgs<FacetSearchResult<any>>) => {

packages/theme/components/AppHeader.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ import {
172172
categoryGetters,
173173
useCart,
174174
useCategorySearch,
175-
useFacet,
176175
wishlistGetters,
177176
} from '@vue-storefront/magento';
178177
import {
@@ -197,6 +196,7 @@ import {
197196
useUiState,
198197
useWishlist,
199198
useUser,
199+
useFacet,
200200
} from '~/composables';
201201
import StoreSwitcher from '~/components/StoreSwitcher.vue';
202202
@@ -224,7 +224,7 @@ export default defineComponent({
224224
result: searchResult,
225225
search: productsSearch,
226226
// loading: productsLoading,
227-
} = useFacet('AppHeader:Products');
227+
} = useFacet();
228228
const {
229229
result: categories,
230230
search: categoriesSearch,

packages/theme/composables/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ export { default as useWishlist } from './useWishlist';
1010
export { default as useUser } from './useUser';
1111
export { default as useForgotPassword } from './useForgotPassword';
1212
export { default as useCategory } from './useCategory';
13+
export { default as useFacet } from './useFacet';
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { SearchData } from './useFacet';
2+
3+
const buildBreadcrumbsList = (rootCat, bc) => {
4+
const newBc = [...bc, {
5+
text: rootCat.name,
6+
link: rootCat.slug,
7+
}];
8+
return rootCat.parent ? buildBreadcrumbsList(rootCat.parent, newBc) : newBc;
9+
};
10+
11+
export const buildBreadcrumbs = (rootCat) => buildBreadcrumbsList(rootCat, [])
12+
.reverse()
13+
.reduce(
14+
(prev, curr, index) => ([
15+
...prev,
16+
{
17+
...curr,
18+
link: `${prev[index - 1]?.link || ''}/${curr.link}`,
19+
}]),
20+
[],
21+
);
22+
23+
const filterFacets = (criteria) => (f) => (criteria ? criteria.includes(f.attribute_code) : true);
24+
25+
const getFacetTypeByCode = (code) => {
26+
if (code === 'type_of_stones') {
27+
return 'radio';
28+
}
29+
return 'checkbox';
30+
};
31+
32+
const createFacetsFromOptions = (facets, filters, facet) => {
33+
const options = facet.options || [];
34+
const selectedList = filters && filters[facet.attribute_code] ? filters[facet.attribute_code] : [];
35+
return options
36+
.map(({
37+
label,
38+
value,
39+
count,
40+
}) => ({
41+
type: getFacetTypeByCode(facet.attribute_code),
42+
id: label,
43+
attrName: label,
44+
value,
45+
selected: selectedList.includes(value),
46+
count,
47+
}));
48+
};
49+
50+
export const reduceForFacets = (facets, filters) => (prev, curr) => ([
51+
...prev,
52+
...createFacetsFromOptions(facets, filters, curr),
53+
]);
54+
55+
export const reduceForGroupedFacets = (facets, filters) => (prev, curr) => ([
56+
...prev,
57+
{
58+
id: curr.attribute_code,
59+
label: curr.label,
60+
options: createFacetsFromOptions(facets, filters, curr),
61+
count: null,
62+
},
63+
]);
64+
65+
export const buildFacets = (searchData: SearchData, reduceFn, criteria?: string[]) => {
66+
if (!searchData.data) {
67+
return [];
68+
}
69+
70+
const {
71+
data: { availableFilters: facets },
72+
input: { filters },
73+
} = searchData;
74+
75+
return facets?.filter(filterFacets(criteria)).reduce(reduceFn(facets, filters), []);
76+
};
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import { Ref, ref, useContext } from '@nuxtjs/composition-api';
2+
import {
3+
AgnosticFacetSearchParams, ComposableFunctionArgs, Logger, ProductsSearchParams } from '@vue-storefront/core';
4+
import { FacetSearchResult, UseFacet, UseFacetErrors} from './useFacet';
5+
import { GetProductSearchParams } from '@vue-storefront/magento-api/src/types/API';
6+
7+
const availableSortingOptions = [
8+
{
9+
label: 'Sort: Default',
10+
value: '',
11+
},
12+
{
13+
label: 'Sort: Name A-Z',
14+
value: 'name_ASC',
15+
},
16+
{
17+
label: 'Sort: Name Z-A',
18+
value: 'name_DESC',
19+
},
20+
{
21+
label: 'Sort: Price from low to high',
22+
value: 'price_ASC',
23+
}, {
24+
label: 'Sort: Price from high to low',
25+
value: 'price_DESC',
26+
},
27+
];
28+
29+
const constructFilterObject = (inputFilters: Object) => {
30+
const filter = {};
31+
32+
Object.keys(inputFilters).forEach((key) => {
33+
if (key === 'price') {
34+
const price = { from: 0, to: 0 };
35+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
36+
const flatPrices = inputFilters[key].flatMap((inputFilter) => inputFilter.split('_').map((str) => Number.parseFloat(str))).sort((a, b) => a - b);
37+
38+
[price.from] = flatPrices;
39+
price.to = flatPrices[flatPrices.length - 1];
40+
41+
filter[key] = price;
42+
} else if (typeof inputFilters[key] === 'string') {
43+
filter[key] = { in: [inputFilters[key]] };
44+
} else {
45+
filter[key] = { in: inputFilters[key] };
46+
}
47+
});
48+
49+
return filter;
50+
};
51+
52+
const constructSortObject = (sortData: string) => {
53+
const baseData = sortData.split(/_/gi);
54+
55+
return baseData.length > 0 ? Object.fromEntries([baseData]) : {};
56+
};
57+
58+
export const useFacet = (): UseFacet => {
59+
const { app } = useContext();
60+
const loading: Ref<boolean> = ref(false);
61+
const result: Ref<FacetSearchResult<any>> = ref({ data: null, input: null });
62+
const error: Ref<UseFacetErrors> = ref({
63+
search: null,
64+
});
65+
66+
const search = async (params?: ComposableFunctionArgs<AgnosticFacetSearchParams>) => {
67+
Logger.debug('useFacet/search', params);
68+
69+
result.value.input = params;
70+
try {
71+
loading.value = true;
72+
73+
const itemsPerPage = (params.itemsPerPage) ? params.itemsPerPage : 20;
74+
const inputFilters = (params.filters) ? params.filters : {};
75+
const categoryId = (params.categoryId) ? {
76+
category_uid: {
77+
...(Array.isArray(params.categoryId)
78+
? { in: params.categoryId }
79+
: { eq: params.categoryId }),
80+
},
81+
} : {};
82+
83+
const productParams: ProductsSearchParams = {
84+
filter: {
85+
...categoryId,
86+
...constructFilterObject({
87+
...inputFilters,
88+
}),
89+
},
90+
perPage: itemsPerPage,
91+
offset: (params.page - 1) * itemsPerPage,
92+
page: params.page,
93+
search: (params.term) ? params.term : '',
94+
sort: constructSortObject(params.sort || ''),
95+
};
96+
97+
const productSearchParams: GetProductSearchParams = {
98+
pageSize: productParams.perPage,
99+
search: productParams.search,
100+
filter: productParams.filter,
101+
sort: productParams.sort,
102+
currentPage: productParams.page,
103+
};
104+
105+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
106+
const { data } = await app.context.$vsf.$magento.api.products(productSearchParams, params?.customQuery || { products: 'products' });
107+
108+
Logger.debug('[Result]:', { data });
109+
110+
result.value.data = {
111+
items: data?.products?.items || [],
112+
total: data?.products?.total_count,
113+
availableFilters: data?.products?.aggregations,
114+
category: { id: params.categoryId },
115+
availableSortingOptions,
116+
perPageOptions: [10, 20, 50],
117+
itemsPerPage,
118+
};
119+
error.value.search = null;
120+
} catch (err) {
121+
error.value.search = err;
122+
Logger.error(`useFacet/search`, err);
123+
} finally {
124+
loading.value = false;
125+
}
126+
};
127+
128+
return {
129+
result,
130+
loading,
131+
error,
132+
search,
133+
};
134+
};
135+
136+
export default useFacet;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { AgnosticFacetSearchParams, ComposableFunctionArgs} from '@vue-storefront/core';
2+
import { Ref } from '@nuxtjs/composition-api';
3+
// @ts-ignore
4+
import { FacetResultsData } from '@vue-storefront/magento/types';
5+
6+
export interface FacetSearchResult<S> {
7+
data: S;
8+
input: AgnosticFacetSearchParams;
9+
}
10+
11+
export interface UseFacetErrors {
12+
search: Error;
13+
}
14+
15+
16+
export type SearchData = FacetSearchResult<FacetResultsData>;
17+
18+
export interface UseFacet {
19+
result: Ref<FacetSearchResult<FacetResultsData>>;
20+
loading: Ref<boolean>;
21+
search: (params?: ComposableFunctionArgs<AgnosticFacetSearchParams>) => Promise<void>;
22+
error: Ref<UseFacetErrors>;
23+
}

packages/theme/pages/Category.vue

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -425,13 +425,12 @@ import {
425425
categoryGetters,
426426
facetGetters,
427427
productGetters,
428-
useFacet,
429428
} from '@vue-storefront/magento';
430429
import { onSSR, useVSFContext } from '@vue-storefront/core';
431430
import { useCache, CacheTagPrefix } from '@vue-storefront/cache';
432431
import { useUrlResolver } from '~/composables/useUrlResolver.ts';
433432
import {
434-
useUiHelpers, useUiState, useImage, useWishlist, useUser, useCategory,
433+
useUiHelpers, useUiState, useImage, useWishlist, useUser, useCategory, useFacet
435434
} from '~/composables';
436435
import cacheControl from '~/helpers/cacheControl';
437436
import { useAddToCart } from '~/helpers/cart/addToCart';
@@ -484,7 +483,7 @@ export default defineComponent({
484483
const {
485484
result,
486485
search,
487-
} = useFacet(`facetId:${path}`);
486+
} = useFacet();
488487
const { toggleFilterSidebar } = useUiState();
489488
const {
490489
categories,

0 commit comments

Comments
 (0)