Fix numeric attribute filters (#2145)
* Handle numeric attribute filters * Fix filter behaviour * Backwards compatibility
This commit is contained in:
parent
1a974e380c
commit
4ee9e4fc59
5 changed files with 36 additions and 9 deletions
|
@ -35,6 +35,9 @@ export const FilterSingleSelectField: React.FC<FilterSingleSelectFieldProps> = (
|
|||
name: filter.name,
|
||||
update: {
|
||||
multiple: event.target.value === FilterType.MULTIPLE,
|
||||
...(event.target.value !== FilterType.MULTIPLE && {
|
||||
value: filter.value.slice(0, 1) as string[],
|
||||
}),
|
||||
},
|
||||
},
|
||||
type: "set-property",
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
createDateField,
|
||||
createDateTimeField,
|
||||
createKeyValueField,
|
||||
createNumberField,
|
||||
createOptionsField,
|
||||
createPriceField,
|
||||
} from "@saleor/utils/filters/fields";
|
||||
|
@ -121,6 +122,9 @@ export function createFilterStructure(
|
|||
const dateTimeAttributes = attributes.filter(
|
||||
filterByType(AttributeInputTypeEnum.DATE_TIME),
|
||||
);
|
||||
const numericAttributes = attributes.filter(
|
||||
filterByType(AttributeInputTypeEnum.NUMERIC),
|
||||
);
|
||||
|
||||
const defaultAttributes = opts.attributes.filter(
|
||||
({ inputType }) =>
|
||||
|
@ -128,6 +132,7 @@ export function createFilterStructure(
|
|||
AttributeInputTypeEnum.BOOLEAN,
|
||||
AttributeInputTypeEnum.DATE,
|
||||
AttributeInputTypeEnum.DATE_TIME,
|
||||
AttributeInputTypeEnum.NUMERIC,
|
||||
].includes(inputType),
|
||||
);
|
||||
|
||||
|
@ -273,6 +278,14 @@ export function createFilterStructure(
|
|||
active: attr.active,
|
||||
group: ProductFilterKeys.attributes,
|
||||
})),
|
||||
...numericAttributes.map(attr => ({
|
||||
...createNumberField(attr.slug, attr.name, {
|
||||
min: attr.value[0],
|
||||
max: attr.value[1] ?? attr.value[0],
|
||||
}),
|
||||
active: attr.active,
|
||||
group: ProductFilterKeys.attributes,
|
||||
})),
|
||||
...defaultAttributes.map(attr => ({
|
||||
...createAutocompleteField(
|
||||
attr.slug,
|
||||
|
|
|
@ -467,8 +467,8 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
|||
confirmButtonState={exportProductsOpts.status}
|
||||
errors={exportProductsOpts.data?.exportProducts.errors || []}
|
||||
productQuantity={{
|
||||
all: countAllProducts.data?.products.totalCount,
|
||||
filter: data?.products.totalCount,
|
||||
all: countAllProducts.data?.products?.totalCount,
|
||||
filter: data?.products?.totalCount,
|
||||
}}
|
||||
selectedProducts={listElements.length}
|
||||
warehouses={mapEdgesToItems(warehouses?.data?.warehouses) || []}
|
||||
|
|
|
@ -27,7 +27,6 @@ import {
|
|||
mapNodeToChoice,
|
||||
mapSlugNodeToChoice,
|
||||
} from "@saleor/utils/maps";
|
||||
import isArray from "lodash/isArray";
|
||||
import moment from "moment-timezone";
|
||||
|
||||
import {
|
||||
|
@ -238,12 +237,12 @@ const parseFilterValue = (
|
|||
params: ProductListUrlFilters,
|
||||
key: string,
|
||||
): {
|
||||
type: "boolean" | "date" | "dateTime" | "string";
|
||||
type: "boolean" | "date" | "dateTime" | "numeric" | "string";
|
||||
isMulti: boolean;
|
||||
value: string[];
|
||||
} => {
|
||||
const value = params.attributes[key];
|
||||
const isMulti = isArray(params.attributes[key]);
|
||||
const isMulti = params.attributes[key].length > 1;
|
||||
|
||||
const isBooleanValue = value.every(val => val === "true" || val === "false");
|
||||
const isDateValue = (isMulti ? value : [value]).some(val =>
|
||||
|
@ -252,8 +251,9 @@ const parseFilterValue = (
|
|||
const isDateTimeValue = (isMulti ? value : [value]).some(val =>
|
||||
moment(val, moment.ISO_8601, true).isValid(),
|
||||
);
|
||||
const isNumericValue = value.some(value => !isNaN(parseFloat(value)));
|
||||
|
||||
const data = { isMulti, value: (isMulti ? value : [value]) as string[] };
|
||||
const data = { isMulti, value };
|
||||
|
||||
if (isBooleanValue) {
|
||||
return { ...data, type: "boolean" };
|
||||
|
@ -261,6 +261,8 @@ const parseFilterValue = (
|
|||
return { ...data, type: "date" };
|
||||
} else if (isDateTimeValue) {
|
||||
return { ...data, type: "dateTime" };
|
||||
} else if (isNumericValue) {
|
||||
return { ...data, type: "numeric" };
|
||||
}
|
||||
return { ...data, type: "string" };
|
||||
};
|
||||
|
@ -317,6 +319,15 @@ function getFilteredAttributeValue(
|
|||
}),
|
||||
};
|
||||
|
||||
case "numeric":
|
||||
return {
|
||||
...name,
|
||||
valuesRange: {
|
||||
gte: value[0] || undefined,
|
||||
lte: isMulti ? value[1] || undefined : value[0] || undefined,
|
||||
},
|
||||
};
|
||||
|
||||
default:
|
||||
return { ...name, values: value };
|
||||
}
|
||||
|
|
|
@ -70,15 +70,15 @@ export function createDateTimeField<K extends string>(
|
|||
export function createNumberField<K extends string>(
|
||||
name: K,
|
||||
label: string,
|
||||
defaultValue: MinMax,
|
||||
value: MinMax,
|
||||
): FilterElementGeneric<K, FieldType.number> {
|
||||
return {
|
||||
active: false,
|
||||
label,
|
||||
multiple: true,
|
||||
multiple: value.min !== value.max,
|
||||
name,
|
||||
type: FieldType.number,
|
||||
value: [defaultValue.min, defaultValue.max],
|
||||
value: [value.min, value.max],
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue