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