Experimental filters: Add API types and handlers (#3841)
This commit is contained in:
parent
8d425700eb
commit
fec476b7e2
7 changed files with 236 additions and 191 deletions
5
.changeset/silent-hornets-sell.md
Normal file
5
.changeset/silent-hornets-sell.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"saleor-dashboard": minor
|
||||
---
|
||||
|
||||
Add API handlers to expermiental filters
|
168
src/components/ConditionalFilter/API/Handler.ts
Normal file
168
src/components/ConditionalFilter/API/Handler.ts
Normal file
|
@ -0,0 +1,168 @@
|
|||
import { ApolloClient } from "@apollo/client";
|
||||
import {
|
||||
_GetAttributeChoicesDocument,
|
||||
_GetAttributeChoicesQuery,
|
||||
_GetAttributeChoicesQueryVariables,
|
||||
_GetCategoriesChoicesDocument,
|
||||
_GetCategoriesChoicesQuery,
|
||||
_GetCategoriesChoicesQueryVariables,
|
||||
_GetChannelOperandsDocument,
|
||||
_GetChannelOperandsQuery,
|
||||
_GetChannelOperandsQueryVariables,
|
||||
_GetCollectionsChoicesDocument,
|
||||
_GetCollectionsChoicesQuery,
|
||||
_GetCollectionsChoicesQueryVariables,
|
||||
_GetDynamicLeftOperandsDocument,
|
||||
_GetDynamicLeftOperandsQuery,
|
||||
_GetDynamicLeftOperandsQueryVariables,
|
||||
_GetProductTypesChoicesDocument,
|
||||
_GetProductTypesChoicesQuery,
|
||||
_GetProductTypesChoicesQueryVariables,
|
||||
} from "@dashboard/graphql";
|
||||
|
||||
import { ItemOption } from "../FilterElement/ConditionSelected";
|
||||
|
||||
export interface Handler {
|
||||
client: ApolloClient<unknown>;
|
||||
query: string;
|
||||
fetch: () => Promise<ItemOption[]>;
|
||||
}
|
||||
|
||||
const createOptionsFromAPI = (
|
||||
// TODO: try to use type from graphql
|
||||
data: Array<{ node: { name: string | null; id: string; slug: string } }>,
|
||||
): ItemOption[] =>
|
||||
data.map(({ node }) => ({
|
||||
label: node.name ?? "",
|
||||
value: node.id,
|
||||
slug: node.slug,
|
||||
}));
|
||||
|
||||
export class AttributeChoicesHandler implements Handler {
|
||||
constructor(
|
||||
public client: ApolloClient<unknown>,
|
||||
public attributeSlug: string,
|
||||
public query: string,
|
||||
) {}
|
||||
|
||||
fetch = async () => {
|
||||
const { client, attributeSlug, query } = this;
|
||||
const { data } = await client.query<
|
||||
_GetAttributeChoicesQuery,
|
||||
_GetAttributeChoicesQueryVariables
|
||||
>({
|
||||
query: _GetAttributeChoicesDocument,
|
||||
variables: {
|
||||
slug: attributeSlug,
|
||||
first: 5,
|
||||
query,
|
||||
},
|
||||
});
|
||||
return createOptionsFromAPI(data.attribute?.choices?.edges ?? []);
|
||||
};
|
||||
}
|
||||
|
||||
export class CollectionHandler implements Handler {
|
||||
constructor(public client: ApolloClient<unknown>, public query: string) {}
|
||||
|
||||
fetch = async () => {
|
||||
const { data } = await this.client.query<
|
||||
_GetCollectionsChoicesQuery,
|
||||
_GetCollectionsChoicesQueryVariables
|
||||
>({
|
||||
query: _GetCollectionsChoicesDocument,
|
||||
variables: {
|
||||
first: 5,
|
||||
query: this.query,
|
||||
},
|
||||
});
|
||||
|
||||
return createOptionsFromAPI(data.collections?.edges ?? []);
|
||||
};
|
||||
}
|
||||
|
||||
export class CategoryHandler implements Handler {
|
||||
constructor(public client: ApolloClient<unknown>, public query: string) {}
|
||||
|
||||
fetch = async () => {
|
||||
const { data } = await this.client.query<
|
||||
_GetCategoriesChoicesQuery,
|
||||
_GetCategoriesChoicesQueryVariables
|
||||
>({
|
||||
query: _GetCategoriesChoicesDocument,
|
||||
variables: {
|
||||
first: 5,
|
||||
query: this.query,
|
||||
},
|
||||
});
|
||||
|
||||
return createOptionsFromAPI(data.categories?.edges ?? []);
|
||||
};
|
||||
}
|
||||
|
||||
export class ProductTypeHandler implements Handler {
|
||||
constructor(public client: ApolloClient<unknown>, public query: string) {}
|
||||
|
||||
fetch = async () => {
|
||||
const { data } = await this.client.query<
|
||||
_GetProductTypesChoicesQuery,
|
||||
_GetProductTypesChoicesQueryVariables
|
||||
>({
|
||||
query: _GetProductTypesChoicesDocument,
|
||||
variables: {
|
||||
first: 5,
|
||||
query: this.query,
|
||||
},
|
||||
});
|
||||
|
||||
return createOptionsFromAPI(data.productTypes?.edges ?? []);
|
||||
};
|
||||
}
|
||||
|
||||
export class ChannelHandler implements Handler {
|
||||
constructor(public client: ApolloClient<unknown>, public query: string) {}
|
||||
|
||||
fetch = async () => {
|
||||
const { data } = await this.client.query<
|
||||
_GetChannelOperandsQuery,
|
||||
_GetChannelOperandsQueryVariables
|
||||
>({
|
||||
query: _GetChannelOperandsDocument,
|
||||
});
|
||||
const options =
|
||||
data.channels?.map(({ id, name, slug }) => ({
|
||||
label: name,
|
||||
value: id,
|
||||
slug,
|
||||
})) ?? [];
|
||||
|
||||
return options.filter(({ label }) =>
|
||||
label.toLowerCase().includes(this.query.toLowerCase()),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export class AttributesHandler implements Handler {
|
||||
constructor(public client: ApolloClient<unknown>, public query: string) {}
|
||||
|
||||
fetch = async () => {
|
||||
const { data } = await this.client.query<
|
||||
_GetDynamicLeftOperandsQuery,
|
||||
_GetDynamicLeftOperandsQueryVariables
|
||||
>({
|
||||
query: _GetDynamicLeftOperandsDocument,
|
||||
variables: {
|
||||
first: 5,
|
||||
query: this.query,
|
||||
},
|
||||
});
|
||||
return (
|
||||
data.attributes?.edges.map(({ node }) => ({
|
||||
label: node.name ?? "",
|
||||
value: node.id,
|
||||
type: node.inputType,
|
||||
slug: node.slug ?? "",
|
||||
})) ?? []
|
||||
);
|
||||
};
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
// @ts-strict-ignore
|
||||
import { ApolloClient } from "@apollo/client";
|
||||
import {
|
||||
_GetAttributeChoicesDocument,
|
||||
_GetCategoriesChoicesDocument,
|
||||
_GetChannelOperandsDocument,
|
||||
_GetCollectionsChoicesDocument,
|
||||
_GetDynamicLeftOperandsDocument,
|
||||
_GetProductTypesChoicesDocument,
|
||||
} from "@dashboard/graphql";
|
||||
|
||||
import { FilterElement } from "../FilterElement";
|
||||
import { FilterContainer } from "../useFilterContainer";
|
||||
import {
|
||||
AttributeChoicesHandler,
|
||||
AttributesHandler,
|
||||
CategoryHandler,
|
||||
ChannelHandler,
|
||||
CollectionHandler,
|
||||
Handler,
|
||||
ProductTypeHandler,
|
||||
} from "./Handler";
|
||||
|
||||
const getFilterElement = (value: any, index: number): FilterElement => {
|
||||
const possibleFilterElement = value[index];
|
||||
|
@ -19,193 +19,67 @@ const getFilterElement = (value: any, index: number): FilterElement => {
|
|||
: null;
|
||||
};
|
||||
|
||||
const createAPIHandler = (
|
||||
selectedRow: FilterElement,
|
||||
client: ApolloClient<unknown>,
|
||||
inputValue: string,
|
||||
): Handler => {
|
||||
if (selectedRow.isAttribute()) {
|
||||
return new AttributeChoicesHandler(
|
||||
client,
|
||||
selectedRow.value.value,
|
||||
inputValue,
|
||||
);
|
||||
}
|
||||
|
||||
if (selectedRow.isCollection()) {
|
||||
return new CollectionHandler(client, inputValue);
|
||||
}
|
||||
|
||||
if (selectedRow.isCategory()) {
|
||||
return new CategoryHandler(client, inputValue);
|
||||
}
|
||||
|
||||
if (selectedRow.isProductType()) {
|
||||
return new ProductTypeHandler(client, inputValue);
|
||||
}
|
||||
|
||||
if (selectedRow.isChannel()) {
|
||||
return new ChannelHandler(client, inputValue);
|
||||
}
|
||||
|
||||
throw new Error("Unknown filter element");
|
||||
};
|
||||
|
||||
export const getInitialRightOperatorOptions = async (
|
||||
client: ApolloClient<any>,
|
||||
client: ApolloClient<unknown>,
|
||||
position: string,
|
||||
value: FilterContainer,
|
||||
) => {
|
||||
const index = parseInt(position, 10);
|
||||
const filterElement = getFilterElement(value, index);
|
||||
const handler = createAPIHandler(filterElement, client, "");
|
||||
|
||||
if (filterElement.isAttribute()) {
|
||||
const { data } = await client.query({
|
||||
query: _GetAttributeChoicesDocument,
|
||||
variables: {
|
||||
slug: filterElement.value.value,
|
||||
first: 5,
|
||||
query: "",
|
||||
},
|
||||
});
|
||||
return data.attribute.choices.edges.map(({ node }) => ({
|
||||
label: node.name,
|
||||
value: node.id,
|
||||
slug: node.slug,
|
||||
}));
|
||||
}
|
||||
|
||||
if (filterElement.isCollection()) {
|
||||
const { data } = await client.query({
|
||||
query: _GetCollectionsChoicesDocument,
|
||||
variables: {
|
||||
first: 5,
|
||||
query: "",
|
||||
},
|
||||
});
|
||||
|
||||
return data.collections.edges.map(({ node }) => ({
|
||||
label: node.name,
|
||||
value: node.id,
|
||||
slug: node.slug,
|
||||
}));
|
||||
}
|
||||
|
||||
if (filterElement.isCategory()) {
|
||||
const { data } = await client.query({
|
||||
query: _GetCategoriesChoicesDocument,
|
||||
variables: {
|
||||
first: 5,
|
||||
query: "",
|
||||
},
|
||||
});
|
||||
|
||||
return data.categories.edges.map(({ node }) => ({
|
||||
label: node.name,
|
||||
value: node.id,
|
||||
slug: node.slug,
|
||||
}));
|
||||
}
|
||||
|
||||
if (filterElement.isProductType()) {
|
||||
const { data } = await client.query({
|
||||
query: _GetProductTypesChoicesDocument,
|
||||
variables: {
|
||||
first: 5,
|
||||
query: "",
|
||||
},
|
||||
});
|
||||
|
||||
return data.productTypes.edges.map(({ node }) => ({
|
||||
label: node.name,
|
||||
value: node.id,
|
||||
slug: node.slug,
|
||||
}));
|
||||
}
|
||||
|
||||
if (filterElement.isChannel()) {
|
||||
const { data } = await client.query({
|
||||
query: _GetChannelOperandsDocument,
|
||||
});
|
||||
|
||||
return data.channels.map(({ id, name, slug }) => ({
|
||||
label: name,
|
||||
value: id,
|
||||
slug,
|
||||
}));
|
||||
}
|
||||
return handler.fetch();
|
||||
};
|
||||
|
||||
export const getRightOperatorOptionsByQuery = async (
|
||||
client: ApolloClient<any>,
|
||||
client: ApolloClient<unknown>,
|
||||
position: string,
|
||||
value: FilterContainer,
|
||||
inputValue: string,
|
||||
) => {
|
||||
const index = parseInt(position, 10);
|
||||
const filterElement = getFilterElement(value, index);
|
||||
const handler = createAPIHandler(filterElement, client, inputValue);
|
||||
|
||||
if (filterElement.isAttribute()) {
|
||||
const { data } = await client.query({
|
||||
query: _GetAttributeChoicesDocument,
|
||||
variables: {
|
||||
slug: filterElement.value.value,
|
||||
first: 5,
|
||||
query: inputValue,
|
||||
},
|
||||
});
|
||||
return data.attribute.choices.edges.map(({ node }) => ({
|
||||
label: node.name,
|
||||
value: node.id,
|
||||
}));
|
||||
}
|
||||
|
||||
if (filterElement.isCollection()) {
|
||||
const { data } = await client.query({
|
||||
query: _GetCollectionsChoicesDocument,
|
||||
variables: {
|
||||
first: 5,
|
||||
query: inputValue,
|
||||
},
|
||||
});
|
||||
|
||||
return data.collections.edges.map(({ node }) => ({
|
||||
label: node.name,
|
||||
value: node.id,
|
||||
slug: node.slug,
|
||||
}));
|
||||
}
|
||||
|
||||
if (filterElement.isCategory()) {
|
||||
const { data } = await client.query({
|
||||
query: _GetCategoriesChoicesDocument,
|
||||
variables: {
|
||||
first: 5,
|
||||
query: inputValue,
|
||||
},
|
||||
});
|
||||
|
||||
return data.categories.edges.map(({ node }) => ({
|
||||
label: node.name,
|
||||
value: node.id,
|
||||
slug: node.slug,
|
||||
}));
|
||||
}
|
||||
|
||||
if (filterElement.isProductType()) {
|
||||
const { data } = await client.query({
|
||||
query: _GetProductTypesChoicesDocument,
|
||||
variables: {
|
||||
first: 5,
|
||||
query: inputValue,
|
||||
},
|
||||
});
|
||||
|
||||
return data.productTypes.edges.map(({ node }) => ({
|
||||
label: node.name,
|
||||
value: node.id,
|
||||
}));
|
||||
}
|
||||
|
||||
if (filterElement.isChannel()) {
|
||||
const { data } = await client.query({
|
||||
query: _GetChannelOperandsDocument,
|
||||
});
|
||||
const options = data.channels.map(({ id, name, slug }) => ({
|
||||
label: name,
|
||||
value: id,
|
||||
slug,
|
||||
}));
|
||||
|
||||
return options.filter(({ label }) =>
|
||||
label.toLowerCase().includes(inputValue.toLowerCase()),
|
||||
);
|
||||
}
|
||||
return handler.fetch();
|
||||
};
|
||||
|
||||
export const getLeftOperatorOptions = async (
|
||||
client: any,
|
||||
client: ApolloClient<unknown>,
|
||||
inputValue: string,
|
||||
) => {
|
||||
const { data } = await client.query({
|
||||
query: _GetDynamicLeftOperandsDocument,
|
||||
variables: {
|
||||
first: 5,
|
||||
query: inputValue,
|
||||
},
|
||||
});
|
||||
return data.attributes.edges.map(({ node }) => ({
|
||||
label: node.name,
|
||||
value: node.id,
|
||||
type: node.inputType,
|
||||
slug: node.slug,
|
||||
}));
|
||||
const handler = new AttributesHandler(client, inputValue);
|
||||
return handler.fetch();
|
||||
};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { AttributeInputTypeEnum } from "@dashboard/graphql";
|
||||
|
||||
import {
|
||||
ATTRIBUTE_INPUT_TYPE_CONDITIONS,
|
||||
STATIC_CONDITIONS,
|
||||
|
@ -50,7 +52,9 @@ export class ConditionOptions extends Array<ConditionItem> {
|
|||
return new ConditionOptions(options);
|
||||
}
|
||||
|
||||
public static fromName(name: AttributeInputType | StaticElementName) {
|
||||
public static fromName(
|
||||
name: AttributeInputType | StaticElementName | AttributeInputTypeEnum,
|
||||
) {
|
||||
const optionsStatic = this.isStaticName(name) && STATIC_CONDITIONS[name];
|
||||
const optionsAttribute =
|
||||
this.isAttributeInputType(name) && ATTRIBUTE_INPUT_TYPE_CONDITIONS[name];
|
||||
|
|
|
@ -61,9 +61,5 @@ export class ConditionSelected {
|
|||
|
||||
public setOptions(options: ConditionValue[]) {
|
||||
this.options = options;
|
||||
|
||||
if (this.conditionValue) {
|
||||
this.value = getDefaultByControlName(this.conditionValue.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,12 +93,12 @@ const FiltersArea = ({ provider, onConfirm }) => {
|
|||
|
||||
const handleLeftOperatorInputValueChange = (event: any) => {
|
||||
const fetchAPI = async () => {
|
||||
updateLeftLoadingState(event.path, true);
|
||||
const options = await getLeftOperatorOptions(client, event.value);
|
||||
setOperands(options);
|
||||
updateLeftLoadingState(event.path, false);
|
||||
setOperands(prev => [...prev, ...options]);
|
||||
};
|
||||
updateLeftLoadingState(event.path, true);
|
||||
fetchAPI();
|
||||
updateLeftLoadingState(event.path, false);
|
||||
};
|
||||
|
||||
const handleLeftOperatorInputValueChangeDebounced = useDebounce(
|
||||
|
@ -108,17 +108,17 @@ const FiltersArea = ({ provider, onConfirm }) => {
|
|||
|
||||
const handleRightOperatorInputValueChange = (event: any) => {
|
||||
const fetchAPI = async () => {
|
||||
updateRightLoadingState(event.path.split(".")[0], true);
|
||||
const options = await getRightOperatorOptionsByQuery(
|
||||
client,
|
||||
event.path.split(".")[0],
|
||||
value,
|
||||
event.value,
|
||||
);
|
||||
updateRightLoadingState(event.path.split(".")[0], false);
|
||||
updateRightOptions(event.path.split(".")[0], options);
|
||||
};
|
||||
updateRightLoadingState(event.path.split(".")[0], true);
|
||||
fetchAPI();
|
||||
updateRightLoadingState(event.path.split(".")[0], false);
|
||||
};
|
||||
|
||||
const handleRightOperatorInputValueChangeDebounced = useDebounce(
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
import { AttributeInputTypeEnum } from "@dashboard/graphql";
|
||||
import { useState } from "react";
|
||||
|
||||
import {
|
||||
AttributeInputType,
|
||||
StaticElementName,
|
||||
} from "./FilterElement/ConditionOptions";
|
||||
import { StaticElementName } from "./FilterElement/ConditionOptions";
|
||||
|
||||
export interface LeftOperand {
|
||||
type: AttributeInputType | StaticElementName;
|
||||
type: AttributeInputTypeEnum | StaticElementName;
|
||||
label: string;
|
||||
value: string;
|
||||
slug: string;
|
||||
|
|
Loading…
Reference in a new issue