From e292059b826daec4e4ba905d0789b2e51f7cc910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chy=C5=82a?= Date: Tue, 29 Aug 2023 13:19:29 +0200 Subject: [PATCH] Fix showing only first 50 warehouses at variant page (#4136) --- .changeset/nervous-pigs-clap.md | 5 +++ src/hooks/makeFetchAll.ts | 41 ++++++++++++++++++ .../ProductStocks/ProductStocks.tsx | 42 ++++++++++++++----- .../ProductVariantPage/ProductVariantPage.tsx | 6 +++ .../ProductVarinatPage.stories.tsx | 8 ++++ .../views/ProductVariant/ProductVariant.tsx | 14 +++++++ src/products/views/ProductVariant/utils.ts | 25 +++++++++++ 7 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 .changeset/nervous-pigs-clap.md create mode 100644 src/hooks/makeFetchAll.ts create mode 100644 src/products/views/ProductVariant/utils.ts diff --git a/.changeset/nervous-pigs-clap.md b/.changeset/nervous-pigs-clap.md new file mode 100644 index 00000000000..4f8d67d25cb --- /dev/null +++ b/.changeset/nervous-pigs-clap.md @@ -0,0 +1,5 @@ +--- +"saleor-dashboard": patch +--- + +Fix showing only first 50 warehouses at variant page diff --git a/src/hooks/makeFetchAll.ts b/src/hooks/makeFetchAll.ts new file mode 100644 index 00000000000..67c0ed3f866 --- /dev/null +++ b/src/hooks/makeFetchAll.ts @@ -0,0 +1,41 @@ +import { PageInfoFragment } from "@dashboard/graphql"; +import { DocumentNode } from "graphql"; +import { useEffect } from "react"; + +import makeQuery from "./makeQuery"; + +export function makeFetchAll( + query: DocumentNode, + accessKey: keyof TData, + mergeFn: ( + previousQueryResult: TData, + options: { + fetchMoreResult?: TData; + }, + ) => TData, +) { + return (variables: TVariables) => { + const useQuery = makeQuery(query); + + const result = useQuery({ + displayLoader: true, + variables, + }); + useEffect(() => { + if (result.data) { + const data = result.data[accessKey] as { pageInfo?: PageInfoFragment }; + const nextPage = data?.pageInfo?.hasNextPage; + const after = data?.pageInfo?.endCursor; + + if (nextPage && after !== null) { + result.fetchMore({ + updateQuery: mergeFn, + variables: { after }, + }); + } + } + }, [result.data]); + + return result; + }; +} diff --git a/src/products/components/ProductStocks/ProductStocks.tsx b/src/products/components/ProductStocks/ProductStocks.tsx index 1f60baecdbd..afb8b2b4c16 100644 --- a/src/products/components/ProductStocks/ProductStocks.tsx +++ b/src/products/components/ProductStocks/ProductStocks.tsx @@ -24,12 +24,14 @@ import { Input, List, PlusIcon, + Spinner, sprinkles, Text, TrashBinIcon, vars, } from "@saleor/macaw-ui/next"; import React from "react"; +import InfiniteScroll from "react-infinite-scroll-component"; import { FormattedMessage, useIntl } from "react-intl"; import { ProductCreateData } from "../ProductCreatePage"; @@ -77,6 +79,8 @@ export interface ProductStocksProps { onWarehouseStockAdd: (warehouseId: string) => void; onWarehouseStockDelete: (warehouseId: string) => void; onWarehouseConfigure: () => void; + onFetchMoreWarehouses?: () => void; + hasNextWarehouses?: boolean; } export const ProductStocks: React.FC = ({ @@ -96,6 +100,8 @@ export const ProductStocks: React.FC = ({ onWarehouseStockAdd, onWarehouseStockDelete, onWarehouseConfigure, + onFetchMoreWarehouses, + hasNextWarehouses, }) => { const intl = useIntl(); const [lastStockRowFocus, setLastStockRowFocus] = React.useState(false); @@ -321,24 +327,40 @@ export const ProductStocks: React.FC = ({ padding={2} borderRadius={4} boxShadow="overlay" - __maxHeight={400} - overflow="auto" backgroundColor="surfaceNeutralPlain" > - {warehousesToAssign.map(warehouse => ( - + - handleWarehouseStockAdd(warehouse.id) - } > - {warehouse.name} + + Loading + - - ))} + } + > + {warehousesToAssign.map(warehouse => ( + + + handleWarehouseStockAdd(warehouse.id) + } + > + {warehouse.name} + + + ))} + diff --git a/src/products/components/ProductVariantPage/ProductVariantPage.tsx b/src/products/components/ProductVariantPage/ProductVariantPage.tsx index c79219f799c..4cc02f74581 100644 --- a/src/products/components/ProductVariantPage/ProductVariantPage.tsx +++ b/src/products/components/ProductVariantPage/ProductVariantPage.tsx @@ -122,6 +122,8 @@ interface ProductVariantPageProps { onSubmit: (data: ProductVariantUpdateSubmitData) => any; onSetDefaultVariant: () => any; onWarehouseConfigure: () => any; + onFetchMoreWarehouses: () => void; + hasNextWarehouses: boolean; } const ProductVariantPage: React.FC = ({ @@ -157,6 +159,8 @@ const ProductVariantPage: React.FC = ({ fetchMoreAttributeValues, onCloseDialog, onAttributeSelectBlur, + hasNextWarehouses, + onFetchMoreWarehouses, }) => { const intl = useIntl(); const navigate = useNavigator(); @@ -355,6 +359,8 @@ const ProductVariantPage: React.FC = ({ ...channel.value, }), )} + onFetchMoreWarehouses={onFetchMoreWarehouses} + hasNextWarehouses={hasNextWarehouses} onVariantChannelListingChange={handlers.changeChannels} data={data} disabled={loading} diff --git a/src/products/components/ProductVariantPage/ProductVarinatPage.stories.tsx b/src/products/components/ProductVariantPage/ProductVarinatPage.stories.tsx index 813a6d2beff..3a79ac961b9 100644 --- a/src/products/components/ProductVariantPage/ProductVarinatPage.stories.tsx +++ b/src/products/components/ProductVariantPage/ProductVarinatPage.stories.tsx @@ -18,6 +18,8 @@ export default { export const WhenLoadedData = () => ( undefined} defaultWeightUnit="kg" header={variant.name || variant.sku} errors={[]} @@ -46,6 +48,8 @@ export const WhenLoadedData = () => ( export const WhenLoadingData = () => ( undefined} defaultWeightUnit="kg" header={undefined} errors={[]} @@ -75,6 +79,8 @@ export const WhenLoadingData = () => ( export const NoWarehouses = () => ( undefined} defaultWeightUnit="kg" header={variant.name || variant.sku} errors={[]} @@ -103,6 +109,8 @@ export const NoWarehouses = () => ( export const AttributeErrors = () => ( undefined} defaultWeightUnit="kg" header={variant.name || variant.sku} channels={channels} diff --git a/src/products/views/ProductVariant/ProductVariant.tsx b/src/products/views/ProductVariant/ProductVariant.tsx index 5c08abe705b..e9fd288bc08 100644 --- a/src/products/views/ProductVariant/ProductVariant.tsx +++ b/src/products/views/ProductVariant/ProductVariant.tsx @@ -60,6 +60,7 @@ import { import { mapFormsetStockToStockInput } from "../../utils/data"; import { createVariantReorderHandler } from "./../ProductUpdate/handlers"; import { useSubmitChannels } from "./useSubmitChannels"; +import { mergeWarehousesQuery } from "./utils"; interface ProductUpdateProps { variantId: string; @@ -258,6 +259,15 @@ export const ProductVariant: React.FC = ({ }), ); + const handleFetchMoreWarehouses = () => { + warehouses?.fetchMore({ + updateQuery: mergeWarehousesQuery, + variables: { + after: warehouses?.data?.warehouses?.pageInfo?.endCursor, + }, + }); + }; + const { loadMore: loadMorePages, search: searchPages, @@ -325,6 +335,10 @@ export const ProductVariant: React.FC = ({ variant={variant} header={variant?.name || variant?.sku} warehouses={mapEdgesToItems(warehouses?.data?.warehouses) || []} + onFetchMoreWarehouses={handleFetchMoreWarehouses} + hasNextWarehouses={ + warehouses?.data?.warehouses?.pageInfo?.hasNextPage ?? false + } onDelete={() => openModal("remove")} onSubmit={handleSubmit} onWarehouseConfigure={() => navigate(warehouseAddPath)} diff --git a/src/products/views/ProductVariant/utils.ts b/src/products/views/ProductVariant/utils.ts new file mode 100644 index 00000000000..f7bacb31985 --- /dev/null +++ b/src/products/views/ProductVariant/utils.ts @@ -0,0 +1,25 @@ +import { WarehouseListQuery } from "@dashboard/graphql"; + +export const mergeWarehousesQuery = ( + previousResult: WarehouseListQuery, + { + fetchMoreResult, + }: { + fetchMoreResult?: WarehouseListQuery; + }, +): WarehouseListQuery => { + if (!fetchMoreResult) { + return previousResult; + } + + const previousEdges = previousResult?.warehouses?.edges ?? []; + const fetchMoreEdges = fetchMoreResult?.warehouses?.edges ?? []; + + if (fetchMoreResult?.warehouses?.edges) { + fetchMoreResult.warehouses.edges = [...previousEdges, ...fetchMoreEdges]; + + return { ...fetchMoreResult }; + } + + return previousResult; +};