Merge pull request #713 from mirumee/fix/no-warehouses-in-variant-creator

Add no warehouses info when working with stock quantities
This commit is contained in:
Dawid Tarasiuk 2020-10-08 12:42:10 +02:00 committed by GitHub
commit 46cadf0c48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 5374 additions and 279 deletions

View file

@ -40,6 +40,8 @@ All notable, unreleased changes to this project will be documented in this file.
- Update schema with PositiveDecimal type - #695 by @AlicjaSzu
- Add error info when fetching taxes - #701 by @dominik-zeglen
- Fix return to previous page on screen size change - #710 by @orzechdev
- Fix updating order details on address change #711 - by @orzechdev
- Add no warehouses info when working with stock quantities #713 - by @orzechdev
- Add variants reordering possibility - #716 by @orzechdev
- Fix avatar change button - #719 by @orzechdev
- Add slug field to product, collection, category & page details (update and create) - #720 by @mmarkusik
@ -104,7 +106,6 @@ All notable, unreleased changes to this project will be documented in this file.
- Update product stock management to newest design - #515 by @dominik-zeglen
- Handle untracked products - #523 by @dominik-zeglen
- Display correct error if there were no graphql errors - #525 by @dominik-zeglen
- Fix updating order details on address change #711 - by @orzechdev
## 2.0.0

View file

@ -302,6 +302,10 @@
"context": "variant stock, header",
"string": "Stock"
},
"productVariantCreatorWarehouseSectionDescription": {
"context": "no warehouses info",
"string": "There are no warehouses set up for your store. You can configure variants without providing stock quantities."
},
"productVariantCreatorWarehouseSectionHeader": {
"context": "header",
"string": "Warehouses"
@ -310,6 +314,14 @@
"context": "optional field",
"string": "Optional"
},
"productVariantWarehouseSectionDescription": {
"context": "no warehouses info",
"string": "There are no warehouses set up for your store. To add stock quantity to the variant please <a>configure a warehouse</a>"
},
"productWarehouseSectionDescription": {
"context": "no warehouses info",
"string": "There are no warehouses set up for your store. To add stock quantity to the product please <a>configure a warehouse</a>"
},
"saleDetailsPageCategoriesQuantity": {
"context": "number of categories",
"string": "Categories ({quantity})"

View file

@ -101,6 +101,7 @@ interface ProductCreatePageProps {
fetchCategories: (data: string) => void;
fetchCollections: (data: string) => void;
fetchProductTypes: (data: string) => void;
onWarehouseConfigure: () => void;
onBack?();
onSubmit?(data: ProductCreatePageSubmitData);
}
@ -124,7 +125,8 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
onBack,
fetchProductTypes,
weightUnit,
onSubmit
onSubmit,
onWarehouseConfigure
}: ProductCreatePageProps) => {
const intl = useIntl();
const localizeDate = useDateLocalize();
@ -297,6 +299,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
<ProductStocks
data={data}
disabled={disabled}
hasVariants={false}
onFormDataChange={change}
errors={errors}
stocks={stocks}
@ -320,6 +323,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
triggerChange();
removeStock(id);
}}
onWarehouseConfigure={onWarehouseConfigure}
/>
<CardSpacer />
</>

View file

@ -21,6 +21,7 @@ import CardTitle from "@saleor/components/CardTitle";
import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
import FormSpacer from "@saleor/components/FormSpacer";
import Hr from "@saleor/components/Hr";
import Link from "@saleor/components/Link";
import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment";
import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment";
import { FormChange } from "@saleor/hooks/useForm";
@ -41,12 +42,14 @@ export interface ProductStocksProps {
data: ProductStockFormData;
disabled: boolean;
errors: ProductErrorFragment[];
hasVariants: boolean;
stocks: ProductStockInput[];
warehouses: WarehouseFragment[];
onChange: FormsetChange;
onFormDataChange: FormChange;
onWarehouseStockAdd: (warehouseId: string) => void;
onWarehouseStockDelete: (warehouseId: string) => void;
onWarehouseConfigure: () => void;
}
const useStyles = makeStyles(
@ -75,6 +78,9 @@ const useStyles = makeStyles(
marginBottom: theme.spacing(2)
}
},
noWarehouseInfo: {
marginTop: theme.spacing()
},
paper: {
padding: theme.spacing(2)
},
@ -105,13 +111,15 @@ const useStyles = makeStyles(
const ProductStocks: React.FC<ProductStocksProps> = ({
data,
disabled,
hasVariants,
errors,
stocks,
warehouses,
onChange,
onFormDataChange,
onWarehouseStockAdd,
onWarehouseStockDelete
onWarehouseStockDelete,
onWarehouseConfigure
}) => {
const classes = useStyles({});
const intl = useIntl();
@ -178,108 +186,143 @@ const ProductStocks: React.FC<ProductStocksProps> = ({
</span>
</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>
<TableCell className={classes.colAction} />
</TableRow>
</TableHead>
<TableBody>
{renderCollection(stocks, stock => (
<TableRow key={stock.id}>
<TableCell className={classes.colName}>{stock.label}</TableCell>
<TableCell className={classes.colQuantity}>
<TextField
className={classes.inputComponent}
disabled={disabled}
fullWidth
inputProps={{
className: classes.input,
min: 0,
type: "number"
{!warehouses.length && (
<Typography color="textSecondary" className={classes.noWarehouseInfo}>
{hasVariants ? (
<>
<FormattedMessage
defaultMessage="There are no warehouses set up for your store. To add stock quantity to the variant please <a>configure a warehouse</a>"
description="no warehouses info"
id="productVariantWarehouseSectionDescription"
values={{
a: chunks => (
<Link onClick={onWarehouseConfigure}>{chunks}</Link>
)
}}
onChange={event => onChange(stock.id, event.target.value)}
value={stock.value}
/>
</>
) : (
<>
<FormattedMessage
defaultMessage="There are no warehouses set up for your store. To add stock quantity to the product please <a>configure a warehouse</a>"
description="no warehouses info"
id="productWarehouseSectionDescription"
values={{
a: chunks => (
<Link onClick={onWarehouseConfigure}>{chunks}</Link>
)
}}
/>
</>
)}
</Typography>
)}
</CardContent>
{warehouses.length > 0 && (
<Table>
<TableHead>
<TableRow>
<TableCell className={classes.colName}>
<FormattedMessage
defaultMessage="Warehouse Name"
description="tabel column header"
/>
</TableCell>
<TableCell className={classes.colAction}>
<IconButton
color="primary"
onClick={() => onWarehouseStockDelete(stock.id)}
>
<DeleteIcon />
</IconButton>
<TableCell className={classes.colQuantity}>
<FormattedMessage
defaultMessage="Quantity Available"
description="tabel column header"
/>
</TableCell>
<TableCell className={classes.colAction} />
</TableRow>
))}
{warehousesToAssign.length > 0 && (
<TableRow>
<TableCell colSpan={2}>
<Typography variant="body2">
<FormattedMessage
defaultMessage="Assign Warehouse"
description="button"
</TableHead>
<TableBody>
{renderCollection(stocks, stock => (
<TableRow key={stock.id}>
<TableCell className={classes.colName}>{stock.label}</TableCell>
<TableCell className={classes.colQuantity}>
<TextField
className={classes.inputComponent}
disabled={disabled}
fullWidth
inputProps={{
className: classes.input,
min: 0,
type: "number"
}}
onChange={event => onChange(stock.id, event.target.value)}
value={stock.value}
/>
</Typography>
</TableCell>
<TableCell className={classes.colAction}>
<ClickAwayListener onClickAway={() => setExpansionState(false)}>
<div ref={anchor}>
<IconButton
color="primary"
onClick={() => setExpansionState(!isExpanded)}
>
<AddIcon />
</IconButton>
<Popper
className={classes.popper}
open={isExpanded}
anchorEl={anchor.current}
transition
placement="top-end"
>
{({ TransitionProps }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin: "right top"
}}
>
<Paper className={classes.paper}>
{warehousesToAssign.map(warehouse => (
<MenuItem
className={classes.menuItem}
onClick={() =>
onWarehouseStockAdd(warehouse.id)
}
>
{warehouse.name}
</MenuItem>
))}
</Paper>
</Grow>
)}
</Popper>
</div>
</ClickAwayListener>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</TableCell>
<TableCell className={classes.colAction}>
<IconButton
color="primary"
onClick={() => onWarehouseStockDelete(stock.id)}
>
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
))}
{warehousesToAssign.length > 0 && (
<TableRow>
<TableCell colSpan={2}>
<Typography variant="body2">
<FormattedMessage
defaultMessage="Assign Warehouse"
description="button"
/>
</Typography>
</TableCell>
<TableCell className={classes.colAction}>
<ClickAwayListener
onClickAway={() => setExpansionState(false)}
>
<div ref={anchor}>
<IconButton
color="primary"
onClick={() => setExpansionState(!isExpanded)}
>
<AddIcon />
</IconButton>
<Popper
className={classes.popper}
open={isExpanded}
anchorEl={anchor.current}
transition
placement="top-end"
>
{({ TransitionProps }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin: "right top"
}}
>
<Paper className={classes.paper}>
{warehousesToAssign.map(warehouse => (
<MenuItem
className={classes.menuItem}
onClick={() =>
onWarehouseStockAdd(warehouse.id)
}
>
{warehouse.name}
</MenuItem>
))}
</Paper>
</Grow>
)}
</Popper>
</div>
</ClickAwayListener>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
)}
</Card>
);
};

View file

@ -87,6 +87,7 @@ export interface ProductUpdatePageProps extends ListActions {
onSubmit?(data: ProductUpdatePageSubmitData);
onVariantAdd?();
onSetDefaultVariant();
onWarehouseConfigure();
}
export interface ProductUpdatePageSubmitData extends ProductUpdatePageFormData {
@ -128,6 +129,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
onSetDefaultVariant,
onVariantShow,
onVariantReorder,
onWarehouseConfigure,
isChecked,
selected,
toggle,
@ -346,6 +348,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
<ProductStocks
data={data}
disabled={disabled}
hasVariants={false}
errors={errors}
stocks={stocks}
warehouses={warehouses}
@ -369,6 +372,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
triggerChange();
removeStock(id);
}}
onWarehouseConfigure={onWarehouseConfigure}
/>
</>
)}

View file

@ -58,6 +58,7 @@ interface ProductVariantCreatePageProps {
onSubmit: (data: ProductVariantCreatePageSubmitData) => void;
onVariantClick: (variantId: string) => void;
onVariantReorder: ReorderAction;
onWarehouseConfigure: () => void;
}
const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
@ -72,7 +73,8 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
onBack,
onSubmit,
onVariantClick,
onVariantReorder
onVariantReorder,
onWarehouseConfigure
}) => {
const intl = useIntl();
const attributeInput = React.useMemo(
@ -165,6 +167,7 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
<ProductStocks
data={data}
disabled={disabled}
hasVariants={true}
onFormDataChange={change}
errors={errors}
stocks={stocks}
@ -187,6 +190,7 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
triggerChange();
removeStock(id);
}}
onWarehouseConfigure={onWarehouseConfigure}
/>
<CardSpacer />
<Metadata data={data} onChange={changeMetadata} />

View file

@ -140,6 +140,17 @@ storiesOf(
step={ProductVariantCreatorStep.prices}
warehouses={[props.warehouses[0]]}
/>
))
.add("ship when no warehouses", () => (
<ProductVariantCreatorContent
{...props}
data={{
...data,
warehouses: []
}}
step={ProductVariantCreatorStep.prices}
warehouses={[]}
/>
));
storiesOf("Views / Products / Create multiple variants / summary", module)

View file

@ -123,192 +123,206 @@ const ProductVariantCreatorStock: React.FC<ProductVariantCreatorStockProps> = pr
})}
/>
<CardContent>
{warehouses.length > 1 && (
{!warehouses.length ? (
<Typography color="textSecondary">
<FormattedMessage
defaultMessage="There are no warehouses set up for your store. You can configure variants without providing stock quantities."
description="no warehouses info"
id="productVariantCreatorWarehouseSectionDescription"
/>
</Typography>
) : (
<>
<Typography className={classes.warehouseHeader} variant="h5">
<FormattedMessage
defaultMessage="Warehouses"
description="header"
id="productVariantCreatorWarehouseSectionHeader"
/>
</Typography>
<Typography className={classes.warehouseSubheader}>
<FormattedMessage
defaultMessage="Based on your selections we will create {numberOfProducts} products. Use this step to customize price and stocks for your new products"
values={{
numberOfProducts: data.attributes.reduce(
(acc, attr) => acc + attr.values.length,
0
)
}}
/>
</Typography>
<div className={classes.warehouseContainer}>
{warehouses.map(warehouse => (
<ControlledCheckbox
checked={isSelected(
warehouse.id,
data.warehouses,
(a, b) => a === b
)}
name={`warehouse:${warehouse.id}`}
label={warehouse.name}
onChange={() => onWarehouseToggle(warehouse.id)}
key={warehouse.id}
/>
))}
</div>
<CardSpacer />
<Hr />
<CardSpacer />
</>
)}
<Typography className={classes.stockHeader} variant="h5">
<FormattedMessage
defaultMessage="Stock"
description="variant stock, header"
id="productVariantCreatorStockSectionHeader"
/>
</Typography>
<RadioGroup value={data.stock.mode}>
<FormControlLabel
value="all"
control={<Radio color="primary" />}
label={intl.formatMessage({
defaultMessage: "Apply single stock to all SKUs"
})}
onChange={() => onApplyToAllChange("all")}
/>
{data.stock.mode === "all" && (
<div className={classes.stockContainer}>
{data.warehouses.map((warehouseId, warehouseIndex) => (
<div key={warehouseId}>
<Typography className={classes.warehouseName}>
{
warehouses.find(warehouse => warehouse.id === warehouseId)
.name
}
</Typography>
<TextField
fullWidth
inputProps={{
min: 0,
type: "number"
}}
label={intl.formatMessage({
defaultMessage: "Stock",
id: "productVariantCreatePricesStockInputLabel"
})}
value={data.stock.value[warehouseIndex]}
onChange={event =>
onApplyToAllStockChange(
parseInt(event.target.value, 10),
warehouseIndex
)
}
{warehouses.length > 1 && (
<>
<Typography className={classes.warehouseHeader} variant="h5">
<FormattedMessage
defaultMessage="Warehouses"
description="header"
id="productVariantCreatorWarehouseSectionHeader"
/>
</Typography>
<Typography className={classes.warehouseSubheader}>
<FormattedMessage
defaultMessage="Based on your selections we will create {numberOfProducts} products. Use this step to customize price and stocks for your new products"
values={{
numberOfProducts: data.attributes.reduce(
(acc, attr) => acc + attr.values.length,
0
)
}}
/>
</Typography>
<div className={classes.warehouseContainer}>
{warehouses.map(warehouse => (
<ControlledCheckbox
checked={isSelected(
warehouse.id,
data.warehouses,
(a, b) => a === b
)}
name={`warehouse:${warehouse.id}`}
label={warehouse.name}
onChange={() => onWarehouseToggle(warehouse.id)}
key={warehouse.id}
/>
))}
</div>
))}
</div>
)}
<FormSpacer />
<FormControlLabel
value="attribute"
control={<Radio color="primary" />}
label={intl.formatMessage({
defaultMessage: "Apply unique stock by attribute to each SKU"
})}
onChange={() => onApplyToAllChange("attribute")}
/>
{data.stock.mode === "attribute" && (
<>
<FormSpacer />
<SingleSelectField
className={classes.shortInput}
choices={attributeChoices}
label={intl.formatMessage({
defaultMessage: "Select Attribute",
description: "variant attribute"
})}
value={data.stock.attribute}
onChange={event => onAttributeSelect(event.target.value)}
<CardSpacer />
<Hr />
<CardSpacer />
</>
)}
<Typography className={classes.stockHeader} variant="h5">
<FormattedMessage
defaultMessage="Stock"
description="variant stock, header"
id="productVariantCreatorStockSectionHeader"
/>
{stockAttributeValues && (
<>
<Hr className={classes.hrAttribute} />
<FormSpacer />
<div className={classes.attributeStockScroll}>
<div className={classes.attributeStockContainer}>
<div />
{data.stock.attribute &&
data.warehouses.map(warehouseId => (
<Typography
className={classes.warehouseName}
key={warehouseId}
>
{
warehouses.find(
warehouse => warehouse.id === warehouseId
).name
}
</Typography>
))}
{stockAttributeValues.map(attributeValue => (
<React.Fragment key={attributeValue.id}>
<Typography>{attributeValue.name}</Typography>
{data.warehouses.map(
(warehouseId, warehouseIndex) => (
<TextField
fullWidth
inputProps={{
min: 0,
type: "number"
}}
label={intl.formatMessage({
defaultMessage: "Stock",
id:
"productVariantCreatePricesStockInputLabel"
})}
value={
data.stock.values.find(
value => value.slug === attributeValue.slug
).value[warehouseIndex]
}
onChange={event =>
onAttributeValueChange(
attributeValue.slug,
parseInt(event.target.value, 10),
warehouseIndex
)
}
key={warehouseId}
/>
)
)}
</React.Fragment>
))}
</Typography>
<RadioGroup value={data.stock.mode}>
<FormControlLabel
value="all"
control={<Radio color="primary" />}
label={intl.formatMessage({
defaultMessage: "Apply single stock to all SKUs"
})}
onChange={() => onApplyToAllChange("all")}
/>
{data.stock.mode === "all" && (
<div className={classes.stockContainer}>
{data.warehouses.map((warehouseId, warehouseIndex) => (
<div key={warehouseId}>
<Typography className={classes.warehouseName}>
{
warehouses.find(
warehouse => warehouse.id === warehouseId
).name
}
</Typography>
<TextField
fullWidth
inputProps={{
min: 0,
type: "number"
}}
label={intl.formatMessage({
defaultMessage: "Stock",
id: "productVariantCreatePricesStockInputLabel"
})}
value={data.stock.value[warehouseIndex]}
onChange={event =>
onApplyToAllStockChange(
parseInt(event.target.value, 10),
warehouseIndex
)
}
/>
</div>
</div>
))}
</div>
)}
<FormSpacer />
<FormControlLabel
value="attribute"
control={<Radio color="primary" />}
label={intl.formatMessage({
defaultMessage: "Apply unique stock by attribute to each SKU"
})}
onChange={() => onApplyToAllChange("attribute")}
/>
{data.stock.mode === "attribute" && (
<>
<FormSpacer />
<SingleSelectField
className={classes.shortInput}
choices={attributeChoices}
label={intl.formatMessage({
defaultMessage: "Select Attribute",
description: "variant attribute"
})}
value={data.stock.attribute}
onChange={event => onAttributeSelect(event.target.value)}
/>
{stockAttributeValues && (
<>
<Hr className={classes.hrAttribute} />
<FormSpacer />
<div className={classes.attributeStockScroll}>
<div className={classes.attributeStockContainer}>
<div />
{data.stock.attribute &&
data.warehouses.map(warehouseId => (
<Typography
className={classes.warehouseName}
key={warehouseId}
>
{
warehouses.find(
warehouse => warehouse.id === warehouseId
).name
}
</Typography>
))}
{stockAttributeValues.map(attributeValue => (
<React.Fragment key={attributeValue.id}>
<Typography>{attributeValue.name}</Typography>
{data.warehouses.map(
(warehouseId, warehouseIndex) => (
<TextField
fullWidth
inputProps={{
min: 0,
type: "number"
}}
label={intl.formatMessage({
defaultMessage: "Stock",
id:
"productVariantCreatePricesStockInputLabel"
})}
value={
data.stock.values.find(
value =>
value.slug === attributeValue.slug
).value[warehouseIndex]
}
onChange={event =>
onAttributeValueChange(
attributeValue.slug,
parseInt(event.target.value, 10),
warehouseIndex
)
}
key={warehouseId}
/>
)
)}
</React.Fragment>
))}
</div>
</div>
</>
)}
</>
)}
{data.stock.mode === "attribute" && !!data.stock.attribute && (
<>
<FormSpacer />
<Hr />
</>
)}
</>
)}
{data.stock.mode === "attribute" && !!data.stock.attribute && (
<>
<FormSpacer />
<Hr />
</>
)}
<FormSpacer />
<FormControlLabel
value="skip"
control={<Radio color="primary" />}
label={intl.formatMessage({
defaultMessage: "Skip stock for now"
})}
onChange={() => onApplyToAllChange("skip")}
/>
</RadioGroup>
<FormControlLabel
value="skip"
control={<Radio color="primary" />}
label={intl.formatMessage({
defaultMessage: "Skip stock for now"
})}
onChange={() => onApplyToAllChange("skip")}
/>
</RadioGroup>
</>
)}
</CardContent>
</Card>
);

View file

@ -70,6 +70,7 @@ interface ProductVariantPageProps {
onImageSelect(id: string);
onVariantClick(variantId: string);
onSetDefaultVariant();
onWarehouseConfigure();
}
const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
@ -88,7 +89,8 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
onSubmit,
onVariantClick,
onVariantReorder,
onSetDefaultVariant
onSetDefaultVariant,
onWarehouseConfigure
}) => {
const attributeInput = React.useMemo(
() => getAttributeInputFromVariant(variant),
@ -240,6 +242,7 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
<ProductStocks
data={data}
disabled={loading}
hasVariants={true}
errors={errors}
stocks={stocks}
warehouses={warehouses}
@ -263,6 +266,7 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
triggerChange();
removeStock(id);
}}
onWarehouseConfigure={onWarehouseConfigure}
/>
<CardSpacer />
<Metadata data={data} onChange={changeMetadata} />

View file

@ -14,6 +14,7 @@ import {
usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseList } from "@saleor/warehouses/queries";
import { warehouseAddPath } from "@saleor/warehouses/urls";
import React from "react";
import { useIntl } from "react-intl";
@ -180,6 +181,7 @@ export const ProductCreateView: React.FC = () => {
)}
onBack={handleBack}
onSubmit={handleSubmit}
onWarehouseConfigure={() => navigate(warehouseAddPath)}
saveButtonBarState={productCreateOpts.status}
fetchMoreCategories={{
hasMore: searchCategoryOpts.data?.search.pageInfo.hasNextPage,

View file

@ -33,6 +33,7 @@ import {
usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseList } from "@saleor/warehouses/queries";
import { warehouseAddPath } from "@saleor/warehouses/urls";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
@ -304,6 +305,7 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
onDelete={() => openModal("remove")}
onImageReorder={handleImageReorder}
onSubmit={handleSubmit}
onWarehouseConfigure={() => navigate(warehouseAddPath)}
onVariantAdd={handleVariantAdd}
onVariantsAdd={() => navigate(productVariantCreatorUrl(id))}
onVariantShow={variantId => () =>

View file

@ -13,6 +13,7 @@ import {
usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseList } from "@saleor/warehouses/queries";
import { warehouseAddPath } from "@saleor/warehouses/urls";
import React, { useEffect, useState } from "react";
import { useIntl } from "react-intl";
@ -215,6 +216,7 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
onDelete={() => openModal("remove")}
onImageSelect={handleImageSelect}
onSubmit={handleSubmit}
onWarehouseConfigure={() => navigate(warehouseAddPath)}
onVariantClick={variantId => {
navigate(productVariantEditUrl(productId, variantId));
}}

View file

@ -10,6 +10,7 @@ import {
usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseList } from "@saleor/warehouses/queries";
import { warehouseAddPath } from "@saleor/warehouses/urls";
import React from "react";
import { useIntl } from "react-intl";
@ -142,6 +143,7 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
onBack={handleBack}
onSubmit={handleSubmit}
onVariantClick={handleVariantClick}
onWarehouseConfigure={() => navigate(warehouseAddPath)}
onVariantReorder={handleVariantReorder}
saveButtonBarState={variantCreateResult.status}
warehouses={

File diff suppressed because it is too large Load diff

View file

@ -35,6 +35,7 @@ storiesOf("Views / Products / Create product", module)
onSubmit={() => undefined}
saveButtonBarState="default"
warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
taxTypes={taxTypes}
weightUnit="kg"
/>
@ -58,6 +59,7 @@ storiesOf("Views / Products / Create product", module)
onSubmit={() => undefined}
saveButtonBarState="default"
warehouses={undefined}
onWarehouseConfigure={() => undefined}
taxTypes={taxTypes}
weightUnit="kg"
/>
@ -87,6 +89,7 @@ storiesOf("Views / Products / Create product", module)
onSubmit={() => undefined}
saveButtonBarState="default"
warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
taxTypes={taxTypes}
weightUnit="kg"
/>

View file

@ -39,6 +39,7 @@ const props: ProductUpdatePageProps = {
onVariantReorder: () => undefined,
onVariantShow: () => undefined,
onVariantsAdd: () => undefined,
onWarehouseConfigure: () => undefined,
placeholderImage,
product,
saveButtonBarState: "default",
@ -104,6 +105,25 @@ storiesOf("Views / Products / Product edit", module)
}}
/>
))
.add("no stock, no variants and no warehouses", () => (
<ProductUpdatePage
{...props}
warehouses={[]}
product={{
...product,
productType: {
...product.productType,
hasVariants: false
},
variants: [
{
...product.variants[0],
stocks: []
}
]
}}
/>
))
.add("no product attributes", () => (
<ProductUpdatePage
{...props}

View file

@ -26,6 +26,7 @@ storiesOf("Views / Products / Create product variant", module)
onVariantReorder={() => undefined}
saveButtonBarState="default"
warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/>
))
.add("with errors", () => (
@ -58,6 +59,7 @@ storiesOf("Views / Products / Create product variant", module)
onVariantReorder={() => undefined}
saveButtonBarState="default"
warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/>
))
.add("when loading data", () => (
@ -74,6 +76,7 @@ storiesOf("Views / Products / Create product variant", module)
onVariantReorder={() => undefined}
saveButtonBarState="default"
warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/>
))
.add("add first variant", () => (
@ -93,5 +96,23 @@ storiesOf("Views / Products / Create product variant", module)
onVariantReorder={() => undefined}
saveButtonBarState="default"
warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/>
))
.add("no warehouses", () => (
<ProductVariantCreatePage
currencySymbol="USD"
weightUnit="kg"
disabled={false}
errors={[]}
header="Add variant"
product={product}
onBack={() => undefined}
onSubmit={() => undefined}
onVariantClick={undefined}
onVariantReorder={() => undefined}
saveButtonBarState="default"
warehouses={[]}
onWarehouseConfigure={() => undefined}
/>
));

View file

@ -28,6 +28,7 @@ storiesOf("Views / Products / Product variant details", module)
onVariantReorder={() => undefined}
saveButtonBarState="default"
warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/>
))
.add("when loading data", () => (
@ -47,6 +48,26 @@ storiesOf("Views / Products / Product variant details", module)
onVariantReorder={() => undefined}
saveButtonBarState="default"
warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/>
))
.add("no warehouses", () => (
<ProductVariantPage
defaultWeightUnit="kg"
header={variant.name || variant.sku}
errors={[]}
variant={variant}
onAdd={() => undefined}
onBack={() => undefined}
onDelete={undefined}
onSetDefaultVariant={() => undefined}
onImageSelect={() => undefined}
onSubmit={() => undefined}
onVariantClick={() => undefined}
onVariantReorder={() => undefined}
saveButtonBarState="default"
warehouses={[]}
onWarehouseConfigure={() => undefined}
/>
))
.add("attribute errors", () => (
@ -82,5 +103,6 @@ storiesOf("Views / Products / Product variant details", module)
...error
}))}
warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/>
));