Add stock management components to simple product
This commit is contained in:
parent
0805ff052d
commit
11a10686ce
23 changed files with 256 additions and 135 deletions
|
@ -1,96 +0,0 @@
|
||||||
import Card from "@material-ui/core/Card";
|
|
||||||
import CardContent from "@material-ui/core/CardContent";
|
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
|
||||||
import TextField from "@material-ui/core/TextField";
|
|
||||||
import React from "react";
|
|
||||||
import { useIntl } from "react-intl";
|
|
||||||
|
|
||||||
import CardTitle from "@saleor/components/CardTitle";
|
|
||||||
import { ProductErrorFragment } from "@saleor/attributes/types/ProductErrorFragment";
|
|
||||||
import { getFormErrors, getProductErrorMessage } from "@saleor/utils/errors";
|
|
||||||
import { ProductDetails_product } from "../../types/ProductDetails";
|
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
|
||||||
theme => ({
|
|
||||||
root: {
|
|
||||||
display: "grid",
|
|
||||||
gridColumnGap: theme.spacing(2),
|
|
||||||
gridTemplateColumns: "1fr 1fr"
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
{ name: "ProductStock" }
|
|
||||||
);
|
|
||||||
|
|
||||||
interface ProductStockProps {
|
|
||||||
data: {
|
|
||||||
sku: string;
|
|
||||||
stockQuantity: number;
|
|
||||||
};
|
|
||||||
disabled: boolean;
|
|
||||||
errors: ProductErrorFragment[];
|
|
||||||
product: ProductDetails_product;
|
|
||||||
onChange: (event: React.ChangeEvent<any>) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ProductStock: React.FC<ProductStockProps> = props => {
|
|
||||||
const { data, disabled, product, onChange, errors } = props;
|
|
||||||
|
|
||||||
const classes = useStyles(props);
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
const formErrors = getFormErrors(["sku", "stockQuantity"], errors);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<CardTitle
|
|
||||||
title={intl.formatMessage({
|
|
||||||
defaultMessage: "Inventory",
|
|
||||||
description: "product stock, section header",
|
|
||||||
id: "productStockHeader"
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<CardContent>
|
|
||||||
<div className={classes.root}>
|
|
||||||
<TextField
|
|
||||||
disabled={disabled}
|
|
||||||
name="sku"
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "SKU (Stock Keeping Unit)"
|
|
||||||
})}
|
|
||||||
value={data.sku}
|
|
||||||
onChange={onChange}
|
|
||||||
error={!!formErrors.sku}
|
|
||||||
helperText={getProductErrorMessage(formErrors.sku, intl)}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
disabled={disabled}
|
|
||||||
name="stockQuantity"
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Inventory",
|
|
||||||
description: "product stock",
|
|
||||||
id: "prodictStockInventoryLabel"
|
|
||||||
})}
|
|
||||||
value={data.stockQuantity}
|
|
||||||
type="number"
|
|
||||||
onChange={onChange}
|
|
||||||
helperText={
|
|
||||||
getProductErrorMessage(formErrors.stockQuantity, intl) ||
|
|
||||||
(product &&
|
|
||||||
intl.formatMessage(
|
|
||||||
{
|
|
||||||
defaultMessage: "Allocated: {quantity}",
|
|
||||||
description: "allocated product stock"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
quantity: product?.variants[0].quantityAllocated
|
|
||||||
}
|
|
||||||
))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
ProductStock.displayName = "ProductStock";
|
|
||||||
export default ProductStock;
|
|
|
@ -1,2 +0,0 @@
|
||||||
export { default } from "./ProductStock";
|
|
||||||
export * from "./ProductStock";
|
|
199
src/products/components/ProductStocks/ProductStocks.tsx
Normal file
199
src/products/components/ProductStocks/ProductStocks.tsx
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
import Button from "@material-ui/core/Button";
|
||||||
|
import Card from "@material-ui/core/Card";
|
||||||
|
import CardContent from "@material-ui/core/CardContent";
|
||||||
|
import Table from "@material-ui/core/Table";
|
||||||
|
import TableHead from "@material-ui/core/TableHead";
|
||||||
|
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 Typography from "@material-ui/core/Typography";
|
||||||
|
import React from "react";
|
||||||
|
import { useIntl, FormattedMessage } from "react-intl";
|
||||||
|
import makeStyles from "@material-ui/core/styles/makeStyles";
|
||||||
|
|
||||||
|
import { FormChange } from "@saleor/hooks/useForm";
|
||||||
|
import { FormsetChange, FormsetAtomicData } from "@saleor/hooks/useFormset";
|
||||||
|
import CardTitle from "@saleor/components/CardTitle";
|
||||||
|
import { getFieldError } from "@saleor/utils/errors";
|
||||||
|
import { UserError } from "@saleor/types";
|
||||||
|
import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
|
||||||
|
import FormSpacer from "@saleor/components/FormSpacer";
|
||||||
|
import Hr from "@saleor/components/Hr";
|
||||||
|
import { renderCollection } from "@saleor/misc";
|
||||||
|
|
||||||
|
export type ProductStockInput = FormsetAtomicData<null, string>;
|
||||||
|
export interface ProductStockFormData {
|
||||||
|
sku: string;
|
||||||
|
trackInventory: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductStocksProps {
|
||||||
|
data: ProductStockFormData;
|
||||||
|
disabled: boolean;
|
||||||
|
errors: UserError[];
|
||||||
|
stocks: ProductStockInput[];
|
||||||
|
onChange: FormsetChange;
|
||||||
|
onFormDataChange: FormChange;
|
||||||
|
onWarehousesEdit: () => undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
colName: {},
|
||||||
|
colQuantity: {
|
||||||
|
textAlign: "right",
|
||||||
|
width: 200
|
||||||
|
},
|
||||||
|
editWarehouses: {
|
||||||
|
marginRight: -theme.spacing()
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
padding: theme.spacing(1.5),
|
||||||
|
textAlign: "right"
|
||||||
|
},
|
||||||
|
inputComponent: {
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
quantityContainer: {
|
||||||
|
paddingTop: theme.spacing()
|
||||||
|
},
|
||||||
|
quantityHeader: {
|
||||||
|
alignItems: "center",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between"
|
||||||
|
},
|
||||||
|
skuInputContainer: {
|
||||||
|
display: "grid",
|
||||||
|
gridColumnGap: theme.spacing(3) + "px",
|
||||||
|
gridTemplateColumns: "repeat(2, 1fr)"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "ProductStocks"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const ProductStocks: React.FC<ProductStocksProps> = ({
|
||||||
|
data,
|
||||||
|
disabled,
|
||||||
|
errors,
|
||||||
|
stocks,
|
||||||
|
onChange,
|
||||||
|
onFormDataChange,
|
||||||
|
onWarehousesEdit
|
||||||
|
}) => {
|
||||||
|
const classes = useStyles({});
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardTitle
|
||||||
|
title={intl.formatMessage({
|
||||||
|
defaultMessage: "Inventory",
|
||||||
|
description: "product stock, section header",
|
||||||
|
id: "productStockHeader"
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<CardContent>
|
||||||
|
<div className={classes.skuInputContainer}>
|
||||||
|
<TextField
|
||||||
|
disabled={disabled}
|
||||||
|
error={!!getFieldError(errors, "sku")}
|
||||||
|
fullWidth
|
||||||
|
helperText={getFieldError(errors, "sku")?.message}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "SKU (Stock Keeping Unit)"
|
||||||
|
})}
|
||||||
|
name="sku"
|
||||||
|
onChange={onFormDataChange}
|
||||||
|
value={data.sku}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<FormSpacer />
|
||||||
|
<ControlledCheckbox
|
||||||
|
checked={data.trackInventory}
|
||||||
|
name="trackInventory"
|
||||||
|
onChange={onFormDataChange}
|
||||||
|
disabled={disabled}
|
||||||
|
label={
|
||||||
|
<>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Track Inventory"
|
||||||
|
description="product inventory, checkbox"
|
||||||
|
/>
|
||||||
|
<Typography variant="caption">
|
||||||
|
<FormattedMessage defaultMessage="Active inventory tracking will automatically calculate changes of stock" />
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</CardContent>
|
||||||
|
<Hr />
|
||||||
|
<CardContent className={classes.quantityContainer}>
|
||||||
|
<Typography>
|
||||||
|
<div className={classes.quantityHeader}>
|
||||||
|
<span>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Quantity"
|
||||||
|
description="header"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<Button
|
||||||
|
className={classes.editWarehouses}
|
||||||
|
color="primary"
|
||||||
|
data-cy="edit-warehouses"
|
||||||
|
onClick={onWarehousesEdit}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Edit Warehouses"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell className={classes.colName}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Warehouse Name"
|
||||||
|
description="tabel column header"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colQuantity}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Quantity Available"
|
||||||
|
description="tabel column header"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{renderCollection(stocks, stock => (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell className={classes.colName}>{stock.label}</TableCell>
|
||||||
|
<TableCell className={classes.colQuantity}>
|
||||||
|
<TextField
|
||||||
|
className={classes.inputComponent}
|
||||||
|
fullWidth
|
||||||
|
inputProps={{
|
||||||
|
className: classes.input,
|
||||||
|
min: 0,
|
||||||
|
type: "number"
|
||||||
|
}}
|
||||||
|
onChange={event => onChange(stock.id, event.target.value)}
|
||||||
|
value={stock.value}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProductStocks.displayName = "ProductStocks";
|
||||||
|
export default ProductStocks;
|
2
src/products/components/ProductStocks/index.ts
Normal file
2
src/products/components/ProductStocks/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./ProductStocks";
|
||||||
|
export { default } from "./ProductStocks";
|
|
@ -34,7 +34,8 @@ import {
|
||||||
getProductUpdatePageFormData,
|
getProductUpdatePageFormData,
|
||||||
getSelectedAttributesFromProduct,
|
getSelectedAttributesFromProduct,
|
||||||
ProductAttributeValueChoices,
|
ProductAttributeValueChoices,
|
||||||
ProductUpdatePageFormData
|
ProductUpdatePageFormData,
|
||||||
|
getStockInputFromProduct
|
||||||
} from "../../utils/data";
|
} from "../../utils/data";
|
||||||
import {
|
import {
|
||||||
createAttributeChangeHandler,
|
createAttributeChangeHandler,
|
||||||
|
@ -45,8 +46,8 @@ import ProductDetailsForm from "../ProductDetailsForm";
|
||||||
import ProductImages from "../ProductImages";
|
import ProductImages from "../ProductImages";
|
||||||
import ProductOrganization from "../ProductOrganization";
|
import ProductOrganization from "../ProductOrganization";
|
||||||
import ProductPricing from "../ProductPricing";
|
import ProductPricing from "../ProductPricing";
|
||||||
import ProductStock from "../ProductStock";
|
|
||||||
import ProductVariants from "../ProductVariants";
|
import ProductVariants from "../ProductVariants";
|
||||||
|
import ProductStocks, { ProductStockInput } from "../ProductStocks";
|
||||||
|
|
||||||
export interface ProductUpdatePageProps extends ListActions {
|
export interface ProductUpdatePageProps extends ListActions {
|
||||||
errors: ProductErrorFragment[];
|
errors: ProductErrorFragment[];
|
||||||
|
@ -71,7 +72,6 @@ export interface ProductUpdatePageProps extends ListActions {
|
||||||
onImageEdit?(id: string);
|
onImageEdit?(id: string);
|
||||||
onImageReorder?(event: { oldIndex: number; newIndex: number });
|
onImageReorder?(event: { oldIndex: number; newIndex: number });
|
||||||
onImageUpload(file: File);
|
onImageUpload(file: File);
|
||||||
onProductShow?();
|
|
||||||
onSeoClick?();
|
onSeoClick?();
|
||||||
onSubmit?(data: ProductUpdatePageSubmitData);
|
onSubmit?(data: ProductUpdatePageSubmitData);
|
||||||
onVariantAdd?();
|
onVariantAdd?();
|
||||||
|
@ -80,6 +80,7 @@ export interface ProductUpdatePageProps extends ListActions {
|
||||||
export interface ProductUpdatePageSubmitData extends ProductUpdatePageFormData {
|
export interface ProductUpdatePageSubmitData extends ProductUpdatePageFormData {
|
||||||
attributes: ProductAttributeInput[];
|
attributes: ProductAttributeInput[];
|
||||||
collections: string[];
|
collections: string[];
|
||||||
|
stocks: ProductStockInput[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
|
export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
|
||||||
|
@ -120,9 +121,13 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
|
||||||
() => getAttributeInputFromProduct(product),
|
() => getAttributeInputFromProduct(product),
|
||||||
[product]
|
[product]
|
||||||
);
|
);
|
||||||
|
const stockInput = React.useMemo(() => getStockInputFromProduct(product), [
|
||||||
|
product
|
||||||
|
]);
|
||||||
const { change: changeAttributeData, data: attributes } = useFormset(
|
const { change: changeAttributeData, data: attributes } = useFormset(
|
||||||
attributeInput
|
attributeInput
|
||||||
);
|
);
|
||||||
|
const { change: changeStockData, data: stocks } = useFormset(stockInput);
|
||||||
|
|
||||||
const [selectedAttributes, setSelectedAttributes] = useStateFromProps<
|
const [selectedAttributes, setSelectedAttributes] = useStateFromProps<
|
||||||
ProductAttributeValueChoices[]
|
ProductAttributeValueChoices[]
|
||||||
|
@ -149,6 +154,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
|
||||||
const handleSubmit = (data: ProductUpdatePageFormData) =>
|
const handleSubmit = (data: ProductUpdatePageFormData) =>
|
||||||
onSubmit({
|
onSubmit({
|
||||||
attributes,
|
attributes,
|
||||||
|
stocks,
|
||||||
...data
|
...data
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -239,12 +245,13 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
|
||||||
toggleAll={toggleAll}
|
toggleAll={toggleAll}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ProductStock
|
<ProductStocks
|
||||||
data={data}
|
data={data}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
product={product}
|
|
||||||
onChange={change}
|
|
||||||
errors={errors}
|
errors={errors}
|
||||||
|
stocks={stocks}
|
||||||
|
onChange={changeStockData}
|
||||||
|
onFormDataChange={change}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
|
|
|
@ -22,7 +22,7 @@ import { maybe, renderCollection } from "../../../misc";
|
||||||
import { ListActions } from "../../../types";
|
import { ListActions } from "../../../types";
|
||||||
import {
|
import {
|
||||||
ProductDetails_product_variants,
|
ProductDetails_product_variants,
|
||||||
ProductDetails_product_variants_stock_warehouse
|
ProductDetails_product_variants_stocks_warehouse
|
||||||
} from "../../types/ProductDetails";
|
} from "../../types/ProductDetails";
|
||||||
import { ProductVariant_costPrice } from "../../types/ProductVariant";
|
import { ProductVariant_costPrice } from "../../types/ProductVariant";
|
||||||
|
|
||||||
|
@ -39,11 +39,11 @@ function getWarehouseChoices(
|
||||||
value: null
|
value: null
|
||||||
},
|
},
|
||||||
...variants
|
...variants
|
||||||
.reduce<ProductDetails_product_variants_stock_warehouse[]>(
|
.reduce<ProductDetails_product_variants_stocks_warehouse[]>(
|
||||||
(warehouses, variant) => [
|
(warehouses, variant) => [
|
||||||
...warehouses,
|
...warehouses,
|
||||||
...variant.stock.reduce<
|
...variant.stocks.reduce<
|
||||||
ProductDetails_product_variants_stock_warehouse[]
|
ProductDetails_product_variants_stocks_warehouse[]
|
||||||
>((variantStocks, stock) => {
|
>((variantStocks, stock) => {
|
||||||
if (!!warehouses.find(w => w.id === stock.warehouse.id)) {
|
if (!!warehouses.find(w => w.id === stock.warehouse.id)) {
|
||||||
return variantStocks;
|
return variantStocks;
|
||||||
|
@ -118,7 +118,7 @@ function getAvailabilityLabel(
|
||||||
variant: ProductDetails_product_variants,
|
variant: ProductDetails_product_variants,
|
||||||
numAvailable: number
|
numAvailable: number
|
||||||
): string {
|
): string {
|
||||||
const variantStock = variant.stock.find(s => s.warehouse.id === warehouse);
|
const variantStock = variant.stocks.find(s => s.warehouse.id === warehouse);
|
||||||
|
|
||||||
if (!!warehouse) {
|
if (!!warehouse) {
|
||||||
if (!!variantStock) {
|
if (!!variantStock) {
|
||||||
|
@ -155,7 +155,7 @@ function getAvailabilityLabel(
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
numAvailable,
|
numAvailable,
|
||||||
numLocations: variant.stock.length
|
numLocations: variant.stocks.length
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -295,8 +295,8 @@ export const ProductVariants: React.FC<ProductVariantsProps> = props => {
|
||||||
{renderCollection(variants, variant => {
|
{renderCollection(variants, variant => {
|
||||||
const isSelected = variant ? isChecked(variant.id) : false;
|
const isSelected = variant ? isChecked(variant.id) : false;
|
||||||
const numAvailable =
|
const numAvailable =
|
||||||
variant && variant.stock
|
variant && variant.stocks
|
||||||
? variant.stock.reduce((acc, s) => acc + s.quantity, 0)
|
? variant.stocks.reduce((acc, s) => acc + s.quantity, 0)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -260,10 +260,8 @@ export const product: (
|
||||||
amount: 678.78,
|
amount: 678.78,
|
||||||
currency: "USD"
|
currency: "USD"
|
||||||
},
|
},
|
||||||
quantity: 12,
|
|
||||||
quantityAllocated: 1,
|
|
||||||
sku: "87192-94370",
|
sku: "87192-94370",
|
||||||
stock: [
|
stocks: [
|
||||||
{
|
{
|
||||||
__typename: "Stock",
|
__typename: "Stock",
|
||||||
id: "1",
|
id: "1",
|
||||||
|
@ -277,7 +275,7 @@ export const product: (
|
||||||
warehouse: warehouseList[1]
|
warehouse: warehouseList[1]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
stockQuantity: 48
|
trackInventory: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
__typename: "ProductVariant",
|
__typename: "ProductVariant",
|
||||||
|
@ -297,10 +295,8 @@ export const product: (
|
||||||
margin: 7,
|
margin: 7,
|
||||||
name: "silver",
|
name: "silver",
|
||||||
priceOverride: null,
|
priceOverride: null,
|
||||||
quantity: 12,
|
|
||||||
quantityAllocated: 1,
|
|
||||||
sku: "69055-15190",
|
sku: "69055-15190",
|
||||||
stock: [
|
stocks: [
|
||||||
{
|
{
|
||||||
__typename: "Stock",
|
__typename: "Stock",
|
||||||
id: "1",
|
id: "1",
|
||||||
|
@ -308,7 +304,7 @@ export const product: (
|
||||||
warehouse: warehouseList[0]
|
warehouse: warehouseList[0]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
stockQuantity: 14
|
trackInventory: false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
|
@ -158,6 +158,7 @@ export const productFragmentDetails = gql`
|
||||||
stocks {
|
stocks {
|
||||||
...StockFragment
|
...StockFragment
|
||||||
}
|
}
|
||||||
|
trackInventory
|
||||||
}
|
}
|
||||||
productType {
|
productType {
|
||||||
id
|
id
|
||||||
|
@ -225,6 +226,7 @@ export const fragmentVariant = gql`
|
||||||
stocks {
|
stocks {
|
||||||
...StockFragment
|
...StockFragment
|
||||||
}
|
}
|
||||||
|
trackInventory
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,7 @@ export interface Product_variants {
|
||||||
priceOverride: Product_variants_priceOverride | null;
|
priceOverride: Product_variants_priceOverride | null;
|
||||||
margin: number | null;
|
margin: number | null;
|
||||||
stocks: (Product_variants_stocks | null)[] | null;
|
stocks: (Product_variants_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Product_productType {
|
export interface Product_productType {
|
||||||
|
|
|
@ -154,6 +154,7 @@ export interface ProductCreate_productCreate_product_variants {
|
||||||
priceOverride: ProductCreate_productCreate_product_variants_priceOverride | null;
|
priceOverride: ProductCreate_productCreate_product_variants_priceOverride | null;
|
||||||
margin: number | null;
|
margin: number | null;
|
||||||
stocks: (ProductCreate_productCreate_product_variants_stocks | null)[] | null;
|
stocks: (ProductCreate_productCreate_product_variants_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProductCreate_productCreate_product_productType {
|
export interface ProductCreate_productCreate_product_productType {
|
||||||
|
|
|
@ -148,6 +148,7 @@ export interface ProductDetails_product_variants {
|
||||||
priceOverride: ProductDetails_product_variants_priceOverride | null;
|
priceOverride: ProductDetails_product_variants_priceOverride | null;
|
||||||
margin: number | null;
|
margin: number | null;
|
||||||
stocks: (ProductDetails_product_variants_stocks | null)[] | null;
|
stocks: (ProductDetails_product_variants_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProductDetails_product_productType_variantAttributes_values {
|
export interface ProductDetails_product_productType_variantAttributes_values {
|
||||||
|
|
|
@ -154,6 +154,7 @@ export interface ProductImageCreate_productImageCreate_product_variants {
|
||||||
priceOverride: ProductImageCreate_productImageCreate_product_variants_priceOverride | null;
|
priceOverride: ProductImageCreate_productImageCreate_product_variants_priceOverride | null;
|
||||||
margin: number | null;
|
margin: number | null;
|
||||||
stocks: (ProductImageCreate_productImageCreate_product_variants_stocks | null)[] | null;
|
stocks: (ProductImageCreate_productImageCreate_product_variants_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProductImageCreate_productImageCreate_product_productType {
|
export interface ProductImageCreate_productImageCreate_product_productType {
|
||||||
|
|
|
@ -154,6 +154,7 @@ export interface ProductImageUpdate_productImageUpdate_product_variants {
|
||||||
priceOverride: ProductImageUpdate_productImageUpdate_product_variants_priceOverride | null;
|
priceOverride: ProductImageUpdate_productImageUpdate_product_variants_priceOverride | null;
|
||||||
margin: number | null;
|
margin: number | null;
|
||||||
stocks: (ProductImageUpdate_productImageUpdate_product_variants_stocks | null)[] | null;
|
stocks: (ProductImageUpdate_productImageUpdate_product_variants_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProductImageUpdate_productImageUpdate_product_productType {
|
export interface ProductImageUpdate_productImageUpdate_product_productType {
|
||||||
|
|
|
@ -154,6 +154,7 @@ export interface ProductUpdate_productUpdate_product_variants {
|
||||||
priceOverride: ProductUpdate_productUpdate_product_variants_priceOverride | null;
|
priceOverride: ProductUpdate_productUpdate_product_variants_priceOverride | null;
|
||||||
margin: number | null;
|
margin: number | null;
|
||||||
stocks: (ProductUpdate_productUpdate_product_variants_stocks | null)[] | null;
|
stocks: (ProductUpdate_productUpdate_product_variants_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProductUpdate_productUpdate_product_productType {
|
export interface ProductUpdate_productUpdate_product_productType {
|
||||||
|
|
|
@ -113,4 +113,5 @@ export interface ProductVariant {
|
||||||
product: ProductVariant_product;
|
product: ProductVariant_product;
|
||||||
sku: string;
|
sku: string;
|
||||||
stocks: (ProductVariant_stocks | null)[] | null;
|
stocks: (ProductVariant_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,7 @@ export interface ProductVariantDetails_productVariant {
|
||||||
product: ProductVariantDetails_productVariant_product;
|
product: ProductVariantDetails_productVariant_product;
|
||||||
sku: string;
|
sku: string;
|
||||||
stocks: (ProductVariantDetails_productVariant_stocks | null)[] | null;
|
stocks: (ProductVariantDetails_productVariant_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProductVariantDetails {
|
export interface ProductVariantDetails {
|
||||||
|
|
|
@ -154,6 +154,7 @@ export interface SimpleProductUpdate_productUpdate_product_variants {
|
||||||
priceOverride: SimpleProductUpdate_productUpdate_product_variants_priceOverride | null;
|
priceOverride: SimpleProductUpdate_productUpdate_product_variants_priceOverride | null;
|
||||||
margin: number | null;
|
margin: number | null;
|
||||||
stocks: (SimpleProductUpdate_productUpdate_product_variants_stocks | null)[] | null;
|
stocks: (SimpleProductUpdate_productUpdate_product_variants_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SimpleProductUpdate_productUpdate_product_productType {
|
export interface SimpleProductUpdate_productUpdate_product_productType {
|
||||||
|
@ -305,6 +306,7 @@ export interface SimpleProductUpdate_productVariantUpdate_productVariant {
|
||||||
product: SimpleProductUpdate_productVariantUpdate_productVariant_product;
|
product: SimpleProductUpdate_productVariantUpdate_productVariant_product;
|
||||||
sku: string;
|
sku: string;
|
||||||
stocks: (SimpleProductUpdate_productVariantUpdate_productVariant_stocks | null)[] | null;
|
stocks: (SimpleProductUpdate_productVariantUpdate_productVariant_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SimpleProductUpdate_productVariantUpdate {
|
export interface SimpleProductUpdate_productVariantUpdate {
|
||||||
|
|
|
@ -121,6 +121,7 @@ export interface VariantCreate_productVariantCreate_productVariant {
|
||||||
product: VariantCreate_productVariantCreate_productVariant_product;
|
product: VariantCreate_productVariantCreate_productVariant_product;
|
||||||
sku: string;
|
sku: string;
|
||||||
stocks: (VariantCreate_productVariantCreate_productVariant_stocks | null)[] | null;
|
stocks: (VariantCreate_productVariantCreate_productVariant_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VariantCreate_productVariantCreate {
|
export interface VariantCreate_productVariantCreate {
|
||||||
|
|
|
@ -121,6 +121,7 @@ export interface VariantImageAssign_variantImageAssign_productVariant {
|
||||||
product: VariantImageAssign_variantImageAssign_productVariant_product;
|
product: VariantImageAssign_variantImageAssign_productVariant_product;
|
||||||
sku: string;
|
sku: string;
|
||||||
stocks: (VariantImageAssign_variantImageAssign_productVariant_stocks | null)[] | null;
|
stocks: (VariantImageAssign_variantImageAssign_productVariant_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VariantImageAssign_variantImageAssign {
|
export interface VariantImageAssign_variantImageAssign {
|
||||||
|
|
|
@ -121,6 +121,7 @@ export interface VariantImageUnassign_variantImageUnassign_productVariant {
|
||||||
product: VariantImageUnassign_variantImageUnassign_productVariant_product;
|
product: VariantImageUnassign_variantImageUnassign_productVariant_product;
|
||||||
sku: string;
|
sku: string;
|
||||||
stocks: (VariantImageUnassign_variantImageUnassign_productVariant_stocks | null)[] | null;
|
stocks: (VariantImageUnassign_variantImageUnassign_productVariant_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VariantImageUnassign_variantImageUnassign {
|
export interface VariantImageUnassign_variantImageUnassign {
|
||||||
|
|
|
@ -121,6 +121,7 @@ export interface VariantUpdate_productVariantUpdate_productVariant {
|
||||||
product: VariantUpdate_productVariantUpdate_productVariant_product;
|
product: VariantUpdate_productVariantUpdate_productVariant_product;
|
||||||
sku: string;
|
sku: string;
|
||||||
stocks: (VariantUpdate_productVariantUpdate_productVariant_stocks | null)[] | null;
|
stocks: (VariantUpdate_productVariantUpdate_productVariant_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VariantUpdate_productVariantUpdate {
|
export interface VariantUpdate_productVariantUpdate {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { ProductAttributeInput } from "../components/ProductAttributes";
|
||||||
import { VariantAttributeInput } from "../components/ProductVariantAttributes";
|
import { VariantAttributeInput } from "../components/ProductVariantAttributes";
|
||||||
import { ProductVariant } from "../types/ProductVariant";
|
import { ProductVariant } from "../types/ProductVariant";
|
||||||
import { ProductVariantCreateData_product } from "../types/ProductVariantCreateData";
|
import { ProductVariantCreateData_product } from "../types/ProductVariantCreateData";
|
||||||
|
import { ProductStockInput } from "../components/ProductStocks";
|
||||||
|
|
||||||
export interface Collection {
|
export interface Collection {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -117,6 +118,17 @@ export function getVariantAttributeInputFromProduct(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getStockInputFromProduct(
|
||||||
|
product: ProductDetails_product
|
||||||
|
): ProductStockInput[] {
|
||||||
|
return product?.variants[0].stocks.map(stock => ({
|
||||||
|
data: null,
|
||||||
|
id: stock.warehouse.id,
|
||||||
|
label: stock.warehouse.name,
|
||||||
|
value: stock.quantity.toString()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
export function getCollectionInput(
|
export function getCollectionInput(
|
||||||
productCollections: ProductDetails_product_collections[]
|
productCollections: ProductDetails_product_collections[]
|
||||||
): Collection[] {
|
): Collection[] {
|
||||||
|
@ -153,7 +165,7 @@ export interface ProductUpdatePageFormData {
|
||||||
seoDescription: string;
|
seoDescription: string;
|
||||||
seoTitle: string;
|
seoTitle: string;
|
||||||
sku: string;
|
sku: string;
|
||||||
stockQuantity: number;
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getProductUpdatePageFormData(
|
export function getProductUpdatePageFormData(
|
||||||
|
@ -183,14 +195,6 @@ export function getProductUpdatePageFormData(
|
||||||
: undefined,
|
: undefined,
|
||||||
""
|
""
|
||||||
),
|
),
|
||||||
stockQuantity: maybe(
|
trackInventory: !!product?.variants[0]?.trackInventory
|
||||||
() =>
|
|
||||||
product.productType.hasVariants
|
|
||||||
? undefined
|
|
||||||
: variants && variants[0]
|
|
||||||
? variants[0].quantity
|
|
||||||
: undefined,
|
|
||||||
0
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,11 +232,6 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
|
||||||
variants={maybe(() => product.variants)}
|
variants={maybe(() => product.variants)}
|
||||||
onBack={handleBack}
|
onBack={handleBack}
|
||||||
onDelete={() => openModal("remove")}
|
onDelete={() => openModal("remove")}
|
||||||
onProductShow={() => {
|
|
||||||
if (product) {
|
|
||||||
window.open(product.url);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onImageReorder={handleImageReorder}
|
onImageReorder={handleImageReorder}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
onVariantAdd={handleVariantAdd}
|
onVariantAdd={handleVariantAdd}
|
||||||
|
|
Loading…
Reference in a new issue