import Button from "@material-ui/core/Button"; import CircularProgress from "@material-ui/core/CircularProgress"; import Dialog from "@material-ui/core/Dialog"; import DialogActions from "@material-ui/core/DialogActions"; import DialogContent from "@material-ui/core/DialogContent"; import DialogContentText from "@material-ui/core/DialogContentText"; import DialogTitle from "@material-ui/core/DialogTitle"; import { makeStyles } from "@material-ui/core/styles"; import TableBody from "@material-ui/core/TableBody"; import TableCell from "@material-ui/core/TableCell"; import TableRow from "@material-ui/core/TableRow"; import TextField from "@material-ui/core/TextField"; import React from "react"; import InfiniteScroll from "react-infinite-scroller"; import { FormattedMessage, useIntl } from "react-intl"; import Checkbox from "@saleor/components/Checkbox"; import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import Money from "@saleor/components/Money"; import ResponsiveTable from "@saleor/components/ResponsiveTable"; import TableCellAvatar from "@saleor/components/TableCellAvatar"; import useSearchQuery from "@saleor/hooks/useSearchQuery"; import { buttonMessages } from "@saleor/intl"; import { maybe, renderCollection } from "@saleor/misc"; import { FetchMoreProps } from "@saleor/types"; import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment"; import getOrderErrorMessage from "@saleor/utils/errors/order"; import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; import FormSpacer from "@saleor/components/FormSpacer"; import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen"; import { SearchOrderVariant_search_edges_node, SearchOrderVariant_search_edges_node_variants } from "../../types/SearchOrderVariant"; const useStyles = makeStyles( theme => ({ avatar: { paddingLeft: 0 }, colName: { paddingLeft: 0 }, colVariantCheckbox: { padding: 0 }, content: { overflowY: "scroll" }, grayText: { color: theme.palette.text.disabled }, loadMoreLoaderContainer: { alignItems: "center", display: "flex", height: theme.spacing(3), justifyContent: "center", marginTop: theme.spacing(3) }, overflow: { overflowY: "visible" }, productCheckboxCell: { "&:first-child": { paddingLeft: 0, paddingRight: 0 } }, textRight: { textAlign: "right" }, variantCheckbox: { left: theme.spacing(), position: "relative" }, wideCell: { width: "100%" } }), { name: "OrderProductAddDialog" } ); type SetVariantsAction = ( data: SearchOrderVariant_search_edges_node_variants[] ) => void; export interface OrderProductAddDialogProps extends FetchMoreProps { confirmButtonState: ConfirmButtonTransitionState; errors: OrderErrorFragment[]; open: boolean; products: SearchOrderVariant_search_edges_node[]; onClose: () => void; onFetch: (query: string) => void; onSubmit: (data: SearchOrderVariant_search_edges_node_variants[]) => void; } function hasAllVariantsSelected( productVariants: SearchOrderVariant_search_edges_node_variants[], selectedVariantsToProductsMap: SearchOrderVariant_search_edges_node_variants[] ): boolean { return productVariants.reduce( (acc, productVariant) => acc && !!selectedVariantsToProductsMap.find( selectedVariant => selectedVariant.id === productVariant.id ), true ); } function isVariantSelected( variant: SearchOrderVariant_search_edges_node_variants, selectedVariantsToProductsMap: SearchOrderVariant_search_edges_node_variants[] ): boolean { return !!selectedVariantsToProductsMap.find( selectedVariant => selectedVariant.id === variant.id ); } const onProductAdd = ( product: SearchOrderVariant_search_edges_node, productIndex: number, productsWithAllVariantsSelected: boolean[], variants: SearchOrderVariant_search_edges_node_variants[], setVariants: SetVariantsAction ) => productsWithAllVariantsSelected[productIndex] ? setVariants( variants.filter( selectedVariant => !product.variants.find( productVariant => productVariant.id === selectedVariant.id ) ) ) : setVariants([ ...variants, ...product.variants.filter( productVariant => !variants.find( selectedVariant => selectedVariant.id === productVariant.id ) ) ]); const onVariantAdd = ( variant: SearchOrderVariant_search_edges_node_variants, variantIndex: number, productIndex: number, variants: SearchOrderVariant_search_edges_node_variants[], selectedVariantsToProductsMap: boolean[][], setVariants: SetVariantsAction ) => selectedVariantsToProductsMap[productIndex][variantIndex] ? setVariants( variants.filter(selectedVariant => selectedVariant.id !== variant.id) ) : setVariants([...variants, variant]); const OrderProductAddDialog: React.FC = props => { const { confirmButtonState, errors: apiErrors, open, loading, hasMore, products, onFetch, onFetchMore, onClose, onSubmit } = props; const classes = useStyles(props); const intl = useIntl(); const [query, onQueryChange] = useSearchQuery(onFetch); const [variants, setVariants] = React.useState< SearchOrderVariant_search_edges_node_variants[] >([]); const errors = useModalDialogErrors(apiErrors, open); useModalDialogOpen(open, { onClose: () => setVariants([]) }); const selectedVariantsToProductsMap = products ? products.map(product => product.variants.map(variant => isVariantSelected(variant, variants)) ) : []; const productsWithAllVariantsSelected = products ? products.map(product => hasAllVariantsSelected(product.variants, variants) ) : []; const handleSubmit = () => onSubmit(variants); return ( }} /> } threshold={10} > {renderCollection( products, (product, productIndex) => ( onProductAdd( product, productIndex, productsWithAllVariantsSelected, variants, setVariants ) } /> product.thumbnail.url)} /> {maybe(() => product.name)} {maybe(() => product.variants, []).map( (variant, variantIndex) => ( onVariantAdd( variant, variantIndex, productIndex, variants, selectedVariantsToProductsMap, setVariants ) } />
{variant.name}
) )}
), () => ( ) )}
{errors.length > 0 && ( <> {errors.map(err => ( {getOrderErrorMessage(err, intl)} ))} )}
); }; OrderProductAddDialog.displayName = "OrderProductAddDialog"; export default OrderProductAddDialog;