Fix duplicated labels in column picker (#1197)
* Fix duplicated labels in column picker * Update changelog * Refactor column picker scroll fetch * Migrate react-infinite-scroller to react-infinite-scroll-component * Remove unneeded keys * Align dialog items to top
This commit is contained in:
parent
8e1dc4e12d
commit
909e08f2af
18 changed files with 280 additions and 268 deletions
|
@ -57,6 +57,7 @@ All notable, unreleased changes to this project will be documented in this file.
|
||||||
- Fix breaking select popups in filters - #1193 by @orzechdev
|
- Fix breaking select popups in filters - #1193 by @orzechdev
|
||||||
- Create channel filters in product, sales and voucher lists - #1187 by @jwm0
|
- Create channel filters in product, sales and voucher lists - #1187 by @jwm0
|
||||||
- Add generic filter validation - #1187 by @jwm0
|
- Add generic filter validation - #1187 by @jwm0
|
||||||
|
- Fix duplicated labels in column picker - #1197 by @orzechdev
|
||||||
|
|
||||||
# 2.11.1
|
# 2.11.1
|
||||||
|
|
||||||
|
|
13
package-lock.json
generated
13
package-lock.json
generated
|
@ -22656,12 +22656,12 @@
|
||||||
"prop-types": "^15.6.1"
|
"prop-types": "^15.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-infinite-scroller": {
|
"react-infinite-scroll-component": {
|
||||||
"version": "1.2.4",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-infinite-scroller/-/react-infinite-scroller-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz",
|
||||||
"integrity": "sha512-/oOa0QhZjXPqaD6sictN2edFMsd3kkMiE19Vcz5JDgHpzEJVqYcmq+V3mkwO88087kvKGe1URNksHEOt839Ubw==",
|
"integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"prop-types": "^15.5.8"
|
"throttle-debounce": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-inlinesvg": {
|
"react-inlinesvg": {
|
||||||
|
@ -26702,8 +26702,7 @@
|
||||||
"throttle-debounce": {
|
"throttle-debounce": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz",
|
||||||
"integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==",
|
"integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"throttleit": {
|
"throttleit": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
"react-error-boundary": "^1.2.5",
|
"react-error-boundary": "^1.2.5",
|
||||||
"react-gtm-module": "^2.0.11",
|
"react-gtm-module": "^2.0.11",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
"react-infinite-scroller": "^1.2.4",
|
"react-infinite-scroll-component": "^6.1.0",
|
||||||
"react-inlinesvg": "^2.1.1",
|
"react-inlinesvg": "^2.1.1",
|
||||||
"react-intl": "^5.10.2",
|
"react-intl": "^5.10.2",
|
||||||
"react-jss": "^10.0.0",
|
"react-jss": "^10.0.0",
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { makeStyles } from "@saleor/theme";
|
||||||
import { FetchMoreProps } from "@saleor/types";
|
import { FetchMoreProps } from "@saleor/types";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import InfiniteScroll from "react-infinite-scroller";
|
import InfiniteScroll from "react-infinite-scroll-component";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
|
@ -73,6 +73,8 @@ export interface AssignAttributeDialogProps extends FetchMoreProps {
|
||||||
onToggle: (id: string) => void;
|
onToggle: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scrollableTargetId = "assignAttributeScrollableDialog";
|
||||||
|
|
||||||
const AssignAttributeDialog: React.FC<AssignAttributeDialogProps> = ({
|
const AssignAttributeDialog: React.FC<AssignAttributeDialogProps> = ({
|
||||||
attributes,
|
attributes,
|
||||||
confirmButtonState,
|
confirmButtonState,
|
||||||
|
@ -126,19 +128,22 @@ const AssignAttributeDialog: React.FC<AssignAttributeDialogProps> = ({
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogContent className={classes.scrollArea} ref={anchor}>
|
<DialogContent
|
||||||
|
className={classes.scrollArea}
|
||||||
|
ref={anchor}
|
||||||
|
id={scrollableTargetId}
|
||||||
|
>
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
pageStart={0}
|
dataLength={attributes?.length}
|
||||||
loadMore={onFetchMore}
|
next={onFetchMore}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
useWindow={false}
|
scrollThreshold="100px"
|
||||||
loader={
|
loader={
|
||||||
<div className={classes.loadMoreLoaderContainer}>
|
<div className={classes.loadMoreLoaderContainer}>
|
||||||
<CircularProgress size={16} />
|
<CircularProgress size={16} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
threshold={100}
|
scrollableTarget={scrollableTargetId}
|
||||||
key="infinite-scroll"
|
|
||||||
>
|
>
|
||||||
<ResponsiveTable key="table">
|
<ResponsiveTable key="table">
|
||||||
<TableBody>
|
<TableBody>
|
||||||
|
|
|
@ -17,14 +17,13 @@ import useScrollableDialogStyle from "@saleor/styles/useScrollableDialogStyle";
|
||||||
import { makeStyles } from "@saleor/theme";
|
import { makeStyles } from "@saleor/theme";
|
||||||
import { FetchMoreProps, Node } from "@saleor/types";
|
import { FetchMoreProps, Node } from "@saleor/types";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import InfiniteScroll from "react-infinite-scroller";
|
import InfiniteScroll from "react-infinite-scroll-component";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import Checkbox from "../Checkbox";
|
import Checkbox from "../Checkbox";
|
||||||
import ConfirmButton, {
|
import ConfirmButton, {
|
||||||
ConfirmButtonTransitionState
|
ConfirmButtonTransitionState
|
||||||
} from "../ConfirmButton/ConfirmButton";
|
} from "../ConfirmButton/ConfirmButton";
|
||||||
import FormSpacer from "../FormSpacer";
|
|
||||||
|
|
||||||
export interface FormData {
|
export interface FormData {
|
||||||
containers: string[];
|
containers: string[];
|
||||||
|
@ -80,6 +79,8 @@ function handleContainerAssign(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scrollableTargetId = "assignContainerScrollableDialog";
|
||||||
|
|
||||||
const AssignContainerDialog: React.FC<AssignContainerDialogProps> = props => {
|
const AssignContainerDialog: React.FC<AssignContainerDialogProps> = props => {
|
||||||
const {
|
const {
|
||||||
confirmButtonState,
|
confirmButtonState,
|
||||||
|
@ -101,12 +102,9 @@ const AssignContainerDialog: React.FC<AssignContainerDialogProps> = props => {
|
||||||
const [selectedContainers, setSelectedContainers] = React.useState<string[]>(
|
const [selectedContainers, setSelectedContainers] = React.useState<string[]>(
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
const container = React.useRef<HTMLDivElement>();
|
|
||||||
|
|
||||||
const handleSubmit = () => onSubmit(selectedContainers);
|
const handleSubmit = () => onSubmit(selectedContainers);
|
||||||
|
|
||||||
const containerHeight = container.current?.scrollHeight - 130;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
|
@ -116,10 +114,7 @@ const AssignContainerDialog: React.FC<AssignContainerDialogProps> = props => {
|
||||||
maxWidth="sm"
|
maxWidth="sm"
|
||||||
>
|
>
|
||||||
<DialogTitle>{title}</DialogTitle>
|
<DialogTitle>{title}</DialogTitle>
|
||||||
<DialogContent
|
<DialogContent className={scrollableDialogClasses.topArea}>
|
||||||
className={scrollableDialogClasses.content}
|
|
||||||
ref={container}
|
|
||||||
>
|
|
||||||
<TextField
|
<TextField
|
||||||
name="query"
|
name="query"
|
||||||
value={query}
|
value={query}
|
||||||
|
@ -132,58 +127,57 @@ const AssignContainerDialog: React.FC<AssignContainerDialogProps> = props => {
|
||||||
endAdornment: loading && <CircularProgress size={16} />
|
endAdornment: loading && <CircularProgress size={16} />
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<FormSpacer />
|
</DialogContent>
|
||||||
<div
|
<DialogContent
|
||||||
className={scrollableDialogClasses.scrollArea}
|
className={scrollableDialogClasses.scrollArea}
|
||||||
style={{ height: containerHeight }}
|
id={scrollableTargetId}
|
||||||
|
>
|
||||||
|
<InfiniteScroll
|
||||||
|
dataLength={containers?.length}
|
||||||
|
next={onFetchMore}
|
||||||
|
hasMore={hasMore}
|
||||||
|
scrollThreshold="100px"
|
||||||
|
loader={
|
||||||
|
<div className={scrollableDialogClasses.loadMoreLoaderContainer}>
|
||||||
|
<CircularProgress size={16} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
scrollableTarget={scrollableTargetId}
|
||||||
>
|
>
|
||||||
<InfiniteScroll
|
<ResponsiveTable>
|
||||||
pageStart={0}
|
<TableBody>
|
||||||
loadMore={onFetchMore}
|
{containers?.map(container => {
|
||||||
hasMore={hasMore}
|
const isSelected = !!selectedContainers.find(
|
||||||
useWindow={false}
|
selectedContainer => selectedContainer === container.id
|
||||||
loader={
|
);
|
||||||
<div className={scrollableDialogClasses.loadMoreLoaderContainer}>
|
|
||||||
<CircularProgress size={16} />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
threshold={10}
|
|
||||||
>
|
|
||||||
<ResponsiveTable>
|
|
||||||
<TableBody>
|
|
||||||
{containers?.map(container => {
|
|
||||||
const isSelected = !!selectedContainers.find(
|
|
||||||
selectedContainer => selectedContainer === container.id
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow key={container.id}>
|
<TableRow key={container.id}>
|
||||||
<TableCell
|
<TableCell
|
||||||
padding="checkbox"
|
padding="checkbox"
|
||||||
className={classes.checkboxCell}
|
className={classes.checkboxCell}
|
||||||
>
|
>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={isSelected}
|
checked={isSelected}
|
||||||
onChange={() =>
|
onChange={() =>
|
||||||
handleContainerAssign(
|
handleContainerAssign(
|
||||||
container.id,
|
container.id,
|
||||||
isSelected,
|
isSelected,
|
||||||
selectedContainers,
|
selectedContainers,
|
||||||
setSelectedContainers
|
setSelectedContainers
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={classes.wideCell}>
|
<TableCell className={classes.wideCell}>
|
||||||
{container.name}
|
{container.name}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</ResponsiveTable>
|
</ResponsiveTable>
|
||||||
</InfiniteScroll>
|
</InfiniteScroll>
|
||||||
</div>
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={onClose}>
|
<Button onClick={onClose}>
|
||||||
|
|
|
@ -13,7 +13,6 @@ import {
|
||||||
import ConfirmButton, {
|
import ConfirmButton, {
|
||||||
ConfirmButtonTransitionState
|
ConfirmButtonTransitionState
|
||||||
} from "@saleor/components/ConfirmButton";
|
} from "@saleor/components/ConfirmButton";
|
||||||
import FormSpacer from "@saleor/components/FormSpacer";
|
|
||||||
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||||
import TableCellAvatar from "@saleor/components/TableCellAvatar";
|
import TableCellAvatar from "@saleor/components/TableCellAvatar";
|
||||||
import useSearchQuery from "@saleor/hooks/useSearchQuery";
|
import useSearchQuery from "@saleor/hooks/useSearchQuery";
|
||||||
|
@ -24,7 +23,7 @@ import useScrollableDialogStyle from "@saleor/styles/useScrollableDialogStyle";
|
||||||
import { makeStyles } from "@saleor/theme";
|
import { makeStyles } from "@saleor/theme";
|
||||||
import { FetchMoreProps } from "@saleor/types";
|
import { FetchMoreProps } from "@saleor/types";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import InfiniteScroll from "react-infinite-scroller";
|
import InfiniteScroll from "react-infinite-scroll-component";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import Checkbox from "../Checkbox";
|
import Checkbox from "../Checkbox";
|
||||||
|
@ -80,6 +79,8 @@ function handleProductAssign(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scrollableTargetId = "assignProductScrollableDialog";
|
||||||
|
|
||||||
const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
|
const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
|
||||||
const {
|
const {
|
||||||
confirmButtonState,
|
confirmButtonState,
|
||||||
|
@ -100,12 +101,9 @@ const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
|
||||||
const [selectedProducts, setSelectedProducts] = React.useState<
|
const [selectedProducts, setSelectedProducts] = React.useState<
|
||||||
SearchProducts_search_edges_node[]
|
SearchProducts_search_edges_node[]
|
||||||
>([]);
|
>([]);
|
||||||
const container = React.useRef<HTMLDivElement>();
|
|
||||||
|
|
||||||
const handleSubmit = () => onSubmit(selectedProducts);
|
const handleSubmit = () => onSubmit(selectedProducts);
|
||||||
|
|
||||||
const containerHeight = container.current?.scrollHeight - 130;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
|
@ -120,10 +118,7 @@ const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
|
||||||
description="dialog header"
|
description="dialog header"
|
||||||
/>
|
/>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent
|
<DialogContent className={scrollableDialogClasses.topArea}>
|
||||||
className={scrollableDialogClasses.content}
|
|
||||||
ref={container}
|
|
||||||
>
|
|
||||||
<TextField
|
<TextField
|
||||||
name="query"
|
name="query"
|
||||||
value={query}
|
value={query}
|
||||||
|
@ -141,66 +136,65 @@ const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
|
||||||
endAdornment: loading && <CircularProgress size={16} />
|
endAdornment: loading && <CircularProgress size={16} />
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<FormSpacer />
|
</DialogContent>
|
||||||
<div
|
<DialogContent
|
||||||
className={scrollableDialogClasses.scrollArea}
|
className={scrollableDialogClasses.scrollArea}
|
||||||
style={{ height: containerHeight }}
|
id={scrollableTargetId}
|
||||||
|
>
|
||||||
|
<InfiniteScroll
|
||||||
|
dataLength={products?.length}
|
||||||
|
next={onFetchMore}
|
||||||
|
hasMore={hasMore}
|
||||||
|
scrollThreshold="100px"
|
||||||
|
loader={
|
||||||
|
<div className={scrollableDialogClasses.loadMoreLoaderContainer}>
|
||||||
|
<CircularProgress size={16} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
scrollableTarget={scrollableTargetId}
|
||||||
>
|
>
|
||||||
<InfiniteScroll
|
<ResponsiveTable key="table">
|
||||||
pageStart={0}
|
<TableBody>
|
||||||
loadMore={onFetchMore}
|
{products &&
|
||||||
hasMore={hasMore}
|
products.map(product => {
|
||||||
useWindow={false}
|
const isSelected = selectedProducts.some(
|
||||||
loader={
|
selectedProduct => selectedProduct.id === product.id
|
||||||
<div className={scrollableDialogClasses.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 (
|
return (
|
||||||
<TableRow
|
<TableRow
|
||||||
key={product.id}
|
key={product.id}
|
||||||
data-test-id="assign-product-table-row"
|
data-test-id="assign-product-table-row"
|
||||||
|
>
|
||||||
|
<TableCellAvatar
|
||||||
|
className={classes.avatar}
|
||||||
|
thumbnail={maybe(() => product.thumbnail.url)}
|
||||||
|
/>
|
||||||
|
<TableCell className={classes.colName}>
|
||||||
|
{product.name}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell
|
||||||
|
padding="checkbox"
|
||||||
|
className={classes.checkboxCell}
|
||||||
>
|
>
|
||||||
<TableCellAvatar
|
<Checkbox
|
||||||
className={classes.avatar}
|
checked={isSelected}
|
||||||
thumbnail={maybe(() => product.thumbnail.url)}
|
onChange={() =>
|
||||||
|
handleProductAssign(
|
||||||
|
product,
|
||||||
|
isSelected,
|
||||||
|
selectedProducts,
|
||||||
|
setSelectedProducts
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<TableCell className={classes.colName}>
|
</TableCell>
|
||||||
{product.name}
|
</TableRow>
|
||||||
</TableCell>
|
);
|
||||||
<TableCell
|
})}
|
||||||
padding="checkbox"
|
</TableBody>
|
||||||
className={classes.checkboxCell}
|
</ResponsiveTable>
|
||||||
>
|
</InfiniteScroll>
|
||||||
<Checkbox
|
|
||||||
checked={isSelected}
|
|
||||||
onChange={() =>
|
|
||||||
handleProductAssign(
|
|
||||||
product,
|
|
||||||
isSelected,
|
|
||||||
selectedProducts,
|
|
||||||
setSelectedProducts
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TableBody>
|
|
||||||
</ResponsiveTable>
|
|
||||||
</InfiniteScroll>
|
|
||||||
</div>
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={onClose}>
|
<Button onClick={onClose}>
|
||||||
|
|
|
@ -43,7 +43,6 @@ const ColumnPicker: React.FC<ColumnPickerProps> = props => {
|
||||||
hasMore,
|
hasMore,
|
||||||
initialColumns,
|
initialColumns,
|
||||||
initialOpen = false,
|
initialOpen = false,
|
||||||
loading,
|
|
||||||
total,
|
total,
|
||||||
onFetchMore,
|
onFetchMore,
|
||||||
onSave
|
onSave
|
||||||
|
@ -100,7 +99,6 @@ const ColumnPicker: React.FC<ColumnPickerProps> = props => {
|
||||||
<ColumnPickerContent
|
<ColumnPickerContent
|
||||||
columns={columns}
|
columns={columns}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
loading={loading}
|
|
||||||
selectedColumns={selectedColumns}
|
selectedColumns={selectedColumns}
|
||||||
total={total}
|
total={total}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { FetchMoreProps } from "@saleor/types";
|
||||||
import { isSelected } from "@saleor/utils/lists";
|
import { isSelected } from "@saleor/utils/lists";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import InfiniteScroll from "react-infinite-scroller";
|
import InfiniteScroll from "react-infinite-scroll-component";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import ControlledCheckbox from "../ControlledCheckbox";
|
import ControlledCheckbox from "../ControlledCheckbox";
|
||||||
|
@ -52,12 +52,12 @@ const useStyles = makeStyles(
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gridColumnGap: theme.spacing(3),
|
gridColumnGap: theme.spacing(3),
|
||||||
gridTemplateColumns: "repeat(3, 1fr)",
|
gridTemplateColumns: "repeat(3, 1fr)",
|
||||||
maxHeight: 256,
|
|
||||||
overflowX: "visible",
|
|
||||||
overflowY: "scroll",
|
|
||||||
padding: theme.spacing(2, 3)
|
padding: theme.spacing(2, 3)
|
||||||
},
|
},
|
||||||
contentContainer: {
|
contentContainer: {
|
||||||
|
maxHeight: 256,
|
||||||
|
overflowX: "visible",
|
||||||
|
overflowY: "scroll",
|
||||||
padding: 0
|
padding: 0
|
||||||
},
|
},
|
||||||
dropShadow: {
|
dropShadow: {
|
||||||
|
@ -80,11 +80,12 @@ const useStyles = makeStyles(
|
||||||
{ name: "ColumnPickerContent" }
|
{ name: "ColumnPickerContent" }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const scrollableTargetId = "columnPickerScrollableDiv";
|
||||||
|
|
||||||
const ColumnPickerContent: React.FC<ColumnPickerContentProps> = props => {
|
const ColumnPickerContent: React.FC<ColumnPickerContentProps> = props => {
|
||||||
const {
|
const {
|
||||||
columns,
|
columns,
|
||||||
hasMore,
|
hasMore,
|
||||||
loading,
|
|
||||||
selectedColumns,
|
selectedColumns,
|
||||||
total,
|
total,
|
||||||
onCancel,
|
onCancel,
|
||||||
|
@ -118,41 +119,24 @@ const ColumnPickerContent: React.FC<ColumnPickerContentProps> = props => {
|
||||||
</Typography>
|
</Typography>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<Hr />
|
<Hr />
|
||||||
{hasMore && onFetchMore ? (
|
<CardContent
|
||||||
|
className={classes.contentContainer}
|
||||||
|
ref={anchor}
|
||||||
|
id={scrollableTargetId}
|
||||||
|
>
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
pageStart={0}
|
dataLength={columns.length}
|
||||||
loadMore={onFetchMore}
|
next={onFetchMore}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
useWindow={false}
|
scrollThreshold="100px"
|
||||||
threshold={100}
|
loader={
|
||||||
key="infinite-scroll"
|
<div className={classes.loadMoreLoaderContainer}>
|
||||||
>
|
<CircularProgress size={16} />
|
||||||
<CardContent className={classes.contentContainer}>
|
|
||||||
<div className={classes.content} ref={anchor}>
|
|
||||||
{columns.map(column => (
|
|
||||||
<ControlledCheckbox
|
|
||||||
checked={isSelected(
|
|
||||||
column.value,
|
|
||||||
selectedColumns,
|
|
||||||
(a, b) => a === b
|
|
||||||
)}
|
|
||||||
name={column.value}
|
|
||||||
label={column.label}
|
|
||||||
onChange={() => onColumnToggle(column.value)}
|
|
||||||
key={column.value}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
{loading && (
|
|
||||||
<div className={classes.loadMoreLoaderContainer}>
|
|
||||||
<CircularProgress size={16} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
}
|
||||||
</InfiniteScroll>
|
scrollableTarget={scrollableTargetId}
|
||||||
) : (
|
>
|
||||||
<CardContent className={classes.contentContainer}>
|
<div className={classes.content}>
|
||||||
<div className={classes.content} ref={anchor}>
|
|
||||||
{columns.map(column => (
|
{columns.map(column => (
|
||||||
<ControlledCheckbox
|
<ControlledCheckbox
|
||||||
checked={isSelected(
|
checked={isSelected(
|
||||||
|
@ -167,8 +151,8 @@ const ColumnPickerContent: React.FC<ColumnPickerContentProps> = props => {
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</InfiniteScroll>
|
||||||
)}
|
</CardContent>
|
||||||
<Hr />
|
<Hr />
|
||||||
<CardContent
|
<CardContent
|
||||||
className={classNames(classes.actionBarContainer, {
|
className={classNames(classes.actionBarContainer, {
|
||||||
|
|
|
@ -29,7 +29,7 @@ import { makeStyles } from "@saleor/theme";
|
||||||
import { ChannelProps, FetchMoreProps } from "@saleor/types";
|
import { ChannelProps, FetchMoreProps } from "@saleor/types";
|
||||||
import getOrderErrorMessage from "@saleor/utils/errors/order";
|
import getOrderErrorMessage from "@saleor/utils/errors/order";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import InfiniteScroll from "react-infinite-scroller";
|
import InfiniteScroll from "react-infinite-scroll-component";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -164,6 +164,8 @@ const onVariantAdd = (
|
||||||
)
|
)
|
||||||
: setVariants([...variants, variant]);
|
: setVariants([...variants, variant]);
|
||||||
|
|
||||||
|
const scrollableTargetId = "orderProductAddScrollableDialog";
|
||||||
|
|
||||||
const OrderProductAddDialog: React.FC<OrderProductAddDialogProps> = props => {
|
const OrderProductAddDialog: React.FC<OrderProductAddDialogProps> = props => {
|
||||||
const {
|
const {
|
||||||
confirmButtonState,
|
confirmButtonState,
|
||||||
|
@ -267,18 +269,18 @@ const OrderProductAddDialog: React.FC<OrderProductAddDialogProps> = props => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogContent className={classes.content}>
|
<DialogContent className={classes.content} id={scrollableTargetId}>
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
pageStart={0}
|
dataLength={productChoicesWithValidVariants?.length}
|
||||||
loadMore={onFetchMore}
|
next={onFetchMore}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
useWindow={false}
|
scrollThreshold="100px"
|
||||||
loader={
|
loader={
|
||||||
<div className={classes.loadMoreLoaderContainer}>
|
<div className={classes.loadMoreLoaderContainer}>
|
||||||
<CircularProgress size={16} />
|
<CircularProgress size={16} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
threshold={10}
|
scrollableTarget={scrollableTargetId}
|
||||||
>
|
>
|
||||||
<ResponsiveTable key="table">
|
<ResponsiveTable key="table">
|
||||||
<TableBody>
|
<TableBody>
|
||||||
|
|
|
@ -27,7 +27,7 @@ import { makeStyles } from "@saleor/theme";
|
||||||
import { DialogProps, FetchMoreProps, SearchPageProps } from "@saleor/types";
|
import { DialogProps, FetchMoreProps, SearchPageProps } from "@saleor/types";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import InfiniteScroll from "react-infinite-scroller";
|
import InfiniteScroll from "react-infinite-scroll-component";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
|
@ -47,9 +47,10 @@ const useStyles = makeStyles(
|
||||||
width: 32
|
width: 32
|
||||||
},
|
},
|
||||||
avatarDefault: {
|
avatarDefault: {
|
||||||
"& p": {
|
"& div": {
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
lineHeight: "47px"
|
lineHeight: 2.8,
|
||||||
|
fontSize: "0.75rem"
|
||||||
},
|
},
|
||||||
background: theme.palette.primary.main,
|
background: theme.palette.primary.main,
|
||||||
height: 32,
|
height: 32,
|
||||||
|
@ -93,7 +94,11 @@ const useStyles = makeStyles(
|
||||||
scrollArea: {
|
scrollArea: {
|
||||||
maxHeight: 400,
|
maxHeight: 400,
|
||||||
overflowY: "scroll",
|
overflowY: "scroll",
|
||||||
paddingTop: 0
|
paddingTop: 0,
|
||||||
|
paddingBottom: 0
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
marginBottom: theme.spacing(3)
|
||||||
},
|
},
|
||||||
statusText: {
|
statusText: {
|
||||||
color: "#9E9D9D"
|
color: "#9E9D9D"
|
||||||
|
@ -132,6 +137,8 @@ function handleStaffMemberAssign(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scrollableTargetId = "assignMembersScrollableDialog";
|
||||||
|
|
||||||
const AssignMembersDialog: React.FC<AssignMembersDialogProps> = ({
|
const AssignMembersDialog: React.FC<AssignMembersDialogProps> = ({
|
||||||
confirmButtonState,
|
confirmButtonState,
|
||||||
disabled,
|
disabled,
|
||||||
|
@ -187,16 +194,23 @@ const AssignMembersDialog: React.FC<AssignMembersDialogProps> = ({
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogContent className={classes.scrollArea}>
|
<DialogContent className={classes.scrollArea} id={scrollableTargetId}>
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
pageStart={0}
|
dataLength={staffMembers?.length}
|
||||||
loadMore={onFetchMore}
|
next={onFetchMore}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
useWindow={false}
|
scrollThreshold="100px"
|
||||||
threshold={100}
|
loader={
|
||||||
key="infinite-scroll"
|
<>
|
||||||
|
{staffMembers?.length > 0 && <CardSpacer />}
|
||||||
|
<div className={classes.loadMoreLoaderContainer}>
|
||||||
|
<CircularProgress size={24} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
scrollableTarget={scrollableTargetId}
|
||||||
>
|
>
|
||||||
<ResponsiveTable>
|
<ResponsiveTable className={classes.table}>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{staffMembers &&
|
{staffMembers &&
|
||||||
staffMembers.map(member => {
|
staffMembers.map(member => {
|
||||||
|
@ -267,14 +281,6 @@ const AssignMembersDialog: React.FC<AssignMembersDialogProps> = ({
|
||||||
})}
|
})}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</ResponsiveTable>
|
</ResponsiveTable>
|
||||||
{loading && (
|
|
||||||
<>
|
|
||||||
{staffMembers?.length > 0 && <CardSpacer />}
|
|
||||||
<div className={classes.loadMoreLoaderContainer}>
|
|
||||||
<CircularProgress size={24} />
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</InfiniteScroll>
|
</InfiniteScroll>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions
|
<DialogActions
|
||||||
|
|
|
@ -10,10 +10,8 @@ import PageHeader from "@saleor/components/PageHeader";
|
||||||
import { RefreshLimits_shop_limits } from "@saleor/components/Shop/types/RefreshLimits";
|
import { RefreshLimits_shop_limits } from "@saleor/components/Shop/types/RefreshLimits";
|
||||||
import { ProductListColumns } from "@saleor/config";
|
import { ProductListColumns } from "@saleor/config";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import {
|
import { AvailableInGridAttributes_availableInGrid_edges_node } from "@saleor/products/types/AvailableInGridAttributes";
|
||||||
GridAttributes_availableInGrid_edges_node,
|
import { GridAttributes_grid_edges_node } from "@saleor/products/types/GridAttributes";
|
||||||
GridAttributes_grid_edges_node
|
|
||||||
} from "@saleor/products/types/GridAttributes";
|
|
||||||
import { ProductList_products_edges_node } from "@saleor/products/types/ProductList";
|
import { ProductList_products_edges_node } from "@saleor/products/types/ProductList";
|
||||||
import { makeStyles } from "@saleor/theme";
|
import { makeStyles } from "@saleor/theme";
|
||||||
import {
|
import {
|
||||||
|
@ -44,7 +42,7 @@ export interface ProductListPageProps
|
||||||
SortPage<ProductListUrlSortField>,
|
SortPage<ProductListUrlSortField>,
|
||||||
ChannelProps {
|
ChannelProps {
|
||||||
activeAttributeSortId: string;
|
activeAttributeSortId: string;
|
||||||
availableInGridAttributes: GridAttributes_availableInGrid_edges_node[];
|
availableInGridAttributes: AvailableInGridAttributes_availableInGrid_edges_node[];
|
||||||
channelsCount: number;
|
channelsCount: number;
|
||||||
currencySymbol: string;
|
currencySymbol: string;
|
||||||
gridAttributes: GridAttributes_grid_edges_node[];
|
gridAttributes: GridAttributes_grid_edges_node[];
|
||||||
|
@ -163,7 +161,6 @@ export const ProductListPage: React.FC<ProductListPageProps> = props => {
|
||||||
columns={columns}
|
columns={columns}
|
||||||
defaultColumns={defaultSettings.columns}
|
defaultColumns={defaultSettings.columns}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
loading={loading}
|
|
||||||
initialColumns={settings.columns}
|
initialColumns={settings.columns}
|
||||||
total={
|
total={
|
||||||
columns.length -
|
columns.length -
|
||||||
|
|
|
@ -19,6 +19,10 @@ import {
|
||||||
} from "@saleor/products/types/ProductMediaById";
|
} from "@saleor/products/types/ProductMediaById";
|
||||||
import gql from "graphql-tag";
|
import gql from "graphql-tag";
|
||||||
|
|
||||||
|
import {
|
||||||
|
AvailableInGridAttributes,
|
||||||
|
AvailableInGridAttributesVariables
|
||||||
|
} from "./types/AvailableInGridAttributes";
|
||||||
import {
|
import {
|
||||||
CreateMultipleVariantsData,
|
CreateMultipleVariantsData,
|
||||||
CreateMultipleVariantsDataVariables
|
CreateMultipleVariantsDataVariables
|
||||||
|
@ -362,7 +366,7 @@ export const useProductMediaQuery = makeQuery<
|
||||||
|
|
||||||
const availableInGridAttributes = gql`
|
const availableInGridAttributes = gql`
|
||||||
${pageInfoFragment}
|
${pageInfoFragment}
|
||||||
query GridAttributes($first: Int!, $after: String, $ids: [ID!]!) {
|
query AvailableInGridAttributes($first: Int!, $after: String) {
|
||||||
availableInGrid: attributes(
|
availableInGrid: attributes(
|
||||||
first: $first
|
first: $first
|
||||||
after: $after
|
after: $after
|
||||||
|
@ -383,7 +387,15 @@ const availableInGridAttributes = gql`
|
||||||
}
|
}
|
||||||
totalCount
|
totalCount
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export const useAvailableInGridAttributesQuery = makeQuery<
|
||||||
|
AvailableInGridAttributes,
|
||||||
|
AvailableInGridAttributesVariables
|
||||||
|
>(availableInGridAttributes);
|
||||||
|
|
||||||
|
const gridAttributes = gql`
|
||||||
|
query GridAttributes($ids: [ID!]!) {
|
||||||
grid: attributes(first: 25, filter: { ids: $ids }) {
|
grid: attributes(first: 25, filter: { ids: $ids }) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
|
@ -394,10 +406,10 @@ const availableInGridAttributes = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const useAvailableInGridAttributesQuery = makeQuery<
|
export const useGridAttributesQuery = makeQuery<
|
||||||
GridAttributes,
|
GridAttributes,
|
||||||
GridAttributesVariables
|
GridAttributesVariables
|
||||||
>(availableInGridAttributes);
|
>(gridAttributes);
|
||||||
|
|
||||||
const createMultipleVariantsData = gql`
|
const createMultipleVariantsData = gql`
|
||||||
${productVariantAttributesFragment}
|
${productVariantAttributesFragment}
|
||||||
|
|
43
src/products/types/AvailableInGridAttributes.ts
Normal file
43
src/products/types/AvailableInGridAttributes.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @generated
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL query operation: AvailableInGridAttributes
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface AvailableInGridAttributes_availableInGrid_edges_node {
|
||||||
|
__typename: "Attribute";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AvailableInGridAttributes_availableInGrid_edges {
|
||||||
|
__typename: "AttributeCountableEdge";
|
||||||
|
node: AvailableInGridAttributes_availableInGrid_edges_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AvailableInGridAttributes_availableInGrid_pageInfo {
|
||||||
|
__typename: "PageInfo";
|
||||||
|
endCursor: string | null;
|
||||||
|
hasNextPage: boolean;
|
||||||
|
hasPreviousPage: boolean;
|
||||||
|
startCursor: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AvailableInGridAttributes_availableInGrid {
|
||||||
|
__typename: "AttributeCountableConnection";
|
||||||
|
edges: AvailableInGridAttributes_availableInGrid_edges[];
|
||||||
|
pageInfo: AvailableInGridAttributes_availableInGrid_pageInfo;
|
||||||
|
totalCount: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AvailableInGridAttributes {
|
||||||
|
availableInGrid: AvailableInGridAttributes_availableInGrid | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AvailableInGridAttributesVariables {
|
||||||
|
first: number;
|
||||||
|
after?: string | null;
|
||||||
|
}
|
|
@ -7,32 +7,6 @@
|
||||||
// GraphQL query operation: GridAttributes
|
// GraphQL query operation: GridAttributes
|
||||||
// ====================================================
|
// ====================================================
|
||||||
|
|
||||||
export interface GridAttributes_availableInGrid_edges_node {
|
|
||||||
__typename: "Attribute";
|
|
||||||
id: string;
|
|
||||||
name: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GridAttributes_availableInGrid_edges {
|
|
||||||
__typename: "AttributeCountableEdge";
|
|
||||||
node: GridAttributes_availableInGrid_edges_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GridAttributes_availableInGrid_pageInfo {
|
|
||||||
__typename: "PageInfo";
|
|
||||||
endCursor: string | null;
|
|
||||||
hasNextPage: boolean;
|
|
||||||
hasPreviousPage: boolean;
|
|
||||||
startCursor: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GridAttributes_availableInGrid {
|
|
||||||
__typename: "AttributeCountableConnection";
|
|
||||||
edges: GridAttributes_availableInGrid_edges[];
|
|
||||||
pageInfo: GridAttributes_availableInGrid_pageInfo;
|
|
||||||
totalCount: number | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GridAttributes_grid_edges_node {
|
export interface GridAttributes_grid_edges_node {
|
||||||
__typename: "Attribute";
|
__typename: "Attribute";
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -50,12 +24,9 @@ export interface GridAttributes_grid {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GridAttributes {
|
export interface GridAttributes {
|
||||||
availableInGrid: GridAttributes_availableInGrid | null;
|
|
||||||
grid: GridAttributes_grid | null;
|
grid: GridAttributes_grid | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GridAttributesVariables {
|
export interface GridAttributesVariables {
|
||||||
first: number;
|
|
||||||
after?: string | null;
|
|
||||||
ids: string[];
|
ids: string[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import {
|
||||||
} from "@saleor/products/components/ProductListPage/utils";
|
} from "@saleor/products/components/ProductListPage/utils";
|
||||||
import {
|
import {
|
||||||
useAvailableInGridAttributesQuery,
|
useAvailableInGridAttributesQuery,
|
||||||
|
useGridAttributesQuery,
|
||||||
useInitialProductFilterAttributesQuery,
|
useInitialProductFilterAttributesQuery,
|
||||||
useInitialProductFilterCategoriesQuery,
|
useInitialProductFilterCategoriesQuery,
|
||||||
useInitialProductFilterCollectionsQuery,
|
useInitialProductFilterCollectionsQuery,
|
||||||
|
@ -319,8 +320,11 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
.filter(isAttributeColumnValue)
|
.filter(isAttributeColumnValue)
|
||||||
.map(getAttributeIdFromColumnValue);
|
.map(getAttributeIdFromColumnValue);
|
||||||
}
|
}
|
||||||
const attributes = useAvailableInGridAttributesQuery({
|
const availableInGridAttributes = useAvailableInGridAttributesQuery({
|
||||||
variables: { first: 6, ids: filterColumnIds(settings.columns) }
|
variables: { first: 24 }
|
||||||
|
});
|
||||||
|
const gridAttributes = useGridAttributesQuery({
|
||||||
|
variables: { ids: filterColumnIds(settings.columns) }
|
||||||
});
|
});
|
||||||
|
|
||||||
const [
|
const [
|
||||||
|
@ -376,21 +380,22 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
}}
|
}}
|
||||||
onSort={handleSort}
|
onSort={handleSort}
|
||||||
availableInGridAttributes={mapEdgesToItems(
|
availableInGridAttributes={mapEdgesToItems(
|
||||||
attributes?.data?.availableInGrid
|
availableInGridAttributes?.data?.availableInGrid
|
||||||
)}
|
)}
|
||||||
currencySymbol={selectedChannel?.currencyCode || ""}
|
currencySymbol={selectedChannel?.currencyCode || ""}
|
||||||
currentTab={currentTab}
|
currentTab={currentTab}
|
||||||
defaultSettings={defaultListSettings[ListViews.PRODUCT_LIST]}
|
defaultSettings={defaultListSettings[ListViews.PRODUCT_LIST]}
|
||||||
filterOpts={filterOpts}
|
filterOpts={filterOpts}
|
||||||
gridAttributes={mapEdgesToItems(attributes?.data?.grid)}
|
gridAttributes={mapEdgesToItems(gridAttributes?.data?.grid)}
|
||||||
totalGridAttributes={maybe(
|
totalGridAttributes={maybe(
|
||||||
() => attributes.data.availableInGrid.totalCount,
|
() => availableInGridAttributes.data.availableInGrid.totalCount,
|
||||||
0
|
0
|
||||||
)}
|
)}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
loading={attributes.loading}
|
loading={availableInGridAttributes.loading || gridAttributes.loading}
|
||||||
hasMore={maybe(
|
hasMore={maybe(
|
||||||
() => attributes.data.availableInGrid.pageInfo.hasNextPage,
|
() =>
|
||||||
|
availableInGridAttributes.data.availableInGrid.pageInfo.hasNextPage,
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
onAdd={() => navigate(productAddUrl())}
|
onAdd={() => navigate(productAddUrl())}
|
||||||
|
@ -398,7 +403,7 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
limits={limitOpts.data?.shop.limits}
|
limits={limitOpts.data?.shop.limits}
|
||||||
products={mapEdgesToItems(data?.products)}
|
products={mapEdgesToItems(data?.products)}
|
||||||
onFetchMore={() =>
|
onFetchMore={() =>
|
||||||
attributes.loadMore(
|
availableInGridAttributes.loadMore(
|
||||||
(prev, next) => {
|
(prev, next) => {
|
||||||
if (
|
if (
|
||||||
prev.availableInGrid.pageInfo.endCursor ===
|
prev.availableInGrid.pageInfo.endCursor ===
|
||||||
|
@ -419,7 +424,9 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
after: attributes.data.availableInGrid.pageInfo.endCursor
|
after:
|
||||||
|
availableInGridAttributes.data.availableInGrid.pageInfo
|
||||||
|
.endCursor
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ import { makeStyles } from "@saleor/theme";
|
||||||
import { FetchMoreProps } from "@saleor/types";
|
import { FetchMoreProps } from "@saleor/types";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { MutationFetchResult } from "react-apollo";
|
import { MutationFetchResult } from "react-apollo";
|
||||||
import InfiniteScroll from "react-infinite-scroller";
|
import InfiniteScroll from "react-infinite-scroll-component";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
|
@ -89,6 +89,8 @@ const handleProductAssign = (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const scrollableTargetId = "shippingMethodProductsAddScrollableDialog";
|
||||||
|
|
||||||
const ShippingMethodProductsAddDialog: React.FC<ShippingMethodProductsAddDialogProps> = props => {
|
const ShippingMethodProductsAddDialog: React.FC<ShippingMethodProductsAddDialogProps> = props => {
|
||||||
const {
|
const {
|
||||||
confirmButtonState,
|
confirmButtonState,
|
||||||
|
@ -154,18 +156,18 @@ const ShippingMethodProductsAddDialog: React.FC<ShippingMethodProductsAddDialogP
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogContent className={classes.content}>
|
<DialogContent className={classes.content} id={scrollableTargetId}>
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
pageStart={0}
|
dataLength={products?.length}
|
||||||
loadMore={onFetchMore}
|
next={onFetchMore}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
useWindow={false}
|
scrollThreshold="100px"
|
||||||
loader={
|
loader={
|
||||||
<div key="loader" className={classes.loadMoreLoaderContainer}>
|
<div key="loader" className={classes.loadMoreLoaderContainer}>
|
||||||
<CircularProgress size={16} />
|
<CircularProgress size={16} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
threshold={10}
|
scrollableTarget={scrollableTargetId}
|
||||||
>
|
>
|
||||||
<ResponsiveTable key="table">
|
<ResponsiveTable key="table">
|
||||||
<TableBody>
|
<TableBody>
|
||||||
|
|
|
@ -42,10 +42,5 @@ storiesOf("Generics / Column picker", module)
|
||||||
.addDecorator(Decorator)
|
.addDecorator(Decorator)
|
||||||
.add("default", () => <ColumnPicker {...props} />)
|
.add("default", () => <ColumnPicker {...props} />)
|
||||||
.add("loading", () => (
|
.add("loading", () => (
|
||||||
<ColumnPicker
|
<ColumnPicker {...props} hasMore={true} onFetchMore={() => undefined} />
|
||||||
{...props}
|
|
||||||
loading={true}
|
|
||||||
hasMore={true}
|
|
||||||
onFetchMore={() => undefined}
|
|
||||||
/>
|
|
||||||
));
|
));
|
||||||
|
|
|
@ -2,9 +2,6 @@ import { makeStyles } from "@saleor/theme";
|
||||||
|
|
||||||
const useScrollableDialogStyle = makeStyles(
|
const useScrollableDialogStyle = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
content: {
|
|
||||||
overflowY: "hidden"
|
|
||||||
},
|
|
||||||
dialog: {
|
dialog: {
|
||||||
height: "calc(100% - 64px)",
|
height: "calc(100% - 64px)",
|
||||||
maxHeight: 700
|
maxHeight: 700
|
||||||
|
@ -16,8 +13,13 @@ const useScrollableDialogStyle = makeStyles(
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
marginTop: theme.spacing(3)
|
marginTop: theme.spacing(3)
|
||||||
},
|
},
|
||||||
|
topArea: {
|
||||||
|
overflowY: "visible"
|
||||||
|
},
|
||||||
scrollArea: {
|
scrollArea: {
|
||||||
overflowY: "scroll"
|
overflowY: "scroll",
|
||||||
|
paddingTop: 0,
|
||||||
|
height: "inherit"
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue