Experimental filters: filter presets & date fixes (#4030)
This commit is contained in:
parent
5087dec2d5
commit
e033d6bf99
9 changed files with 41 additions and 24 deletions
5
.changeset/grumpy-eagles-sing.md
Normal file
5
.changeset/grumpy-eagles-sing.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"saleor-dashboard": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Experimental filters: filter presets & date fixes
|
|
@ -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;
|
|
||||||
};
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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" }],
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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") {
|
||||||
|
|
|
@ -159,6 +159,7 @@ export const FilterPresetsSelect = ({
|
||||||
onRemove={() => {
|
onRemove={() => {
|
||||||
onRemove(index + 1);
|
onRemove(index + 1);
|
||||||
}}
|
}}
|
||||||
|
key={`filter-preset-${index}`}
|
||||||
>
|
>
|
||||||
{preset}
|
{preset}
|
||||||
</FilterPresetItem>
|
</FilterPresetItem>
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue