Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changed filters of aggregations query in PLP #4362

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Object {
"availableSortMethods": null,
"categoryDescription": "Jewelry category",
"categoryName": "Jewelry",
"filterOptions": undefined,
"filters": null,
"items": Array [
null,
Expand All @@ -17,6 +18,7 @@ Object {
null,
null,
],
"setFilterOptions": [Function],
"totalCount": null,
"totalPagesFromData": null,
}
Expand All @@ -32,6 +34,7 @@ Object {
],
"categoryDescription": "Jewelry category",
"categoryName": "Jewelry",
"filterOptions": undefined,
"filters": Array [
Object {
"label": "Label",
Expand All @@ -47,6 +50,7 @@ Object {
"name": "Necklace",
},
],
"setFilterOptions": [Function],
"totalCount": 2,
"totalPagesFromData": 1,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ jest.mock('@apollo/client', () => {
};
});

const mockGetFiltersAttributeCode = {
data: {
products: {
aggregations: [
{
label: 'Label'
}
]
}
}
};

const mockProductFiltersByCategoryData = {
data: {
products: {
Expand Down Expand Up @@ -91,21 +103,22 @@ const mockCategoryData = {

const mockGetSortMethods = jest.fn();
const mockGetFilters = jest.fn();
const mockfilterData = jest.fn();

jest.mock('@magento/peregrine/lib/context/eventing', () => ({
useEventingContext: jest.fn().mockReturnValue([{}, { dispatch: jest.fn() }])
}));

const Component = props => {
const talonprops = useCategoryContent(props);

return <i {...talonprops} />;
};

useQuery.mockReturnValue({ data: mockCategoryData });
describe('useCategoryContent tests', () => {
it('returns the proper shape', () => {
useLazyQuery
.mockReturnValueOnce([mockfilterData, mockGetFiltersAttributeCode])
.mockReturnValueOnce([
mockGetFilters,
mockProductFiltersByCategoryData
Expand All @@ -124,6 +137,7 @@ describe('useCategoryContent tests', () => {

it('handles default category id', () => {
useLazyQuery
.mockReturnValueOnce([mockfilterData, mockGetFiltersAttributeCode])
.mockReturnValueOnce([
mockGetFilters,
mockProductFiltersByCategoryData
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { gql } from '@apollo/client';

export const GET_PRODUCT_FILTERS_BY_CATEGORY = gql`
query getProductFiltersByCategory(
$categoryIdFilter: FilterEqualTypeInput!
) {
products(filter: { category_uid: $categoryIdFilter }) {
query getProductFiltersByCategory($filters: ProductAttributeFilterInput!) {
products(filter: $filters) {
aggregations {
label
count
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { useEffect, useState, useMemo } from 'react';
import { useLazyQuery, useQuery } from '@apollo/client';

import mergeOperations from '../../../util/shallowMerge';
Expand Down Expand Up @@ -29,6 +29,92 @@ export const useCategoryContent = props => {
getCategoryAvailableSortMethodsQuery
} = operations;

const [
getFiltersAttributeCode,
{ data: filterAttributeData }
] = useLazyQuery(getProductFiltersByCategoryQuery, {
fetchPolicy: 'cache-and-network',
nextFetchPolicy: 'cache-first'
});

useEffect(() => {
if (categoryId) {
getFiltersAttributeCode({
variables: {
filters: {
category_uid: { eq: categoryId }
}
}
});
}
}, [categoryId, getFiltersAttributeCode]);

const availableFilterData = filterAttributeData
? filterAttributeData.products?.aggregations
: null;
const availableFilters = availableFilterData
?.map(eachitem => eachitem.attribute_code)
?.sort();

const handlePriceFilter = priceFilter => {
if (priceFilter && priceFilter.size > 0) {
for (const price of priceFilter) {
const [from, to] = price.value.split('_');
return { price: { from, to } };
}
}
return {};
};

const [filterOptions, setFilterOptions] = useState();

const selectedFilters = useMemo(() => {
const filters = {};
if (filterOptions) {
for (const [group, items] of filterOptions.entries()) {
availableFilters?.map(eachitem => {
if (eachitem === group && group !== 'price') {
const sampleArray = [];
for (const item of items) {
sampleArray.push(item.value);
}
filters[group] = sampleArray;
}
});
}
}

if (filterOptions && filterOptions.has('price')) {
const priceFilter = filterOptions.get('price');
const priceRange = handlePriceFilter(priceFilter);
if (priceRange.price) {
filters.price = priceRange.price;
}
}

return filters;
}, [filterOptions, availableFilters]);

const dynamicQueryVariables = useMemo(() => {
const generateDynamicFiltersQuery = filterParams => {
let filterConditions = {
category_uid: { eq: categoryId }
};

Object.keys(filterParams).forEach(key => {
let filter = {};
if (key !== 'price') {
filter = { [key]: { in: filterParams[key] } };
}
filterConditions = { ...filterConditions, ...filter };
});

return filterConditions;
};

return generateDynamicFiltersQuery(selectedFilters);
}, [selectedFilters, categoryId]);

const placeholderItems = Array.from({ length: pageSize }).fill(null);

const [getFilters, { data: filterData }] = useLazyQuery(
Expand Down Expand Up @@ -60,18 +146,26 @@ export const useCategoryContent = props => {
);

const [, { dispatch }] = useEventingContext();

const [previousFilters, setPreviousFilters] = useState(null);
useEffect(() => {
if (categoryId) {
if (
categoryId &&
JSON.stringify(selectedFilters) !== JSON.stringify(previousFilters)
) {
getFilters({
variables: {
categoryIdFilter: {
eq: categoryId
}
filters: dynamicQueryVariables
}
});
setPreviousFilters(selectedFilters);
}
}, [categoryId, getFilters]);
}, [
categoryId,
selectedFilters,
dynamicQueryVariables,
previousFilters,
getFilters
]);

useEffect(() => {
if (categoryId) {
Expand All @@ -85,7 +179,7 @@ export const useCategoryContent = props => {
}
}, [categoryId, getSortMethods]);

const filters = filterData ? filterData.products.aggregations : null;
const filters = filterData ? filterData.products?.aggregations : null;
const items = data ? data.products.items : placeholderItems;
const totalPagesFromData = data
? data.products.page_info.total_pages
Expand All @@ -104,7 +198,7 @@ export const useCategoryContent = props => {
: null;

useEffect(() => {
if (!categoryLoading && categoryData.categories.items.length > 0) {
if (!categoryLoading && categoryData?.categories.items.length > 0) {
dispatch({
type: 'CATEGORY_PAGE_VIEW',
payload: {
Expand All @@ -122,6 +216,8 @@ export const useCategoryContent = props => {
categoryName,
categoryDescription,
filters,
filterOptions,
setFilterOptions,
items,
totalCount,
totalPagesFromData
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const CategoryContent = props => {
categoryName,
categoryDescription,
filters,
setFilterOptions,
items,
totalCount,
totalPagesFromData
Expand Down Expand Up @@ -79,7 +80,7 @@ const CategoryContent = props => {
) : null;

const sidebar = shouldShowFilterButtons ? (
<FilterSidebar filters={filters} />
<FilterSidebar filters={filters} setFilterOptions={setFilterOptions} />
) : shouldShowFilterShimmer ? (
<FilterSidebarShimmer />
) : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ const mockHandleApply = jest.fn();

const mockScrollTo = jest.fn();

const mockFilterOptions = jest.fn();

const mockGetBoundingClientRect = jest.fn();

let mockFilterState;
Expand Down Expand Up @@ -125,21 +127,24 @@ const Component = () => {

const givenDefaultValues = () => {
inputProps = {
filters: []
filters: [],
setFilterOptions: mockFilterOptions
};

mockFilterState = new Map();
};

const givenFilters = () => {
inputProps = {
filters: mockFilters
filters: mockFilters,
setFilterOptions: mockFilterOptions
};
};

const givenSelectedFilters = () => {
inputProps = {
filters: mockFilters
filters: mockFilters,
setFilterOptions: mockFilterOptions
};

mockFilterState = new Map([['group', 'item']]);
Expand All @@ -148,7 +153,8 @@ const givenSelectedFilters = () => {
const givenFiltersAndAmountToShow = () => {
inputProps = {
filters: mockFilters,
filterCountToOpen: mockFiltersOpenCount
filterCountToOpen: mockFiltersOpenCount,
setFilterOptions: mockFilterOptions
};
};

Expand Down
10 changes: 8 additions & 2 deletions packages/venia-ui/lib/components/FilterSidebar/filterSidebar.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo, useCallback, useRef } from 'react';
import React, { useMemo, useCallback, useRef, useEffect } from 'react';
import { FormattedMessage } from 'react-intl';
import { array, arrayOf, shape, string, number } from 'prop-types';
import { useFilterSidebar } from '@magento/peregrine/lib/talons/FilterSidebar';
Expand All @@ -17,7 +17,7 @@ const SCROLL_OFFSET = 150;
* @param {Object} props.filters - filters to display
*/
const FilterSidebar = props => {
const { filters, filterCountToOpen } = props;
const { filters, filterCountToOpen, setFilterOptions } = props;
const talonProps = useFilterSidebar({ filters });
const {
filterApi,
Expand Down Expand Up @@ -50,6 +50,12 @@ const FilterSidebar = props => {
[handleApply, filterRef]
);

useEffect(() => {
if (filterState) {
setFilterOptions(filterState);
}
}, [filterState, setFilterOptions]);

const filtersList = useMemo(
() =>
Array.from(filterItems, ([group, items], iteration) => {
Expand Down