Experimental filters: filter presets & date fixes (#4030)

This commit is contained in:
Krzysztof Żuraw 2023-07-28 13:43:58 +02:00 committed by GitHub
parent 5087dec2d5
commit e033d6bf99
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 41 additions and 24 deletions

View file

@ -0,0 +1,5 @@
---
"saleor-dashboard": patch
---
Experimental filters: filter presets & date fixes

View file

@ -1,5 +1,4 @@
import { parse, ParsedQs } from "qs"; import { parse, ParsedQs } from "qs";
import { useRef } from "react";
import { InitialStateResponse } from "../../API/InitialStateResponse"; import { InitialStateResponse } from "../../API/InitialStateResponse";
import { FilterContainer, FilterElement } from "../../FilterElement"; import { FilterContainer, FilterElement } from "../../FilterElement";
@ -91,13 +90,3 @@ export class TokenArray extends Array<string | UrlToken | TokenArray> {
}); });
} }
} }
export const useTokenArray = (url: string) => {
const instance = useRef<TokenArray | null>(null);
if (!instance.current) {
instance.current = new TokenArray(url);
}
return instance.current;
};

View file

@ -5,7 +5,7 @@ import useRouter from "use-react-router";
import { InitialAPIState } from "../API"; import { InitialAPIState } from "../API";
import { FilterContainer, FilterElement } from "../FilterElement"; import { FilterContainer, FilterElement } from "../FilterElement";
import { FilterValueProvider } from "../FilterValueProvider"; import { FilterValueProvider } from "../FilterValueProvider";
import { useTokenArray } from "./TokenArray"; import { TokenArray } from "./TokenArray";
import { UrlEntry } from "./UrlToken"; import { UrlEntry } from "./UrlToken";
type Structure = Array<string | UrlEntry | Structure>; type Structure = Array<string | UrlEntry | Structure>;
@ -25,20 +25,22 @@ const prepareStructure = (filterValue: FilterContainer): Structure =>
export const useUrlValueProvider = ( export const useUrlValueProvider = (
initialState: InitialAPIState, initialState: InitialAPIState,
locationSearch: string,
): FilterValueProvider => { ): FilterValueProvider => {
const router = useRouter(); const router = useRouter();
const params = new URLSearchParams(router.location.search); const params = new URLSearchParams(locationSearch);
const { data, loading, fetchQueries } = initialState; const { data, loading, fetchQueries } = initialState;
const [value, setValue] = useState<FilterContainer>([]); const [value, setValue] = useState<FilterContainer>([]);
params.delete("asc"); params.delete("asc");
params.delete("sort"); params.delete("sort");
const tokenizedUrl = useTokenArray(params.toString()); const tokenizedUrl = new TokenArray(params.toString());
const fetchingParams = tokenizedUrl.getFetchingParams(); const fetchingParams = tokenizedUrl.getFetchingParams();
useEffect(() => { useEffect(() => {
fetchQueries(fetchingParams); fetchQueries(fetchingParams);
}, []); }, [locationSearch]);
useEffect(() => { useEffect(() => {
if (loading) return; if (loading) return;

View file

@ -93,11 +93,13 @@ export const ATTRIBUTE_INPUT_TYPE_CONDITIONS = {
{ type: "number.range", label: "between", value: "input-4" }, { type: "number.range", label: "between", value: "input-4" },
], ],
DATE_TIME: [ DATE_TIME: [
{ type: "datetime", label: "is", value: "input-1" }, { type: "datetime", label: "lower", value: "input-2" },
{ type: "datetime", label: "greater", value: "input-3" },
{ type: "datetime.range", label: "between", value: "input-4" }, { type: "datetime.range", label: "between", value: "input-4" },
], ],
DATE: [ DATE: [
{ type: "date", label: "is", value: "input-1" }, { type: "date", label: "lower", value: "input-1" },
{ type: "date", label: "greater", value: "input-2" },
{ type: "date.range", label: "between", value: "input-4" }, { type: "date.range", label: "between", value: "input-4" },
], ],
SWATCH: [{ type: "multiselect", label: "in", value: "input-2" }], SWATCH: [{ type: "multiselect", label: "in", value: "input-2" }],

View file

@ -7,10 +7,12 @@ import { useFilterLeftOperandsProvider } from "../useFilterLeftOperands";
import { useUrlValueProvider } from "../ValueProvider/useUrlValueProvider"; import { useUrlValueProvider } from "../ValueProvider/useUrlValueProvider";
import { ConditionalFilterContext } from "./context"; import { ConditionalFilterContext } from "./context";
export const ConditionalProductFilterProvider: FC = ({ children }) => { export const ConditionalProductFilterProvider: FC<{
locationSearch: string;
}> = ({ children, locationSearch }) => {
const apiProvider = useProductFilterAPIProvider(); const apiProvider = useProductFilterAPIProvider();
const initialState = useProductInitialAPIState(); const initialState = useProductInitialAPIState();
const valueProvider = useUrlValueProvider(initialState); const valueProvider = useUrlValueProvider(initialState, locationSearch);
const leftOperandsProvider = useFilterLeftOperandsProvider(); const leftOperandsProvider = useFilterLeftOperandsProvider();
const containerState = useContainerState(valueProvider); const containerState = useContainerState(valueProvider);

View file

@ -35,7 +35,7 @@ const createStaticQueryPart = (
} }
if (isTuple(value) && label === "between") { if (isTuple(value) && label === "between") {
const [lte, gte] = value; const [gte, lte] = value;
return { range: { lte, gte } }; return { range: { lte, gte } };
} }
@ -59,7 +59,7 @@ const createStaticQueryPart = (
}; };
const getRangeQueryPartByType = (value: [string, string], type: string) => { const getRangeQueryPartByType = (value: [string, string], type: string) => {
const [lte, gte] = value; const [gte, lte] = value;
switch (type) { switch (type) {
case "datetime.range": case "datetime.range":
@ -72,6 +72,21 @@ const getRangeQueryPartByType = (value: [string, string], type: string) => {
} }
}; };
const getQueryPartByType = (
value: string,
type: string,
what: "lte" | "gte",
) => {
switch (type) {
case "datetime":
return { dateTime: { [what]: value } };
case "date":
return { date: { [what]: value } };
default:
return { valuesRange: { [what]: parseFloat(value) } };
}
};
const createAttributeQueryPart = ( const createAttributeQueryPart = (
attributeSlug: string, attributeSlug: string,
selected: ConditionSelected, selected: ConditionSelected,
@ -82,11 +97,11 @@ const createAttributeQueryPart = (
const { value } = selected; const { value } = selected;
if (label === "lower" && typeof value === "string") { if (label === "lower" && typeof value === "string") {
return { slug: attributeSlug, valuesRange: { lte: parseFloat(value) } }; return { slug: attributeSlug, ...getQueryPartByType(value, type, "lte") };
} }
if (label === "greater" && typeof value === "string") { if (label === "greater" && typeof value === "string") {
return { slug: attributeSlug, valuesRange: { gte: parseFloat(value) } }; return { slug: attributeSlug, ...getQueryPartByType(value, type, "gte") };
} }
if (isTuple(value) && label === "between") { if (isTuple(value) && label === "between") {

View file

@ -159,6 +159,7 @@ export const FilterPresetsSelect = ({
onRemove={() => { onRemove={() => {
onRemove(index + 1); onRemove(index + 1);
}} }}
key={`filter-preset-${index}`}
> >
{preset} {preset}
</FilterPresetItem> </FilterPresetItem>

View file

@ -45,7 +45,7 @@ const ProductList: React.FC<RouteComponentProps<any>> = ({ location }) => {
); );
return ( return (
<ConditionalProductFilterProvider> <ConditionalProductFilterProvider locationSearch={location.search}>
<ProductListComponent params={params} /> <ProductListComponent params={params} />
</ConditionalProductFilterProvider> </ConditionalProductFilterProvider>
); );

View file

@ -66,6 +66,7 @@ export function getSortQueryVariables(
} }
const field = getSortQueryField(params.sort); const field = getSortQueryField(params.sort);
// TODO: how to handle search & sort
return { return {
direction, direction,
field, field,