Add infinite scroll to product selection

This commit is contained in:
dominik-zeglen 2020-10-26 11:29:41 +01:00
parent 1bfc13c8b5
commit 96d8aa101c
4 changed files with 85 additions and 41 deletions

View file

@ -60,8 +60,11 @@ export const CollectionDetails: React.FC<CollectionDetailsProps> = ({
);
const paginate = usePaginator();
const intl = useIntl();
const { search, result } = useProductSearch({
variables: DEFAULT_INITIAL_SEARCH_DATA
const { search, loadMore, result } = useProductSearch({
variables: {
...DEFAULT_INITIAL_SEARCH_DATA,
first: 100
}
});
const [updateMetadata] = useMetadataUpdate({});
const [updatePrivateMetadata] = usePrivateMetadataUpdate({});
@ -296,8 +299,10 @@ export const CollectionDetails: React.FC<CollectionDetailsProps> = ({
/>
<AssignProductDialog
confirmButtonState={assignProductOpts.status}
hasMore={result.data?.search?.pageInfo.hasNextPage}
open={params.action === "assign"}
onFetch={search}
onFetchMore={loadMore}
loading={result.loading}
onClose={closeModal}
onSubmit={products =>

View file

@ -19,7 +19,9 @@ import useSearchQuery from "@saleor/hooks/useSearchQuery";
import { buttonMessages } from "@saleor/intl";
import { maybe } from "@saleor/misc";
import { SearchProducts_search_edges_node } from "@saleor/searches/types/SearchProducts";
import { FetchMoreProps } from "@saleor/types";
import React from "react";
import InfiniteScroll from "react-infinite-scroller";
import { FormattedMessage, useIntl } from "react-intl";
import Checkbox from "../Checkbox";
@ -30,7 +32,7 @@ export interface FormData {
}
const useStyles = makeStyles(
{
theme => ({
avatar: {
"&&:first-child": {
paddingLeft: 0
@ -44,17 +46,25 @@ const useStyles = makeStyles(
colName: {
paddingLeft: 0
},
loadMoreLoaderContainer: {
alignItems: "center",
display: "flex",
height: theme.spacing(3),
justifyContent: "center",
marginTop: theme.spacing(3)
},
overflow: {
overflowY: "visible"
},
scrollArea: {
height: 500,
overflowY: "scroll"
}
},
}),
{ name: "AssignProductDialog" }
);
export interface AssignProductDialogProps {
export interface AssignProductDialogProps extends FetchMoreProps {
confirmButtonState: ConfirmButtonTransitionState;
open: boolean;
products: SearchProducts_search_edges_node[];
@ -84,11 +94,13 @@ function handleProductAssign(
const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
const {
confirmButtonState,
hasMore,
open,
loading,
products,
onClose,
onFetch,
onFetchMore,
onSubmit
} = props;
const classes = useStyles(props);
@ -135,44 +147,57 @@ const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
/>
<FormSpacer />
<div className={classes.scrollArea}>
<ResponsiveTable>
<TableBody>
{products &&
products.map(product => {
const isSelected = selectedProducts.some(
selectedProduct => selectedProduct.id === product.id
);
<InfiniteScroll
pageStart={0}
loadMore={onFetchMore}
hasMore={hasMore}
useWindow={false}
loader={
<div className={classes.loadMoreLoaderContainer}>
<CircularProgress size={16} />
</div>
}
threshold={10}
>
<ResponsiveTable key="table">
<TableBody>
{products &&
products.map(product => {
const isSelected = selectedProducts.some(
selectedProduct => selectedProduct.id === product.id
);
return (
<TableRow key={product.id}>
<TableCellAvatar
className={classes.avatar}
thumbnail={maybe(() => product.thumbnail.url)}
/>
<TableCell className={classes.colName}>
{product.name}
</TableCell>
<TableCell
padding="checkbox"
className={classes.checkboxCell}
>
<Checkbox
checked={isSelected}
onChange={() =>
handleProductAssign(
product,
isSelected,
selectedProducts,
setSelectedProducts
)
}
return (
<TableRow key={product.id}>
<TableCellAvatar
className={classes.avatar}
thumbnail={maybe(() => product.thumbnail.url)}
/>
</TableCell>
</TableRow>
);
})}
</TableBody>
</ResponsiveTable>
<TableCell className={classes.colName}>
{product.name}
</TableCell>
<TableCell
padding="checkbox"
className={classes.checkboxCell}
>
<Checkbox
checked={isSelected}
onChange={() =>
handleProductAssign(
product,
isSelected,
selectedProducts,
setSelectedProducts
)
}
/>
</TableCell>
</TableRow>
);
})}
</TableBody>
</ResponsiveTable>
</InfiniteScroll>
</div>
</DialogContent>
<DialogActions>

View file

@ -68,18 +68,21 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
);
const intl = useIntl();
const {
// loadMore: loadMoreCategories,
search: searchCategories,
result: searchCategoriesOpts
} = useCategorySearch({
variables: DEFAULT_INITIAL_SEARCH_DATA
});
const {
// loadMore: loadMoreCollections,
search: searchCollections,
result: searchCollectionsOpts
} = useCollectionSearch({
variables: DEFAULT_INITIAL_SEARCH_DATA
});
const {
loadMore: loadMoreProducts,
search: searchProducts,
result: searchProductsOpts
} = useProductSearch({
@ -325,8 +328,13 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
/>
<AssignProductDialog
confirmButtonState={saleCataloguesAddOpts.status}
hasMore={
searchProductsOpts.data?.search.pageInfo
.hasNextPage
}
open={params.action === "assign-product"}
onFetch={searchProducts}
onFetchMore={loadMoreProducts}
loading={searchProductsOpts.loading}
onClose={closeModal}
onSubmit={products =>

View file

@ -82,6 +82,7 @@ export const VoucherDetails: React.FC<VoucherDetailsProps> = ({
variables: DEFAULT_INITIAL_SEARCH_DATA
});
const {
loadMore: loadMoreProducts,
search: searchProducts,
result: searchProductsOpts
} = useProductSearch({
@ -484,8 +485,13 @@ export const VoucherDetails: React.FC<VoucherDetailsProps> = ({
confirmButtonState={
voucherCataloguesAddOpts.status
}
hasMore={
searchProductsOpts.data?.search.pageInfo
.hasNextPage
}
open={params.action === "assign-product"}
onFetch={searchProducts}
onFetchMore={loadMoreProducts}
loading={searchProductsOpts.loading}
onClose={closeModal}
onSubmit={products =>