From cc0e0e58f3b291a5a3351008ecd944c27a92d98b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20=C5=BBuraw?= <9116238+krzysztofzuraw@users.noreply.github.com> Date: Mon, 10 Jul 2023 08:17:30 +0200 Subject: [PATCH] Experimental filters: refactor API hooks (#3882) --- .changeset/popular-plants-sing.md | 7 ++ .eslintrc.json | 2 +- package-lock.json | 14 +-- package.json | 2 +- .../API/FilterAPIProvider.ts | 12 +++ .../ConditionalFilter/API/Handler.ts | 6 +- .../API/ProductFilterAPIProvider.tsx | 86 +++++++++++++++++++ .../ConditionalFilter/API/getAPIOptions.tsx | 84 ------------------ .../FilterElement/Condition.ts | 2 +- .../FilterElement/FilterElement.ts | 29 +++---- .../ConditionalFilter/LeftOperandsProvider.ts | 15 ++++ src/components/ConditionalFilter/index.tsx | 68 +++------------ .../ConditionalFilter/useFilterContainer.ts | 59 ++++++++++--- ...ftOperands.ts => useFilterLeftOperands.ts} | 15 +--- 14 files changed, 206 insertions(+), 195 deletions(-) create mode 100644 .changeset/popular-plants-sing.md create mode 100644 src/components/ConditionalFilter/API/FilterAPIProvider.ts create mode 100644 src/components/ConditionalFilter/API/ProductFilterAPIProvider.tsx delete mode 100644 src/components/ConditionalFilter/API/getAPIOptions.tsx create mode 100644 src/components/ConditionalFilter/LeftOperandsProvider.ts rename src/components/ConditionalFilter/{useLeftOperands.ts => useFilterLeftOperands.ts} (61%) diff --git a/.changeset/popular-plants-sing.md b/.changeset/popular-plants-sing.md new file mode 100644 index 000000000..65027f12a --- /dev/null +++ b/.changeset/popular-plants-sing.md @@ -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. diff --git a/.eslintrc.json b/.eslintrc.json index cf8fa459f..f5a97cac4 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -83,7 +83,7 @@ "@typescript-eslint/ban-ts-comment": "warn", "@typescript-eslint/ban-types": "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/no-base-to-string": "warn", "@typescript-eslint/no-dynamic-delete": "warn", diff --git a/package-lock.json b/package-lock.json index c53214d09..ae5686eb2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "@material-ui/lab": "^4.0.0-alpha.61", "@material-ui/styles": "^4.11.4", "@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", "@sentry/react": "^6.0.0", "@types/faker": "^5.1.6", @@ -7947,9 +7947,9 @@ } }, "node_modules/@saleor/macaw-ui": { - "version": "0.8.0-pre.103", - "resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.103.tgz", - "integrity": "sha512-Y6E4vHKhXf5cRZiQwLOy6LnabUH1FkyDQ9GZ03RH2PzXwoVA972v21ySJV4Vd3Kk8c7X5ugGzgV0Etovo963lA==", + "version": "0.8.0-pre.104", + "resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.104.tgz", + "integrity": "sha512-5Et/UIsH6ZzVyJLMhhnbN5PDllRGhyhJXBXUlgOdD0yH47+PPeaN9BPDDrlX/eiJbLMimJOIuj5hhb+WhWT/Zw==", "dependencies": { "@dessert-box/react": "^0.4.0", "@floating-ui/react-dom-interactions": "^0.5.0", @@ -41209,9 +41209,9 @@ } }, "@saleor/macaw-ui": { - "version": "0.8.0-pre.103", - "resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.103.tgz", - "integrity": "sha512-Y6E4vHKhXf5cRZiQwLOy6LnabUH1FkyDQ9GZ03RH2PzXwoVA972v21ySJV4Vd3Kk8c7X5ugGzgV0Etovo963lA==", + "version": "0.8.0-pre.104", + "resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.104.tgz", + "integrity": "sha512-5Et/UIsH6ZzVyJLMhhnbN5PDllRGhyhJXBXUlgOdD0yH47+PPeaN9BPDDrlX/eiJbLMimJOIuj5hhb+WhWT/Zw==", "requires": { "@dessert-box/react": "^0.4.0", "@floating-ui/react-dom-interactions": "^0.5.0", diff --git a/package.json b/package.json index 276561df9..78aab1eec 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@material-ui/lab": "^4.0.0-alpha.61", "@material-ui/styles": "^4.11.4", "@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", "@sentry/react": "^6.0.0", "@types/faker": "^5.1.6", diff --git a/src/components/ConditionalFilter/API/FilterAPIProvider.ts b/src/components/ConditionalFilter/API/FilterAPIProvider.ts new file mode 100644 index 000000000..0e448a05d --- /dev/null +++ b/src/components/ConditionalFilter/API/FilterAPIProvider.ts @@ -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; + fetchLeftOptions: (inputValue: string) => Promise; +} diff --git a/src/components/ConditionalFilter/API/Handler.ts b/src/components/ConditionalFilter/API/Handler.ts index b2c9354f6..6d1049d4b 100644 --- a/src/components/ConditionalFilter/API/Handler.ts +++ b/src/components/ConditionalFilter/API/Handler.ts @@ -21,7 +21,7 @@ import { } from "@dashboard/graphql"; import { ItemOption } from "../FilterElement/ConditionValue"; - +import { LeftOperand } from "../LeftOperandsProvider"; export interface Handler { client: ApolloClient; @@ -146,7 +146,7 @@ export class ChannelHandler implements Handler { export class AttributesHandler implements Handler { constructor(public client: ApolloClient, public query: string) {} - fetch = async () => { + fetch = async (): Promise => { const { data } = await this.client.query< _GetDynamicLeftOperandsQuery, _GetDynamicLeftOperandsQueryVariables @@ -161,7 +161,7 @@ export class AttributesHandler implements Handler { data.attributes?.edges.map(({ node }) => ({ label: node.name ?? "", value: node.id, - type: node.inputType, + type: node.inputType ?? ("" as LeftOperand["type"]), slug: node.slug ?? "", })) ?? [] ); diff --git a/src/components/ConditionalFilter/API/ProductFilterAPIProvider.tsx b/src/components/ConditionalFilter/API/ProductFilterAPIProvider.tsx new file mode 100644 index 000000000..0ccc5436b --- /dev/null +++ b/src/components/ConditionalFilter/API/ProductFilterAPIProvider.tsx @@ -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, + 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, + }; +}; diff --git a/src/components/ConditionalFilter/API/getAPIOptions.tsx b/src/components/ConditionalFilter/API/getAPIOptions.tsx deleted file mode 100644 index 3b955ed36..000000000 --- a/src/components/ConditionalFilter/API/getAPIOptions.tsx +++ /dev/null @@ -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, - 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, - 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, - 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, - inputValue: string, -) => { - const handler = new AttributesHandler(client, inputValue); - return handler.fetch(); -}; diff --git a/src/components/ConditionalFilter/FilterElement/Condition.ts b/src/components/ConditionalFilter/FilterElement/Condition.ts index d4bacf619..07fce4d0d 100644 --- a/src/components/ConditionalFilter/FilterElement/Condition.ts +++ b/src/components/ConditionalFilter/FilterElement/Condition.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/member-ordering */ import { InitialStateResponse } from "../API/InitialStateResponse"; -import { LeftOperand } from "./../useLeftOperands"; +import { LeftOperand } from "../LeftOperandsProvider"; import { UrlToken } from "./../ValueProvider/UrlToken"; import { ConditionOptions } from "./ConditionOptions"; import { ConditionSelected } from "./ConditionSelected"; diff --git a/src/components/ConditionalFilter/FilterElement/FilterElement.ts b/src/components/ConditionalFilter/FilterElement/FilterElement.ts index bb0ea6a30..cc94a8341 100644 --- a/src/components/ConditionalFilter/FilterElement/FilterElement.ts +++ b/src/components/ConditionalFilter/FilterElement/FilterElement.ts @@ -1,48 +1,46 @@ /* eslint-disable @typescript-eslint/member-ordering */ import { InitialStateResponse } from "../API/InitialStateResponse"; -import { LeftOperand } from "./../useLeftOperands"; +import { LeftOperand } from "../LeftOperandsProvider"; import { TokenType, UrlEntry, UrlToken } from "./../ValueProvider/UrlToken"; import { Condition } from "./Condition"; import { ConditionItem, ConditionOptions } from "./ConditionOptions"; import { ConditionSelected } from "./ConditionSelected"; import { ConditionValue, ItemOption } from "./ConditionValue"; - class ExpressionValue { constructor( public value: string, public label: string, - public type: string + public type: string, ) {} public static fromLeftOperand(leftOperand: LeftOperand) { return new ExpressionValue( leftOperand.slug, leftOperand.label, - leftOperand.type - ) + leftOperand.type, + ); } public static fromUrlToken(token: UrlToken) { - return new ExpressionValue( - token.name, - token.name, - token.name - ) + return new ExpressionValue(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); return new ExpressionValue( attributeName, attribute.label, attribute.inputType, - ) + ); } public static emptyStatic() { - return new ExpressionValue("", "", TokenType.STATIC) + return new ExpressionValue("", "", TokenType.STATIC); } } @@ -126,10 +124,10 @@ export class FilterElement { public asUrlEntry(): UrlEntry { 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) { @@ -165,5 +163,4 @@ export class FilterElement { } } - export type FilterContainer = Array; diff --git a/src/components/ConditionalFilter/LeftOperandsProvider.ts b/src/components/ConditionalFilter/LeftOperandsProvider.ts new file mode 100644 index 000000000..bc908d95e --- /dev/null +++ b/src/components/ConditionalFilter/LeftOperandsProvider.ts @@ -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; +} diff --git a/src/components/ConditionalFilter/index.tsx b/src/components/ConditionalFilter/index.tsx index 3c63df41a..93806fd30 100644 --- a/src/components/ConditionalFilter/index.tsx +++ b/src/components/ConditionalFilter/index.tsx @@ -1,6 +1,4 @@ // @ts-strict-ignore -import { useApolloClient } from "@apollo/client"; -import useDebounce from "@dashboard/hooks/useDebounce"; import { _ExperimentalFilters, Box, @@ -9,17 +7,14 @@ import { } from "@saleor/macaw-ui/next"; import React from "react"; -import { - getInitialRightOperatorOptions, - getLeftOperatorOptions, - getRightOperatorOptionsByQuery, -} from "./API/getAPIOptions"; +import { useProductFilterAPIProvider } from "./API/ProductFilterAPIProvider"; import { useFilterContainer } from "./useFilterContainer"; -import { useLeftOperands } from "./useLeftOperands"; +import { useFilterLeftOperandsProvider } from "./useFilterLeftOperands"; import { useUrlValueProvider } from "./ValueProvider/useUrlValueProvider"; const FiltersArea = ({ provider, onConfirm }) => { - const client = useApolloClient(); + const apiProvider = useProductFilterAPIProvider(); + const leftOperandsProvider = useFilterLeftOperandsProvider(); const { value, @@ -29,46 +24,8 @@ const FiltersArea = ({ provider, onConfirm }) => { updateRightOperator, updateCondition, updateRightOptions, - updateRightLoadingState, - updateLeftLoadingState, - } = 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, - ); + updateLeftOptions, + } = useFilterContainer(provider, apiProvider, leftOperandsProvider); const handleStateChange = async (event: FilterEvent["detail"]) => { if (event.type === "row.add") { @@ -88,24 +45,19 @@ const FiltersArea = ({ provider, onConfirm }) => { } if (event.type === "rightOperator.onChange") { - // @ts-expect-error slug in missing in MacawUI updateRightOperator(event.path.split(".")[0], event.value); } if (event.type === "rightOperator.onFocus") { - const path = event.path.split(".")[0]; - updateRightLoadingState(path, true); - const options = await getInitialRightOperatorOptions(client, path, value); - updateRightOptions(path, options); - updateRightLoadingState(path, false); + updateRightOptions(event.path.split(".")[0], ""); } if (event.type === "rightOperator.onInputValueChange") { - handleRightOperatorInputValueChangeDebounced(event); + updateRightOptions(event.path.split(".")[0], event.value); } if (event.type === "leftOperator.onInputValueChange") { - handleLeftOperatorInputValueChangeDebounced(event); + updateLeftOptions(event.path.split(".")[0], event.value); } }; @@ -114,7 +66,7 @@ const FiltersArea = ({ provider, onConfirm }) => { return ( <_ExperimentalFilters - leftOptions={operands} + leftOptions={leftOperandsProvider.operands} // @ts-expect-error value={value} onChange={handleStateChange} diff --git a/src/components/ConditionalFilter/useFilterContainer.ts b/src/components/ConditionalFilter/useFilterContainer.ts index 3e3ecfccb..660192de8 100644 --- a/src/components/ConditionalFilter/useFilterContainer.ts +++ b/src/components/ConditionalFilter/useFilterContainer.ts @@ -1,38 +1,72 @@ +import useDebounce from "@dashboard/hooks/useDebounce"; + +import { FilterAPIProvider } from "./API/FilterAPIProvider"; import { FilterContainer } from "./FilterElement"; import { ConditionValue, ItemOption } from "./FilterElement/ConditionValue"; +import { LeftOperandsProvider } from "./LeftOperandsProvider"; import { useContainerState } from "./useContainerState"; -export const useFilterContainer = (initialValue: FilterContainer) => { - const { value, updateAt, removeAt, createEmpty } = useContainerState(initialValue) +export const useFilterContainer = ( + initialValue: FilterContainer, + apiProvider: FilterAPIProvider, + leftOperandsProvider: LeftOperandsProvider, +) => { + const { value, updateAt, removeAt, createEmpty } = + useContainerState(initialValue); const addEmpty = () => { - createEmpty() + createEmpty(); }; const updateLeftOperator = (position: string, leftOperator: any) => { - updateAt(position, (el) => el.updateLeftOperator(leftOperator)) + updateAt(position, el => el.updateLeftOperator(leftOperator)); }; const updateLeftLoadingState = (position: string, loading: boolean) => { - updateAt(position, (el) => el.updateLeftLoadingState(loading)) + updateAt(position, el => el.updateLeftLoadingState(loading)); }; - const updateRightOperator = (position: string, rightOperator: ConditionValue) => { - updateAt(position, (el) => el.updateRightOperator(rightOperator)) + const updateRightOperator = ( + position: string, + rightOperator: ConditionValue, + ) => { + updateAt(position, el => el.updateRightOperator(rightOperator)); }; - const updateRightOptions = (position: string, options: ItemOption[]) => { - updateAt(position, (el) => el.updateRightOptions(options)) + const _updateRightOptions = (position: string, options: ItemOption[]) => { + updateAt(position, el => el.updateRightOptions(options)); }; const updateRightLoadingState = (position: string, loading: boolean) => { - updateAt(position, (el) => el.updateRightLoadingState(loading)) + updateAt(position, el => el.updateRightLoadingState(loading)); }; 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 { value, addEmpty, @@ -41,7 +75,6 @@ export const useFilterContainer = (initialValue: FilterContainer) => { updateRightOperator, updateCondition, updateRightOptions, - updateRightLoadingState, - updateLeftLoadingState, + updateLeftOptions, }; }; diff --git a/src/components/ConditionalFilter/useLeftOperands.ts b/src/components/ConditionalFilter/useFilterLeftOperands.ts similarity index 61% rename from src/components/ConditionalFilter/useLeftOperands.ts rename to src/components/ConditionalFilter/useFilterLeftOperands.ts index f630bc2f0..63340cf65 100644 --- a/src/components/ConditionalFilter/useLeftOperands.ts +++ b/src/components/ConditionalFilter/useFilterLeftOperands.ts @@ -1,14 +1,6 @@ -import { AttributeInputTypeEnum } from "@dashboard/graphql"; import { useState } from "react"; -import { StaticElementName } from "./FilterElement/ConditionOptions"; - -export interface LeftOperand { - type: AttributeInputTypeEnum | StaticElementName; - label: string; - value: string; - slug: string; -} +import { LeftOperand, LeftOperandsProvider } from "./LeftOperandsProvider"; const STATIC_OPTIONS: LeftOperand[] = [ { value: "price", label: "Price", type: "price", slug: "price" }, @@ -22,11 +14,12 @@ const STATIC_OPTIONS: LeftOperand[] = [ { value: "channel", label: "Channel", type: "channel", slug: "channel" }, ]; -export const useLeftOperands = () => { +export const useFilterLeftOperandsProvider = (): LeftOperandsProvider => { const [operands, setOperands] = useState(STATIC_OPTIONS); return { operands, - setOperands, + setOperands: (options: LeftOperand[]) => + setOperands(prev => [...prev, ...options]), }; };