Skip to content

Commit

Permalink
Fix product variant crash when many warehouses by load on scroll (#4932)
Browse files Browse the repository at this point in the history
* Fetch warehouses async

* Update create and update page

* Improve loader and button

* useInfityScroll hook

* Center loader

* Improve edge cases in infinity scroll

* Improve useWarehouseSearch variables typing

* Keep warehouses fetch in view component

* Fix infinity loading

* Add changesset

* Fix typos

* Remove not usedd hook useAllWarehouses

* Use event listener insted of expose onScroll funtion

* use scroll  instead

* Back to scroll again Yeah!

* Fix loading more on init
  • Loading branch information
poulch committed Jun 7, 2024
1 parent 03efea1 commit 8222516
Show file tree
Hide file tree
Showing 25 changed files with 432 additions and 293 deletions.
5 changes: 5 additions & 0 deletions .changeset/swift-balloons-serve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"saleor-dashboard": patch
---

You can now assign warehouses in product variant page without page crash
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-strict-ignore
import SingleAutocompleteSelectField from "@dashboard/components/SingleAutocompleteSelectField";
import CardAddItemsFooter from "@dashboard/products/components/ProductStocks/CardAddItemsFooter";
import CardAddItemsFooter from "@dashboard/products/components/ProductStocks/components/CardAddItemsFooter";
import { mapNodeToChoice } from "@dashboard/utils/maps";
import { ClickAwayListener } from "@material-ui/core";
import React, { useEffect, useRef, useState } from "react";
Expand Down
5 changes: 3 additions & 2 deletions src/graphql/hooks.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14648,12 +14648,12 @@ export type SearchStaffMembersQueryHookResult = ReturnType<typeof useSearchStaff
export type SearchStaffMembersLazyQueryHookResult = ReturnType<typeof useSearchStaffMembersLazyQuery>;
export type SearchStaffMembersQueryResult = Apollo.QueryResult<Types.SearchStaffMembersQuery, Types.SearchStaffMembersQueryVariables>;
export const SearchWarehousesDocument = gql`
query SearchWarehouses($after: String, $first: Int!, $query: String!) {
query SearchWarehouses($after: String, $first: Int!, $query: String!, $channnelsId: [ID!]) {
search: warehouses(
after: $after
first: $first
sortBy: {direction: ASC, field: NAME}
filter: {search: $query}
filter: {search: $query, channels: $channnelsId}
) {
totalCount
edges {
Expand Down Expand Up @@ -14684,6 +14684,7 @@ export const SearchWarehousesDocument = gql`
* after: // value for 'after'
* first: // value for 'first'
* query: // value for 'query'
* channnelsId: // value for 'channnelsId'
* },
* });
*/
Expand Down
1 change: 1 addition & 0 deletions src/graphql/types.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10581,6 +10581,7 @@ export type SearchWarehousesQueryVariables = Exact<{
after?: InputMaybe<Scalars['String']>;
first: Scalars['Int'];
query: Scalars['String'];
channnelsId?: InputMaybe<Array<Scalars['ID']> | Scalars['ID']>;
}>;


Expand Down
78 changes: 78 additions & 0 deletions src/hooks/useInfinityScroll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { useCallback, useEffect, useRef } from "react";

import useDebounce from "./useDebounce";

const SCROLL_THRESHOLD = 100;
const DEBOUNCE_TIME = 500;

export const useInfinityScroll = <TElementRef extends HTMLElement>({
onLoadMore,
threshold = SCROLL_THRESHOLD,
debounceTime = DEBOUNCE_TIME,
}: {
onLoadMore: () => void;
threshold?: number;
debounceTime?: number;
}) => {
const scrollRef = useRef<TElementRef>(null);

const shouldLoadMore = useCallback(() => {
if (!scrollRef.current) {
return false;
}

const totalScrollHeight = scrollRef.current.scrollHeight;
const scrollTop = scrollRef.current.scrollTop;
const clientHeight = scrollRef.current.clientHeight;

if (scrollTop === 0 && totalScrollHeight === 0 && clientHeight === 0) {
return false;
}

const scrolledHeight = scrollTop + clientHeight;
const scrollBottom = totalScrollHeight - scrolledHeight;

return scrollBottom < threshold;
}, [threshold]);

const handleInfiniteScroll = () => {
if (!scrollRef.current) {
return;
}

if (shouldLoadMore()) {
onLoadMore();
}
};

const debouncedHandleInfiniteScroll = useDebounce(
handleInfiniteScroll,
debounceTime,
);

useEffect(() => {
if (!scrollRef.current) {
return;
}

const callback = () => debouncedHandleInfiniteScroll();
const ref = scrollRef.current;

ref.addEventListener("scroll", callback);

return () => {
ref.removeEventListener("scroll", callback);
};
}, [debouncedHandleInfiniteScroll]);

useEffect(() => {
// On init check thresholdd and load more if needed
if (shouldLoadMore()) {
onLoadMore();
}
}, [onLoadMore, shouldLoadMore]);

return {
scrollRef,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export const OrderChangeWarehouseDialog: React.FC<
} = useWarehouseSearch({
variables: {
after: null,
channnelsId: null,
first: 20,
query: "",
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ const props = {
onCloseDialog: () => undefined,
onSelectProductType: () => undefined,
onAttributeSelectBlur: () => undefined,
fetchMoreWarehouses: () => undefined,
searchWarehousesResult: undefined,
};

export const Default = () => <ProductCreatePage {...props} />;
Expand Down
21 changes: 16 additions & 5 deletions src/products/components/ProductCreatePage/ProductCreatePage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @ts-strict-ignore
import { QueryResult } from "@apollo/client";
import {
getReferenceAttributeEntityTypeFromAttribute,
mergeAttributeValues,
Expand Down Expand Up @@ -39,6 +40,7 @@ import {
productListUrl,
} from "@dashboard/products/urls";
import { getChoices } from "@dashboard/products/utils/data";
import { mapEdgesToItems } from "@dashboard/utils/maps";
import React from "react";
import { useIntl } from "react-intl";

Expand Down Expand Up @@ -75,7 +77,6 @@ interface ProductCreatePageProps {
header: string;
saveButtonBarState: ConfirmButtonTransitionState;
weightUnit: string;
warehouses: RelayToFlat<SearchWarehousesQuery["search"]>;
taxClasses: TaxClassBaseFragment[];
fetchMoreTaxClasses: FetchMoreProps;
selectedProductType?: ProductTypeQuery["productType"];
Expand All @@ -95,7 +96,9 @@ interface ProductCreatePageProps {
onAttributeSelectBlur: () => void;
onCloseDialog: (currentParams?: ProductCreateUrlQueryParams) => void;
onSelectProductType: (productTypeId: string) => void;
onSubmit?(data: ProductCreateData);
onSubmit?: (data: ProductCreateData) => any;
fetchMoreWarehouses: () => void;
searchWarehousesResult: QueryResult<SearchWarehousesQuery>;
}

export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
Expand All @@ -118,7 +121,6 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
referencePages = [],
referenceProducts = [],
saveButtonBarState,
warehouses,
taxClasses,
fetchMoreTaxClasses,
selectedProductType,
Expand All @@ -139,6 +141,8 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
onCloseDialog,
onSelectProductType,
onAttributeSelectBlur,
fetchMoreWarehouses,
searchWarehousesResult,
}: ProductCreatePageProps) => {
const intl = useIntl();
const navigate = useNavigator();
Expand Down Expand Up @@ -205,7 +209,6 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
setSelectedTaxClass={setSelectedTaxClass}
setChannels={onChannelsChange}
taxClasses={taxClassChoices}
warehouses={warehouses}
currentChannels={currentChannels}
fetchReferencePages={fetchReferencePages}
fetchMoreReferencePages={fetchMoreReferencePages}
Expand Down Expand Up @@ -281,13 +284,21 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
/>
<ProductStocks
data={data}
warehouses={
mapEdgesToItems(searchWarehousesResult?.data?.search) ??
[]
}
fetchMoreWarehouses={fetchMoreWarehouses}
hasMoreWarehouses={
searchWarehousesResult?.data?.search?.pageInfo
?.hasNextPage
}
disabled={loading}
hasVariants={false}
onFormDataChange={change}
errors={errors}
formErrors={formErrors}
stocks={data.stocks}
warehouses={warehouses}
onChange={handlers.changeStock}
onChangePreorderEndDate={handlers.changePreorderEndDate}
onWarehouseStockAdd={handlers.addStock}
Expand Down
9 changes: 4 additions & 5 deletions src/products/components/ProductCreatePage/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {
SearchPagesQuery,
SearchProductsQuery,
SearchProductTypesQuery,
SearchWarehousesQuery,
} from "@dashboard/graphql";
import useForm, {
CommonUseFormResultWithHandlers,
Expand Down Expand Up @@ -126,7 +125,8 @@ export interface ProductCreateHandlers
Record<"selectAttributeReference", FormsetChange<string[]>>,
Record<"selectAttributeFile", FormsetChange<File>>,
Record<"reorderAttributeValue", FormsetChange<ReorderEvent>>,
Record<"addStock" | "deleteStock", (id: string) => void> {
Record<"addStock", (id: string, label: string) => void>,
Record<"deleteStock", (id: string) => void> {
changePreorderEndDate: FormChange;
fetchReferences: (value: string) => void;
fetchMoreReferences: FetchMoreProps;
Expand Down Expand Up @@ -160,7 +160,6 @@ export interface UseProductCreateFormOpts
setChannels: (channels: ChannelData[]) => void;
selectedCollections: MultiAutocompleteChoiceType[];
productTypes: RelayToFlat<SearchProductTypesQuery["search"]>;
warehouses: RelayToFlat<SearchWarehousesQuery["search"]>;
currentChannels: ChannelData[];
referencePages: RelayToFlat<SearchPagesQuery["search"]>;
referenceProducts: RelayToFlat<SearchProductsQuery["search"]>;
Expand Down Expand Up @@ -312,14 +311,14 @@ function useProductCreateForm(
triggerChange();
stocks.change(id, value);
};
const handleStockAdd = (id: string) => {
const handleStockAdd = (id: string, label: string) => {
triggerChange();
stocks.add({
data: {
quantityAllocated: 0,
},
id,
label: opts.warehouses.find(warehouse => warehouse.id === id).name,
label,
value: "0",
});
};
Expand Down
Loading

0 comments on commit 8222516

Please sign in to comment.