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