Add variant stock filtering by warehouse

This commit is contained in:
dominik-zeglen 2020-02-07 17:44:42 +01:00
parent ccc51b1243
commit ee36d6046c
10 changed files with 160 additions and 16 deletions

View file

@ -53,13 +53,15 @@ const useStyles = makeStyles(
); );
export interface LinkChoiceProps { export interface LinkChoiceProps {
className?: string;
choices: SingleAutocompleteChoiceType[]; choices: SingleAutocompleteChoiceType[];
name: "country"; name?: string;
value: string; value: string;
onChange: FormChange; onChange: FormChange;
} }
const LinkChoice: React.FC<LinkChoiceProps> = ({ const LinkChoice: React.FC<LinkChoiceProps> = ({
className,
choices, choices,
name, name,
value, value,
@ -107,7 +109,7 @@ const LinkChoice: React.FC<LinkChoiceProps> = ({
return ( return (
<span <span
className={classes.root} className={classNames(classes.root, className)}
ref={anchor} ref={anchor}
onKeyDown={handleKeyPress} onKeyDown={handleKeyPress}
tabIndex={0} tabIndex={0}

View file

@ -8,7 +8,7 @@ import TableCell from "@material-ui/core/TableCell";
import TableRow from "@material-ui/core/TableRow"; import TableRow from "@material-ui/core/TableRow";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl, IntlShape } from "react-intl";
import CardTitle from "@saleor/components/CardTitle"; import CardTitle from "@saleor/components/CardTitle";
import Checkbox from "@saleor/components/Checkbox"; import Checkbox from "@saleor/components/Checkbox";
@ -16,11 +16,51 @@ import Money from "@saleor/components/Money";
import ResponsiveTable from "@saleor/components/ResponsiveTable"; import ResponsiveTable from "@saleor/components/ResponsiveTable";
import Skeleton from "@saleor/components/Skeleton"; import Skeleton from "@saleor/components/Skeleton";
import TableHead from "@saleor/components/TableHead"; import TableHead from "@saleor/components/TableHead";
import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField";
import LinkChoice from "@saleor/components/LinkChoice";
import { maybe, renderCollection } from "../../../misc"; import { maybe, renderCollection } from "../../../misc";
import { ListActions } from "../../../types"; import { ListActions } from "../../../types";
import { ProductDetails_product_variants } from "../../types/ProductDetails"; import {
ProductDetails_product_variants,
ProductDetails_product_variants_stock_warehouse
} from "../../types/ProductDetails";
import { ProductVariant_costPrice } from "../../types/ProductVariant"; import { ProductVariant_costPrice } from "../../types/ProductVariant";
function getWarehouseChoices(
variants: ProductDetails_product_variants[],
intl: IntlShape
): SingleAutocompleteChoiceType[] {
return [
{
label: intl.formatMessage({
defaultMessage: "All Warehouses",
description: "filtering option"
}),
value: null
},
...variants
.reduce<ProductDetails_product_variants_stock_warehouse[]>(
(warehouses, variant) => [
...warehouses,
...variant.stock.reduce<
ProductDetails_product_variants_stock_warehouse[]
>((variantStocks, stock) => {
if (!!warehouses.find(w => w.id === stock.warehouse.id)) {
return variantStocks;
}
return [...variantStocks, stock.warehouse];
}, [])
],
[]
)
.map(w => ({
label: w.name,
value: w.id
}))
];
}
const useStyles = makeStyles( const useStyles = makeStyles(
theme => ({ theme => ({
[theme.breakpoints.up("lg")]: { [theme.breakpoints.up("lg")]: {
@ -57,6 +97,13 @@ const useStyles = makeStyles(
}, },
textRight: { textRight: {
textAlign: "right" as "right" textAlign: "right" as "right"
},
warehouseLabel: {
display: "inline-block",
marginRight: theme.spacing()
},
warehouseSelectContainer: {
paddingTop: theme.spacing(2)
} }
}), }),
{ name: "ProductVariants" } { name: "ProductVariants" }
@ -90,6 +137,7 @@ export const ProductVariants: React.FC<ProductVariantsProps> = props => {
const classes = useStyles(props); const classes = useStyles(props);
const intl = useIntl(); const intl = useIntl();
const [warehouse, setWarehouse] = React.useState(null);
const hasVariants = maybe(() => variants.length > 0, true); const hasVariants = maybe(() => variants.length > 0, true);
return ( return (
@ -127,7 +175,23 @@ export const ProductVariants: React.FC<ProductVariantsProps> = props => {
) )
} }
/> />
{!variants.length && (
{variants.length > 0 ? (
<CardContent className={classes.warehouseSelectContainer}>
<Typography className={classes.warehouseLabel}>
<FormattedMessage
defaultMessage="Available inventoty at:"
description="variant stock status"
/>
</Typography>
<LinkChoice
choices={getWarehouseChoices(variants, intl)}
name="warehouse"
value={warehouse}
onChange={event => setWarehouse(event.target.value)}
/>
</CardContent>
) : (
<CardContent> <CardContent>
<Typography color={hasVariants ? "textPrimary" : "textSecondary"}> <Typography color={hasVariants ? "textPrimary" : "textSecondary"}>
<FormattedMessage defaultMessage="Use variants for products that come in a variety of versions for example different sizes or colors" /> <FormattedMessage defaultMessage="Use variants for products that come in a variety of versions for example different sizes or colors" />
@ -146,7 +210,7 @@ export const ProductVariants: React.FC<ProductVariantsProps> = props => {
> >
<TableCell className={classes.colName}> <TableCell className={classes.colName}>
<FormattedMessage <FormattedMessage
defaultMessage="Name" defaultMessage="Variant"
description="product variant name" description="product variant name"
/> />
</TableCell> </TableCell>
@ -175,6 +239,9 @@ export const ProductVariants: React.FC<ProductVariantsProps> = props => {
variant && variant.stock variant && variant.stock
? variant.stock.reduce((acc, s) => acc + s.quantity, 0) ? variant.stock.reduce((acc, s) => acc + s.quantity, 0)
: null; : null;
const variantStock = variant.stock.find(
s => s.warehouse.id === warehouse
);
return ( return (
<TableRow <TableRow
@ -219,19 +286,41 @@ export const ProductVariants: React.FC<ProductVariantsProps> = props => {
> >
{numAvailable === null ? ( {numAvailable === null ? (
<Skeleton /> <Skeleton />
) : numAvailable === 0 ? ( ) : warehouse === null ? (
<FormattedMessage numAvailable === 0 ? (
defaultMessage="Unavailable in all locations" <FormattedMessage
description="product variant inventory" defaultMessage="Unavailable in all locations"
/> description="product variant inventory"
/>
) : (
<FormattedMessage
defaultMessage="{numAvailable} available at {numLocations} {numLocations,plural,one{location} other{locations}}"
description="product variant inventory"
values={{
numAvailable,
numLocations: variant.stock.length
}}
/>
)
) : !!variantStock ? (
variantStock.quantity > 0 ? (
<FormattedMessage
defaultMessage="{stockQuantity} available"
description="product variant inventory"
values={{
stockQuantity: variantStock.quantity
}}
/>
) : (
<FormattedMessage
defaultMessage="Unavailable"
description="product variant inventory"
/>
)
) : ( ) : (
<FormattedMessage <FormattedMessage
defaultMessage="{numAvailable} available at {numLocations} {numLocations,plural,one{location} other{locations}}" defaultMessage="Not stocked"
description="product variant inventory" description="product variant inventory"
values={{
numAvailable,
numLocations: variant.stock.length
}}
/> />
)} )}
</TableCell> </TableCell>

View file

@ -149,6 +149,10 @@ export const productFragmentDetails = gql`
stock { stock {
id id
quantity quantity
warehouse {
id
name
}
} }
} }
productType { productType {

View file

@ -127,10 +127,17 @@ export interface Product_variants_priceOverride {
currency: string; currency: string;
} }
export interface Product_variants_stock_warehouse {
__typename: "Warehouse";
id: string;
name: string;
}
export interface Product_variants_stock { export interface Product_variants_stock {
__typename: "Stock"; __typename: "Stock";
id: string; id: string;
quantity: number; quantity: number;
warehouse: Product_variants_stock_warehouse;
} }
export interface Product_variants { export interface Product_variants {

View file

@ -133,10 +133,17 @@ export interface ProductCreate_productCreate_product_variants_priceOverride {
currency: string; currency: string;
} }
export interface ProductCreate_productCreate_product_variants_stock_warehouse {
__typename: "Warehouse";
id: string;
name: string;
}
export interface ProductCreate_productCreate_product_variants_stock { export interface ProductCreate_productCreate_product_variants_stock {
__typename: "Stock"; __typename: "Stock";
id: string; id: string;
quantity: number; quantity: number;
warehouse: ProductCreate_productCreate_product_variants_stock_warehouse;
} }
export interface ProductCreate_productCreate_product_variants { export interface ProductCreate_productCreate_product_variants {

View file

@ -127,10 +127,17 @@ export interface ProductDetails_product_variants_priceOverride {
currency: string; currency: string;
} }
export interface ProductDetails_product_variants_stock_warehouse {
__typename: "Warehouse";
id: string;
name: string;
}
export interface ProductDetails_product_variants_stock { export interface ProductDetails_product_variants_stock {
__typename: "Stock"; __typename: "Stock";
id: string; id: string;
quantity: number; quantity: number;
warehouse: ProductDetails_product_variants_stock_warehouse;
} }
export interface ProductDetails_product_variants { export interface ProductDetails_product_variants {

View file

@ -133,10 +133,17 @@ export interface ProductImageCreate_productImageCreate_product_variants_priceOve
currency: string; currency: string;
} }
export interface ProductImageCreate_productImageCreate_product_variants_stock_warehouse {
__typename: "Warehouse";
id: string;
name: string;
}
export interface ProductImageCreate_productImageCreate_product_variants_stock { export interface ProductImageCreate_productImageCreate_product_variants_stock {
__typename: "Stock"; __typename: "Stock";
id: string; id: string;
quantity: number; quantity: number;
warehouse: ProductImageCreate_productImageCreate_product_variants_stock_warehouse;
} }
export interface ProductImageCreate_productImageCreate_product_variants { export interface ProductImageCreate_productImageCreate_product_variants {

View file

@ -133,10 +133,17 @@ export interface ProductImageUpdate_productImageUpdate_product_variants_priceOve
currency: string; currency: string;
} }
export interface ProductImageUpdate_productImageUpdate_product_variants_stock_warehouse {
__typename: "Warehouse";
id: string;
name: string;
}
export interface ProductImageUpdate_productImageUpdate_product_variants_stock { export interface ProductImageUpdate_productImageUpdate_product_variants_stock {
__typename: "Stock"; __typename: "Stock";
id: string; id: string;
quantity: number; quantity: number;
warehouse: ProductImageUpdate_productImageUpdate_product_variants_stock_warehouse;
} }
export interface ProductImageUpdate_productImageUpdate_product_variants { export interface ProductImageUpdate_productImageUpdate_product_variants {

View file

@ -133,10 +133,17 @@ export interface ProductUpdate_productUpdate_product_variants_priceOverride {
currency: string; currency: string;
} }
export interface ProductUpdate_productUpdate_product_variants_stock_warehouse {
__typename: "Warehouse";
id: string;
name: string;
}
export interface ProductUpdate_productUpdate_product_variants_stock { export interface ProductUpdate_productUpdate_product_variants_stock {
__typename: "Stock"; __typename: "Stock";
id: string; id: string;
quantity: number; quantity: number;
warehouse: ProductUpdate_productUpdate_product_variants_stock_warehouse;
} }
export interface ProductUpdate_productUpdate_product_variants { export interface ProductUpdate_productUpdate_product_variants {

View file

@ -133,10 +133,17 @@ export interface SimpleProductUpdate_productUpdate_product_variants_priceOverrid
currency: string; currency: string;
} }
export interface SimpleProductUpdate_productUpdate_product_variants_stock_warehouse {
__typename: "Warehouse";
id: string;
name: string;
}
export interface SimpleProductUpdate_productUpdate_product_variants_stock { export interface SimpleProductUpdate_productUpdate_product_variants_stock {
__typename: "Stock"; __typename: "Stock";
id: string; id: string;
quantity: number; quantity: number;
warehouse: SimpleProductUpdate_productUpdate_product_variants_stock_warehouse;
} }
export interface SimpleProductUpdate_productUpdate_product_variants { export interface SimpleProductUpdate_productUpdate_product_variants {