Experimental filters: refactor API hooks (#3882)
This commit is contained in:
parent
b09f2d556f
commit
cc0e0e58f3
14 changed files with 206 additions and 195 deletions
7
.changeset/popular-plants-sing.md
Normal file
7
.changeset/popular-plants-sing.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
"saleor-dashboard": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Experimental filters: refactor API hooks.
|
||||||
|
|
||||||
|
This PR refactors API hooks used to fetch data. Right now they return the provider which then is used by the filter container to update options coming from API.
|
|
@ -83,7 +83,7 @@
|
||||||
"@typescript-eslint/ban-ts-comment": "warn",
|
"@typescript-eslint/ban-ts-comment": "warn",
|
||||||
"@typescript-eslint/ban-types": "warn",
|
"@typescript-eslint/ban-types": "warn",
|
||||||
"@typescript-eslint/consistent-type-assertions": "warn",
|
"@typescript-eslint/consistent-type-assertions": "warn",
|
||||||
"@typescript-eslint/explicit-function-return-type": "warn",
|
"@typescript-eslint/explicit-function-return-type": "off",
|
||||||
"@typescript-eslint/naming-convention": "warn",
|
"@typescript-eslint/naming-convention": "warn",
|
||||||
"@typescript-eslint/no-base-to-string": "warn",
|
"@typescript-eslint/no-base-to-string": "warn",
|
||||||
"@typescript-eslint/no-dynamic-delete": "warn",
|
"@typescript-eslint/no-dynamic-delete": "warn",
|
||||||
|
|
14
package-lock.json
generated
14
package-lock.json
generated
|
@ -27,7 +27,7 @@
|
||||||
"@material-ui/lab": "^4.0.0-alpha.61",
|
"@material-ui/lab": "^4.0.0-alpha.61",
|
||||||
"@material-ui/styles": "^4.11.4",
|
"@material-ui/styles": "^4.11.4",
|
||||||
"@reach/auto-id": "^0.16.0",
|
"@reach/auto-id": "^0.16.0",
|
||||||
"@saleor/macaw-ui": "0.8.0-pre.103",
|
"@saleor/macaw-ui": "0.8.0-pre.104",
|
||||||
"@saleor/sdk": "0.6.0",
|
"@saleor/sdk": "0.6.0",
|
||||||
"@sentry/react": "^6.0.0",
|
"@sentry/react": "^6.0.0",
|
||||||
"@types/faker": "^5.1.6",
|
"@types/faker": "^5.1.6",
|
||||||
|
@ -7947,9 +7947,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@saleor/macaw-ui": {
|
"node_modules/@saleor/macaw-ui": {
|
||||||
"version": "0.8.0-pre.103",
|
"version": "0.8.0-pre.104",
|
||||||
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.103.tgz",
|
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.104.tgz",
|
||||||
"integrity": "sha512-Y6E4vHKhXf5cRZiQwLOy6LnabUH1FkyDQ9GZ03RH2PzXwoVA972v21ySJV4Vd3Kk8c7X5ugGzgV0Etovo963lA==",
|
"integrity": "sha512-5Et/UIsH6ZzVyJLMhhnbN5PDllRGhyhJXBXUlgOdD0yH47+PPeaN9BPDDrlX/eiJbLMimJOIuj5hhb+WhWT/Zw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dessert-box/react": "^0.4.0",
|
"@dessert-box/react": "^0.4.0",
|
||||||
"@floating-ui/react-dom-interactions": "^0.5.0",
|
"@floating-ui/react-dom-interactions": "^0.5.0",
|
||||||
|
@ -41209,9 +41209,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@saleor/macaw-ui": {
|
"@saleor/macaw-ui": {
|
||||||
"version": "0.8.0-pre.103",
|
"version": "0.8.0-pre.104",
|
||||||
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.103.tgz",
|
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.104.tgz",
|
||||||
"integrity": "sha512-Y6E4vHKhXf5cRZiQwLOy6LnabUH1FkyDQ9GZ03RH2PzXwoVA972v21ySJV4Vd3Kk8c7X5ugGzgV0Etovo963lA==",
|
"integrity": "sha512-5Et/UIsH6ZzVyJLMhhnbN5PDllRGhyhJXBXUlgOdD0yH47+PPeaN9BPDDrlX/eiJbLMimJOIuj5hhb+WhWT/Zw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@dessert-box/react": "^0.4.0",
|
"@dessert-box/react": "^0.4.0",
|
||||||
"@floating-ui/react-dom-interactions": "^0.5.0",
|
"@floating-ui/react-dom-interactions": "^0.5.0",
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
"@material-ui/lab": "^4.0.0-alpha.61",
|
"@material-ui/lab": "^4.0.0-alpha.61",
|
||||||
"@material-ui/styles": "^4.11.4",
|
"@material-ui/styles": "^4.11.4",
|
||||||
"@reach/auto-id": "^0.16.0",
|
"@reach/auto-id": "^0.16.0",
|
||||||
"@saleor/macaw-ui": "0.8.0-pre.103",
|
"@saleor/macaw-ui": "0.8.0-pre.104",
|
||||||
"@saleor/sdk": "0.6.0",
|
"@saleor/sdk": "0.6.0",
|
||||||
"@sentry/react": "^6.0.0",
|
"@sentry/react": "^6.0.0",
|
||||||
"@types/faker": "^5.1.6",
|
"@types/faker": "^5.1.6",
|
||||||
|
|
12
src/components/ConditionalFilter/API/FilterAPIProvider.ts
Normal file
12
src/components/ConditionalFilter/API/FilterAPIProvider.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { FilterContainer } from "../FilterElement";
|
||||||
|
import { ItemOption } from "../FilterElement/ConditionValue";
|
||||||
|
import { LeftOperand } from "../LeftOperandsProvider";
|
||||||
|
|
||||||
|
export interface FilterAPIProvider {
|
||||||
|
fetchRightOptions: (
|
||||||
|
position: string,
|
||||||
|
value: FilterContainer,
|
||||||
|
inputValue: string,
|
||||||
|
) => Promise<ItemOption[]>;
|
||||||
|
fetchLeftOptions: (inputValue: string) => Promise<LeftOperand[]>;
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ import {
|
||||||
} from "@dashboard/graphql";
|
} from "@dashboard/graphql";
|
||||||
|
|
||||||
import { ItemOption } from "../FilterElement/ConditionValue";
|
import { ItemOption } from "../FilterElement/ConditionValue";
|
||||||
|
import { LeftOperand } from "../LeftOperandsProvider";
|
||||||
|
|
||||||
export interface Handler {
|
export interface Handler {
|
||||||
client: ApolloClient<unknown>;
|
client: ApolloClient<unknown>;
|
||||||
|
@ -146,7 +146,7 @@ export class ChannelHandler implements Handler {
|
||||||
export class AttributesHandler implements Handler {
|
export class AttributesHandler implements Handler {
|
||||||
constructor(public client: ApolloClient<unknown>, public query: string) {}
|
constructor(public client: ApolloClient<unknown>, public query: string) {}
|
||||||
|
|
||||||
fetch = async () => {
|
fetch = async (): Promise<LeftOperand[]> => {
|
||||||
const { data } = await this.client.query<
|
const { data } = await this.client.query<
|
||||||
_GetDynamicLeftOperandsQuery,
|
_GetDynamicLeftOperandsQuery,
|
||||||
_GetDynamicLeftOperandsQueryVariables
|
_GetDynamicLeftOperandsQueryVariables
|
||||||
|
@ -161,7 +161,7 @@ export class AttributesHandler implements Handler {
|
||||||
data.attributes?.edges.map(({ node }) => ({
|
data.attributes?.edges.map(({ node }) => ({
|
||||||
label: node.name ?? "",
|
label: node.name ?? "",
|
||||||
value: node.id,
|
value: node.id,
|
||||||
type: node.inputType,
|
type: node.inputType ?? ("" as LeftOperand["type"]),
|
||||||
slug: node.slug ?? "",
|
slug: node.slug ?? "",
|
||||||
})) ?? []
|
})) ?? []
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
import { ApolloClient, useApolloClient } from "@apollo/client";
|
||||||
|
|
||||||
|
import { FilterContainer, FilterElement } from "../FilterElement";
|
||||||
|
import { FilterAPIProvider } from "./FilterAPIProvider";
|
||||||
|
import {
|
||||||
|
AttributeChoicesHandler,
|
||||||
|
AttributesHandler,
|
||||||
|
CategoryHandler,
|
||||||
|
ChannelHandler,
|
||||||
|
CollectionHandler,
|
||||||
|
Handler,
|
||||||
|
ProductTypeHandler,
|
||||||
|
} from "./Handler";
|
||||||
|
|
||||||
|
const getFilterElement = (
|
||||||
|
value: FilterContainer,
|
||||||
|
index: number,
|
||||||
|
): FilterElement => {
|
||||||
|
const possibleFilterElement = value[index];
|
||||||
|
if (
|
||||||
|
typeof possibleFilterElement !== "string" &&
|
||||||
|
!Array.isArray(possibleFilterElement)
|
||||||
|
) {
|
||||||
|
return possibleFilterElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("Unknown filter element used to create API handler");
|
||||||
|
};
|
||||||
|
|
||||||
|
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 useProductFilterAPIProvider = (): FilterAPIProvider => {
|
||||||
|
const client = useApolloClient();
|
||||||
|
|
||||||
|
const fetchRightOptions = async (
|
||||||
|
position: string,
|
||||||
|
value: FilterContainer,
|
||||||
|
inputValue: string,
|
||||||
|
) => {
|
||||||
|
const index = parseInt(position, 10);
|
||||||
|
const filterElement = getFilterElement(value, index);
|
||||||
|
const handler = createAPIHandler(filterElement, client, inputValue);
|
||||||
|
|
||||||
|
return handler.fetch();
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchLeftOptions = async (inputValue: string) => {
|
||||||
|
const handler = new AttributesHandler(client, inputValue);
|
||||||
|
return handler.fetch();
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
fetchRightOptions,
|
||||||
|
fetchLeftOptions,
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,84 +0,0 @@
|
||||||
import { ApolloClient } from "@apollo/client";
|
|
||||||
|
|
||||||
import { FilterContainer, FilterElement } from "../FilterElement";
|
|
||||||
import {
|
|
||||||
AttributeChoicesHandler,
|
|
||||||
AttributesHandler,
|
|
||||||
CategoryHandler,
|
|
||||||
ChannelHandler,
|
|
||||||
CollectionHandler,
|
|
||||||
Handler,
|
|
||||||
ProductTypeHandler,
|
|
||||||
} from "./Handler";
|
|
||||||
|
|
||||||
const getFilterElement = (value: any, index: number): FilterElement => {
|
|
||||||
const possibleFilterElement = value[index];
|
|
||||||
return typeof possibleFilterElement !== "string"
|
|
||||||
? possibleFilterElement
|
|
||||||
: 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<unknown>,
|
|
||||||
position: string,
|
|
||||||
value: FilterContainer,
|
|
||||||
) => {
|
|
||||||
const index = parseInt(position, 10);
|
|
||||||
const filterElement = getFilterElement(value, index);
|
|
||||||
const handler = createAPIHandler(filterElement, client, "");
|
|
||||||
|
|
||||||
return handler.fetch();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getRightOperatorOptionsByQuery = async (
|
|
||||||
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);
|
|
||||||
|
|
||||||
return handler.fetch();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getLeftOperatorOptions = async (
|
|
||||||
client: ApolloClient<unknown>,
|
|
||||||
inputValue: string,
|
|
||||||
) => {
|
|
||||||
const handler = new AttributesHandler(client, inputValue);
|
|
||||||
return handler.fetch();
|
|
||||||
};
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable @typescript-eslint/member-ordering */
|
/* eslint-disable @typescript-eslint/member-ordering */
|
||||||
import { InitialStateResponse } from "../API/InitialStateResponse";
|
import { InitialStateResponse } from "../API/InitialStateResponse";
|
||||||
import { LeftOperand } from "./../useLeftOperands";
|
import { LeftOperand } from "../LeftOperandsProvider";
|
||||||
import { UrlToken } from "./../ValueProvider/UrlToken";
|
import { UrlToken } from "./../ValueProvider/UrlToken";
|
||||||
import { ConditionOptions } from "./ConditionOptions";
|
import { ConditionOptions } from "./ConditionOptions";
|
||||||
import { ConditionSelected } from "./ConditionSelected";
|
import { ConditionSelected } from "./ConditionSelected";
|
||||||
|
|
|
@ -1,48 +1,46 @@
|
||||||
/* eslint-disable @typescript-eslint/member-ordering */
|
/* eslint-disable @typescript-eslint/member-ordering */
|
||||||
import { InitialStateResponse } from "../API/InitialStateResponse";
|
import { InitialStateResponse } from "../API/InitialStateResponse";
|
||||||
import { LeftOperand } from "./../useLeftOperands";
|
import { LeftOperand } from "../LeftOperandsProvider";
|
||||||
import { TokenType, UrlEntry, UrlToken } from "./../ValueProvider/UrlToken";
|
import { TokenType, UrlEntry, UrlToken } from "./../ValueProvider/UrlToken";
|
||||||
import { Condition } from "./Condition";
|
import { Condition } from "./Condition";
|
||||||
import { ConditionItem, ConditionOptions } from "./ConditionOptions";
|
import { ConditionItem, ConditionOptions } from "./ConditionOptions";
|
||||||
import { ConditionSelected } from "./ConditionSelected";
|
import { ConditionSelected } from "./ConditionSelected";
|
||||||
import { ConditionValue, ItemOption } from "./ConditionValue";
|
import { ConditionValue, ItemOption } from "./ConditionValue";
|
||||||
|
|
||||||
|
|
||||||
class ExpressionValue {
|
class ExpressionValue {
|
||||||
constructor(
|
constructor(
|
||||||
public value: string,
|
public value: string,
|
||||||
public label: string,
|
public label: string,
|
||||||
public type: string
|
public type: string,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public static fromLeftOperand(leftOperand: LeftOperand) {
|
public static fromLeftOperand(leftOperand: LeftOperand) {
|
||||||
return new ExpressionValue(
|
return new ExpressionValue(
|
||||||
leftOperand.slug,
|
leftOperand.slug,
|
||||||
leftOperand.label,
|
leftOperand.label,
|
||||||
leftOperand.type
|
leftOperand.type,
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromUrlToken(token: UrlToken) {
|
public static fromUrlToken(token: UrlToken) {
|
||||||
return new ExpressionValue(
|
return new ExpressionValue(token.name, token.name, token.name);
|
||||||
token.name,
|
|
||||||
token.name,
|
|
||||||
token.name
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static forAttribute(attributeName: string, response: InitialStateResponse) {
|
public static forAttribute(
|
||||||
|
attributeName: string,
|
||||||
|
response: InitialStateResponse,
|
||||||
|
) {
|
||||||
const attribute = response.attributeByName(attributeName);
|
const attribute = response.attributeByName(attributeName);
|
||||||
|
|
||||||
return new ExpressionValue(
|
return new ExpressionValue(
|
||||||
attributeName,
|
attributeName,
|
||||||
attribute.label,
|
attribute.label,
|
||||||
attribute.inputType,
|
attribute.inputType,
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static emptyStatic() {
|
public static emptyStatic() {
|
||||||
return new ExpressionValue("", "", TokenType.STATIC)
|
return new ExpressionValue("", "", TokenType.STATIC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,10 +124,10 @@ export class FilterElement {
|
||||||
|
|
||||||
public asUrlEntry(): UrlEntry {
|
public asUrlEntry(): UrlEntry {
|
||||||
if (this.isAttribute()) {
|
if (this.isAttribute()) {
|
||||||
return UrlEntry.forAttribute(this.condition.selected, this.value.value)
|
return UrlEntry.forAttribute(this.condition.selected, this.value.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UrlEntry.forStatic(this.condition.selected, this.value.value)
|
return UrlEntry.forStatic(this.condition.selected, this.value.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromValueEntry(valueEntry: any) {
|
public static fromValueEntry(valueEntry: any) {
|
||||||
|
@ -165,5 +163,4 @@ export class FilterElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export type FilterContainer = Array<string | FilterElement | FilterContainer>;
|
export type FilterContainer = Array<string | FilterElement | FilterContainer>;
|
||||||
|
|
15
src/components/ConditionalFilter/LeftOperandsProvider.ts
Normal file
15
src/components/ConditionalFilter/LeftOperandsProvider.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { AttributeInputTypeEnum } from "@dashboard/graphql";
|
||||||
|
|
||||||
|
import { StaticElementName } from "./FilterElement/ConditionOptions";
|
||||||
|
|
||||||
|
export interface LeftOperand {
|
||||||
|
type: AttributeInputTypeEnum | StaticElementName;
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
slug: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LeftOperandsProvider {
|
||||||
|
operands: LeftOperand[];
|
||||||
|
setOperands: (operands: LeftOperand[]) => void;
|
||||||
|
}
|
|
@ -1,6 +1,4 @@
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { useApolloClient } from "@apollo/client";
|
|
||||||
import useDebounce from "@dashboard/hooks/useDebounce";
|
|
||||||
import {
|
import {
|
||||||
_ExperimentalFilters,
|
_ExperimentalFilters,
|
||||||
Box,
|
Box,
|
||||||
|
@ -9,17 +7,14 @@ import {
|
||||||
} from "@saleor/macaw-ui/next";
|
} from "@saleor/macaw-ui/next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import {
|
import { useProductFilterAPIProvider } from "./API/ProductFilterAPIProvider";
|
||||||
getInitialRightOperatorOptions,
|
|
||||||
getLeftOperatorOptions,
|
|
||||||
getRightOperatorOptionsByQuery,
|
|
||||||
} from "./API/getAPIOptions";
|
|
||||||
import { useFilterContainer } from "./useFilterContainer";
|
import { useFilterContainer } from "./useFilterContainer";
|
||||||
import { useLeftOperands } from "./useLeftOperands";
|
import { useFilterLeftOperandsProvider } from "./useFilterLeftOperands";
|
||||||
import { useUrlValueProvider } from "./ValueProvider/useUrlValueProvider";
|
import { useUrlValueProvider } from "./ValueProvider/useUrlValueProvider";
|
||||||
|
|
||||||
const FiltersArea = ({ provider, onConfirm }) => {
|
const FiltersArea = ({ provider, onConfirm }) => {
|
||||||
const client = useApolloClient();
|
const apiProvider = useProductFilterAPIProvider();
|
||||||
|
const leftOperandsProvider = useFilterLeftOperandsProvider();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
value,
|
value,
|
||||||
|
@ -29,46 +24,8 @@ const FiltersArea = ({ provider, onConfirm }) => {
|
||||||
updateRightOperator,
|
updateRightOperator,
|
||||||
updateCondition,
|
updateCondition,
|
||||||
updateRightOptions,
|
updateRightOptions,
|
||||||
updateRightLoadingState,
|
updateLeftOptions,
|
||||||
updateLeftLoadingState,
|
} = useFilterContainer(provider, apiProvider, leftOperandsProvider);
|
||||||
} = useFilterContainer(provider);
|
|
||||||
|
|
||||||
const { operands, setOperands } = useLeftOperands();
|
|
||||||
|
|
||||||
const handleLeftOperatorInputValueChange = (event: any) => {
|
|
||||||
const fetchAPI = async () => {
|
|
||||||
updateLeftLoadingState(event.path, true);
|
|
||||||
const options = await getLeftOperatorOptions(client, event.value);
|
|
||||||
updateLeftLoadingState(event.path, false);
|
|
||||||
setOperands(prev => [...prev, ...options]);
|
|
||||||
};
|
|
||||||
fetchAPI();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleLeftOperatorInputValueChangeDebounced = useDebounce(
|
|
||||||
handleLeftOperatorInputValueChange,
|
|
||||||
500,
|
|
||||||
);
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
fetchAPI();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRightOperatorInputValueChangeDebounced = useDebounce(
|
|
||||||
handleRightOperatorInputValueChange,
|
|
||||||
500,
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleStateChange = async (event: FilterEvent["detail"]) => {
|
const handleStateChange = async (event: FilterEvent["detail"]) => {
|
||||||
if (event.type === "row.add") {
|
if (event.type === "row.add") {
|
||||||
|
@ -88,24 +45,19 @@ const FiltersArea = ({ provider, onConfirm }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type === "rightOperator.onChange") {
|
if (event.type === "rightOperator.onChange") {
|
||||||
// @ts-expect-error slug in missing in MacawUI
|
|
||||||
updateRightOperator(event.path.split(".")[0], event.value);
|
updateRightOperator(event.path.split(".")[0], event.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type === "rightOperator.onFocus") {
|
if (event.type === "rightOperator.onFocus") {
|
||||||
const path = event.path.split(".")[0];
|
updateRightOptions(event.path.split(".")[0], "");
|
||||||
updateRightLoadingState(path, true);
|
|
||||||
const options = await getInitialRightOperatorOptions(client, path, value);
|
|
||||||
updateRightOptions(path, options);
|
|
||||||
updateRightLoadingState(path, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type === "rightOperator.onInputValueChange") {
|
if (event.type === "rightOperator.onInputValueChange") {
|
||||||
handleRightOperatorInputValueChangeDebounced(event);
|
updateRightOptions(event.path.split(".")[0], event.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type === "leftOperator.onInputValueChange") {
|
if (event.type === "leftOperator.onInputValueChange") {
|
||||||
handleLeftOperatorInputValueChangeDebounced(event);
|
updateLeftOptions(event.path.split(".")[0], event.value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -114,7 +66,7 @@ const FiltersArea = ({ provider, onConfirm }) => {
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<_ExperimentalFilters
|
<_ExperimentalFilters
|
||||||
leftOptions={operands}
|
leftOptions={leftOperandsProvider.operands}
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
value={value}
|
value={value}
|
||||||
onChange={handleStateChange}
|
onChange={handleStateChange}
|
||||||
|
|
|
@ -1,38 +1,72 @@
|
||||||
|
import useDebounce from "@dashboard/hooks/useDebounce";
|
||||||
|
|
||||||
|
import { FilterAPIProvider } from "./API/FilterAPIProvider";
|
||||||
import { FilterContainer } from "./FilterElement";
|
import { FilterContainer } from "./FilterElement";
|
||||||
import { ConditionValue, ItemOption } from "./FilterElement/ConditionValue";
|
import { ConditionValue, ItemOption } from "./FilterElement/ConditionValue";
|
||||||
|
import { LeftOperandsProvider } from "./LeftOperandsProvider";
|
||||||
import { useContainerState } from "./useContainerState";
|
import { useContainerState } from "./useContainerState";
|
||||||
|
|
||||||
export const useFilterContainer = (initialValue: FilterContainer) => {
|
export const useFilterContainer = (
|
||||||
const { value, updateAt, removeAt, createEmpty } = useContainerState(initialValue)
|
initialValue: FilterContainer,
|
||||||
|
apiProvider: FilterAPIProvider,
|
||||||
|
leftOperandsProvider: LeftOperandsProvider,
|
||||||
|
) => {
|
||||||
|
const { value, updateAt, removeAt, createEmpty } =
|
||||||
|
useContainerState(initialValue);
|
||||||
|
|
||||||
const addEmpty = () => {
|
const addEmpty = () => {
|
||||||
createEmpty()
|
createEmpty();
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateLeftOperator = (position: string, leftOperator: any) => {
|
const updateLeftOperator = (position: string, leftOperator: any) => {
|
||||||
updateAt(position, (el) => el.updateLeftOperator(leftOperator))
|
updateAt(position, el => el.updateLeftOperator(leftOperator));
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateLeftLoadingState = (position: string, loading: boolean) => {
|
const updateLeftLoadingState = (position: string, loading: boolean) => {
|
||||||
updateAt(position, (el) => el.updateLeftLoadingState(loading))
|
updateAt(position, el => el.updateLeftLoadingState(loading));
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateRightOperator = (position: string, rightOperator: ConditionValue) => {
|
const updateRightOperator = (
|
||||||
updateAt(position, (el) => el.updateRightOperator(rightOperator))
|
position: string,
|
||||||
|
rightOperator: ConditionValue,
|
||||||
|
) => {
|
||||||
|
updateAt(position, el => el.updateRightOperator(rightOperator));
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateRightOptions = (position: string, options: ItemOption[]) => {
|
const _updateRightOptions = (position: string, options: ItemOption[]) => {
|
||||||
updateAt(position, (el) => el.updateRightOptions(options))
|
updateAt(position, el => el.updateRightOptions(options));
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateRightLoadingState = (position: string, loading: boolean) => {
|
const updateRightLoadingState = (position: string, loading: boolean) => {
|
||||||
updateAt(position, (el) => el.updateRightLoadingState(loading))
|
updateAt(position, el => el.updateRightLoadingState(loading));
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateCondition = (position: string, conditionValue: any) => {
|
const updateCondition = (position: string, conditionValue: any) => {
|
||||||
updateAt(position, (el) => el.updateCondition(conditionValue))
|
updateAt(position, el => el.updateCondition(conditionValue));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const _fetchRightOptions = async (position: string, inputValue: string) => {
|
||||||
|
updateRightLoadingState(position, true);
|
||||||
|
const options = await apiProvider.fetchRightOptions(
|
||||||
|
position,
|
||||||
|
value,
|
||||||
|
inputValue,
|
||||||
|
);
|
||||||
|
updateRightLoadingState(position, false);
|
||||||
|
_updateRightOptions(position, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateRightOptions = useDebounce(_fetchRightOptions, 500);
|
||||||
|
|
||||||
|
const _fetchLeftOptions = async (position: string, inputValue: string) => {
|
||||||
|
updateLeftLoadingState(position, true);
|
||||||
|
const options = await apiProvider.fetchLeftOptions(inputValue);
|
||||||
|
updateLeftLoadingState(position, false);
|
||||||
|
leftOperandsProvider.setOperands(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateLeftOptions = useDebounce(_fetchLeftOptions, 500);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
value,
|
value,
|
||||||
addEmpty,
|
addEmpty,
|
||||||
|
@ -41,7 +75,6 @@ export const useFilterContainer = (initialValue: FilterContainer) => {
|
||||||
updateRightOperator,
|
updateRightOperator,
|
||||||
updateCondition,
|
updateCondition,
|
||||||
updateRightOptions,
|
updateRightOptions,
|
||||||
updateRightLoadingState,
|
updateLeftOptions,
|
||||||
updateLeftLoadingState,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
import { AttributeInputTypeEnum } from "@dashboard/graphql";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { StaticElementName } from "./FilterElement/ConditionOptions";
|
import { LeftOperand, LeftOperandsProvider } from "./LeftOperandsProvider";
|
||||||
|
|
||||||
export interface LeftOperand {
|
|
||||||
type: AttributeInputTypeEnum | StaticElementName;
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
slug: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const STATIC_OPTIONS: LeftOperand[] = [
|
const STATIC_OPTIONS: LeftOperand[] = [
|
||||||
{ value: "price", label: "Price", type: "price", slug: "price" },
|
{ value: "price", label: "Price", type: "price", slug: "price" },
|
||||||
|
@ -22,11 +14,12 @@ const STATIC_OPTIONS: LeftOperand[] = [
|
||||||
{ value: "channel", label: "Channel", type: "channel", slug: "channel" },
|
{ value: "channel", label: "Channel", type: "channel", slug: "channel" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const useLeftOperands = () => {
|
export const useFilterLeftOperandsProvider = (): LeftOperandsProvider => {
|
||||||
const [operands, setOperands] = useState<LeftOperand[]>(STATIC_OPTIONS);
|
const [operands, setOperands] = useState<LeftOperand[]>(STATIC_OPTIONS);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
operands,
|
operands,
|
||||||
setOperands,
|
setOperands: (options: LeftOperand[]) =>
|
||||||
|
setOperands(prev => [...prev, ...options]),
|
||||||
};
|
};
|
||||||
};
|
};
|
Loading…
Reference in a new issue