From 11bead49c42c78ac2f451e5cf4b4a6853775646a Mon Sep 17 00:00:00 2001 From: sektordv Date: Wed, 11 Aug 2021 11:47:01 +0200 Subject: [PATCH] clear values on blur, prevent unnecessary updates --- .../MultiAutocompleteSelectField.tsx | 11 +++++++ src/pages/views/PageCreate.tsx | 4 +-- src/pages/views/PageDetails.tsx | 4 +-- .../ProductVariantCreator.stories.tsx | 3 +- .../ProductVariantCreatorContent.tsx | 5 ++- .../ProductVariantCreatorValues.tsx | 5 ++- .../views/ProductCreate/ProductCreate.tsx | 4 +-- .../views/ProductUpdate/ProductUpdate.tsx | 4 +-- src/products/views/ProductVariant.tsx | 4 +-- src/products/views/ProductVariantCreate.tsx | 4 +-- .../ProductVariantCreator.tsx | 6 ++-- .../handlers/attributeValueSearchHandler.ts | 32 ++++++++++++++++--- 12 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx index 7180f4ccc..e0841f022 100644 --- a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx +++ b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx @@ -89,6 +89,7 @@ export interface MultiAutocompleteSelectFieldProps testId?: string; fetchChoices?: (value: string) => void; onChange: (event: React.ChangeEvent) => void; + onBlur?: () => void; fetchOnFocus?: boolean; endAdornment?: React.ReactNode; } @@ -115,6 +116,7 @@ const MultiAutocompleteSelectFieldComponent: React.FC debounceFn(value)} onSelect={handleSelect} itemToString={() => ""} + // this is to prevent unwanted state updates when the dropdown is closed with an empty value, + // which downshift interprets as the value being updated with an empty string, causing side-effects + stateReducer={(state, changes) => { + if (changes.isOpen === false && state.inputValue === "") { + delete changes.inputValue; + } + return changes; + }} > {({ closeMenu, @@ -175,6 +185,7 @@ const MultiAutocompleteSelectFieldComponent: React.FC ), id: undefined, + onBlur, onClick: toggleMenu, onFocus: () => { if (fetchOnFocus) { diff --git a/src/pages/views/PageCreate.tsx b/src/pages/views/PageCreate.tsx index 530eb1811..c074c4e7f 100644 --- a/src/pages/views/PageCreate.tsx +++ b/src/pages/views/PageCreate.tsx @@ -15,7 +15,7 @@ import useNotifier from "@saleor/hooks/useNotifier"; import usePageSearch from "@saleor/searches/usePageSearch"; import usePageTypeSearch from "@saleor/searches/usePageTypeSearch"; import useProductSearch from "@saleor/searches/useProductSearch"; -import createAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; +import useAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler"; import { mapEdgesToItems } from "@saleor/utils/maps"; import { @@ -77,7 +77,7 @@ export const PageCreate: React.FC = ({ params }) => { loadMore: loadMoreAttributeValues, search: searchAttributeValues, result: searchAttributeValuesOpts - } = createAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); + } = useAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); const { data: selectedPageType } = usePageTypeQuery({ variables: { diff --git a/src/pages/views/PageDetails.tsx b/src/pages/views/PageDetails.tsx index ff57b9c35..9c305e7ec 100644 --- a/src/pages/views/PageDetails.tsx +++ b/src/pages/views/PageDetails.tsx @@ -26,7 +26,7 @@ import useNotifier from "@saleor/hooks/useNotifier"; import { commonMessages } from "@saleor/intl"; import usePageSearch from "@saleor/searches/usePageSearch"; import useProductSearch from "@saleor/searches/useProductSearch"; -import createAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; +import useAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler"; import { mapEdgesToItems } from "@saleor/utils/maps"; import { @@ -177,7 +177,7 @@ export const PageDetails: React.FC = ({ id, params }) => { loadMore: loadMoreAttributeValues, search: searchAttributeValues, result: searchAttributeValuesOpts - } = createAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); + } = useAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); const attributeValues = mapEdgesToItems(searchAttributeValuesOpts?.data?.attribute.choices) || []; diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx index 1dd349667..22648fc74 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx @@ -109,7 +109,8 @@ const props: ProductVariantCreatorContentProps = { errors: [], variantsLeft: 6, step: ProductVariantCreatorStep.values, - warehouses: warehouseList + warehouses: warehouseList, + onAttributeSelectBlur: () => undefined }; storiesOf("Views / Products / Create multiple variants", module) diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx index 60bf3b153..a6368a42a 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx @@ -29,6 +29,7 @@ export interface ProductVariantCreatorContentProps { warehouses: WarehouseFragment[]; fetchAttributeValues: (query: string, attributeId: string) => void; fetchMoreAttributeValues?: FetchMoreProps; + onAttributeSelectBlur: () => void; } const ProductVariantCreatorContent: React.FC = ({ @@ -42,7 +43,8 @@ const ProductVariantCreatorContent: React.FC errors, step, variantsLeft, - warehouses + warehouses, + onAttributeSelectBlur }) => { const selectedAttributes = attributes.filter(attribute => isSelected( @@ -71,6 +73,7 @@ const ProductVariantCreatorContent: React.FC type: ProductVariantCreateReducerActionType.selectValue }) } + onValueBlur={onAttributeSelectBlur} /> )} {step === ProductVariantCreatorStep.prices && ( diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorValues.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorValues.tsx index 7aabb0b1e..6dee79cf3 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorValues.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorValues.tsx @@ -102,6 +102,7 @@ export interface ProductVariantCreatorValuesProps { attributeId: string, value: AttributeValue> ) => void; + onValueBlur: () => void; } const ProductVariantCreatorValues: React.FC = props => { @@ -112,7 +113,8 @@ const ProductVariantCreatorValues: React.FC = fetchMoreAttributeValues, data, variantsLeft, - onValueClick + onValueClick, + onValueBlur } = props; const intl = useIntl(); const variantsNumber = getVariantsNumber(data); @@ -208,6 +210,7 @@ const ProductVariantCreatorValues: React.FC = fetchChoices={value => fetchAttributeValues(value, attribute.id) } + onBlur={onValueBlur} {...fetchMoreAttributeValues} /> )} diff --git a/src/products/views/ProductCreate/ProductCreate.tsx b/src/products/views/ProductCreate/ProductCreate.tsx index 15a623b9d..41e56905f 100644 --- a/src/products/views/ProductCreate/ProductCreate.tsx +++ b/src/products/views/ProductCreate/ProductCreate.tsx @@ -35,7 +35,7 @@ import useProductSearch from "@saleor/searches/useProductSearch"; import useProductTypeSearch from "@saleor/searches/useProductTypeSearch"; import { useTaxTypeList } from "@saleor/taxes/queries"; import { getProductErrorMessage } from "@saleor/utils/errors"; -import createAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; +import useAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler"; import { mapEdgesToItems } from "@saleor/utils/maps"; @@ -110,7 +110,7 @@ export const ProductCreateView: React.FC = ({ params }) => { loadMore: loadMoreAttributeValues, search: searchAttributeValues, result: searchAttributeValuesOpts - } = createAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); + } = useAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); const warehouses = useWarehouseList({ displayLoader: true, variables: { diff --git a/src/products/views/ProductUpdate/ProductUpdate.tsx b/src/products/views/ProductUpdate/ProductUpdate.tsx index 94334046b..d8f5cac2f 100644 --- a/src/products/views/ProductUpdate/ProductUpdate.tsx +++ b/src/products/views/ProductUpdate/ProductUpdate.tsx @@ -47,7 +47,7 @@ import useCollectionSearch from "@saleor/searches/useCollectionSearch"; import usePageSearch from "@saleor/searches/usePageSearch"; import useProductSearch from "@saleor/searches/useProductSearch"; import { getProductErrorMessage } from "@saleor/utils/errors"; -import createAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; +import useAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler"; import { mapEdgesToItems } from "@saleor/utils/maps"; @@ -149,7 +149,7 @@ export const ProductUpdate: React.FC = ({ id, params }) => { loadMore: loadMoreAttributeValues, search: searchAttributeValues, result: searchAttributeValuesOpts - } = createAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); + } = useAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); const warehouses = useWarehouseList({ displayLoader: true, variables: { diff --git a/src/products/views/ProductVariant.tsx b/src/products/views/ProductVariant.tsx index 97cd8d5de..41e738e72 100644 --- a/src/products/views/ProductVariant.tsx +++ b/src/products/views/ProductVariant.tsx @@ -25,7 +25,7 @@ import { useProductVariantChannelListingUpdate } from "@saleor/products/mutation import { ProductVariantDetails_productVariant } from "@saleor/products/types/ProductVariantDetails"; import usePageSearch from "@saleor/searches/usePageSearch"; import useProductSearch from "@saleor/searches/useProductSearch"; -import createAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; +import useAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler"; import { mapEdgesToItems } from "@saleor/utils/maps"; @@ -304,7 +304,7 @@ export const ProductVariant: React.FC = ({ loadMore: loadMoreAttributeValues, search: searchAttributeValues, result: searchAttributeValuesOpts - } = createAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); + } = useAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); const fetchMoreReferencePages = { hasMore: searchPagesOpts.data?.search?.pageInfo?.hasNextPage, diff --git a/src/products/views/ProductVariantCreate.tsx b/src/products/views/ProductVariantCreate.tsx index 30fb36d31..7f35bc703 100644 --- a/src/products/views/ProductVariantCreate.tsx +++ b/src/products/views/ProductVariantCreate.tsx @@ -13,7 +13,7 @@ import useNavigator from "@saleor/hooks/useNavigator"; import useShop from "@saleor/hooks/useShop"; import usePageSearch from "@saleor/searches/usePageSearch"; import useProductSearch from "@saleor/searches/useProductSearch"; -import createAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; +import useAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler"; import { mapEdgesToItems } from "@saleor/utils/maps"; import { @@ -172,7 +172,7 @@ export const ProductVariant: React.FC = ({ loadMore: loadMoreAttributeValues, search: searchAttributeValues, result: searchAttributeValuesOpts - } = createAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); + } = useAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); const fetchMoreReferencePages = { hasMore: searchPagesOpts.data?.search?.pageInfo?.hasNextPage, diff --git a/src/products/views/ProductVariantCreator/ProductVariantCreator.tsx b/src/products/views/ProductVariantCreator/ProductVariantCreator.tsx index 4c5d54330..60abf357e 100644 --- a/src/products/views/ProductVariantCreator/ProductVariantCreator.tsx +++ b/src/products/views/ProductVariantCreator/ProductVariantCreator.tsx @@ -6,7 +6,7 @@ import useNotifier from "@saleor/hooks/useNotifier"; import { useProductVariantBulkCreateMutation } from "@saleor/products/mutations"; import { useCreateMultipleVariantsData } from "@saleor/products/queries"; import { productUrl } from "@saleor/products/urls"; -import createAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; +import useAttributeValueSearchHandler from "@saleor/utils/handlers/attributeValueSearchHandler"; import { mapEdgesToItems } from "@saleor/utils/maps"; import React from "react"; import { useIntl } from "react-intl"; @@ -56,8 +56,9 @@ const ProductVariantCreator: React.FC = ({ const { loadMore: loadMoreAttributeValues, search: searchAttributeValues, + reset: searchAttributeReset, result: searchAttributeValuesOpts - } = createAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); + } = useAttributeValueSearchHandler(DEFAULT_INITIAL_SEARCH_DATA); const fetchMoreAttributeValues = { hasMore: !!searchAttributeValuesOpts.data?.attribute?.choices?.pageInfo @@ -98,6 +99,7 @@ const ProductVariantCreator: React.FC = ({ variables: { id, inputs } }) } + onAttributeSelectBlur={searchAttributeReset} warehouses={mapEdgesToItems(data?.warehouses) || []} /> diff --git a/src/utils/handlers/attributeValueSearchHandler.ts b/src/utils/handlers/attributeValueSearchHandler.ts index c361a8266..a37ca3bd1 100644 --- a/src/utils/handlers/attributeValueSearchHandler.ts +++ b/src/utils/handlers/attributeValueSearchHandler.ts @@ -1,4 +1,8 @@ -import { SearchAttributeValuesVariables } from "@saleor/searches/types/SearchAttributeValues"; +import { UseSearchResult } from "@saleor/hooks/makeSearch"; +import { + SearchAttributeValues, + SearchAttributeValuesVariables +} from "@saleor/searches/types/SearchAttributeValues"; import useAttributeValueSearch from "@saleor/searches/useAttributeValueSearch"; import { useEffect, useState } from "react"; @@ -7,9 +11,18 @@ interface AttributeValueSearchHandlerState { query: string; } -function createAttributeValueSearchHandler( +export interface UseAttributeValueSearchHandler + extends Omit< + UseSearchResult, + "search" + > { + reset: () => void; + search: (query: string, id: string | null) => void; +} + +function useAttributeValueSearchHandler( variables: SearchAttributeValuesVariables -) { +): UseAttributeValueSearchHandler { const [state, setState] = useState({ id: null, query: variables.query @@ -35,16 +48,25 @@ function createAttributeValueSearchHandler( } }; + const reset = () => setState(prevState => ({ ...prevState, id: null })); + useEffect(() => { if (state.id) { search(""); } }, [state.id]); + return { loadMore, search: handleSearch, - result + reset, + result: state.id + ? result + : { + ...result, + data: undefined + } }; } -export default createAttributeValueSearchHandler; +export default useAttributeValueSearchHandler;