Add no warehouses info in variant and product details

This commit is contained in:
Dawid Tarasiuk 2020-09-16 19:13:08 +02:00
parent 4cb5a1114c
commit 6065c5ded6
22 changed files with 370 additions and 120 deletions

View file

@ -304,7 +304,7 @@
},
"productVariantCreatorWarehouseSectionDescription": {
"context": "no warehouses info",
"string": "There are no warehouses set up for your store. You can configure your variants without providing stock quantites."
"string": "There are no warehouses set up for your store. You can configure variants without providing stock quantities."
},
"productVariantCreatorWarehouseSectionHeader": {
"context": "header",
@ -314,6 +314,22 @@
"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"
},
"productVariantWarehouseSectionDescriptionLink": {
"context": "no warehouses info",
"string": "configure a warehouse"
},
"productWarehouseSectionDescription": {
"context": "no warehouses info",
"string": "There are no warehouses set up for your store. To add stock quantity to the product please"
},
"productWarehouseSectionDescriptionLink": {
"context": "no warehouses info",
"string": "configure a warehouse"
},
"saleDetailsPageCategoriesQuantity": {
"context": "number of categories",
"string": "Categories ({quantity})"
@ -1577,6 +1593,10 @@
"context": "button",
"string": "{languageName} - {languageCode}"
},
"src_dot_components_dot_LeaveScreenDialog_dot_3281163715": {
"context": "leaving screen warning message",
"string": "You're leaving this screen. Do you want to save previously made changes?"
},
"src_dot_components_dot_ListField_dot_3099331554": {
"context": "button",
"string": "Add"

View file

@ -211,7 +211,7 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
disabled={loading}
errors={updateResult.data?.categoryUpdate.errors || []}
onAddCategory={() => navigate(categoryAddUrl(id))}
onAddProduct={() => navigate(productAddUrl)}
onAddProduct={() => navigate(productAddUrl())}
onBack={() =>
navigate(
maybe(() => categoryUrl(data.category.parent.id), categoryListUrl())

View file

@ -0,0 +1,54 @@
import Button from "@material-ui/core/Button";
import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
import { buttonMessages } from "@saleor/intl";
import React from "react";
import { FormattedMessage } from "react-intl";
import ConfirmButton, { ConfirmButtonTransitionState } from "../ConfirmButton";
import Form from "../Form";
export interface LeaveScreenDialogProps {
confirmButtonState: ConfirmButtonTransitionState;
open: boolean;
onClose: () => void;
onSubmit: () => void;
}
const LeaveScreenDialog: React.FC<LeaveScreenDialogProps> = ({
confirmButtonState,
onClose,
onSubmit,
open
}) => (
<Dialog onClose={onClose} open={open} fullWidth maxWidth="sm">
<Form onSubmit={onSubmit}>
{({ submit }) => (
<>
<DialogContent>
<FormattedMessage
defaultMessage="You're leaving this screen. Do you want to save previously made changes?"
description="leaving screen warning message"
/>
</DialogContent>
<DialogActions>
<Button onClick={onClose}>
<FormattedMessage {...buttonMessages.cancel} />
</Button>
<ConfirmButton
transitionState={confirmButtonState}
color="primary"
variant="contained"
onClick={submit}
>
<FormattedMessage {...buttonMessages.save} />
</ConfirmButton>
</DialogActions>
</>
)}
</Form>
</Dialog>
);
LeaveScreenDialog.displayName = "LeaveScreenDialog";
export default LeaveScreenDialog;

View file

@ -0,0 +1,2 @@
export { default } from "./LeaveScreenDialog";
export * from "./LeaveScreenDialog";

View file

@ -46,7 +46,7 @@ export function searchInCommands(
{
label: intl.formatMessage(messages.createProduct),
onClick: () => {
navigate(productAddUrl);
navigate(productAddUrl());
return false;
}
},

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);
}
@ -122,6 +123,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
warehouses,
taxTypes,
onBack,
onWarehouseConfigure,
fetchProductTypes,
weightUnit,
onSubmit
@ -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,147 @@ const ProductStocks: React.FC<ProductStocksProps> = ({
</span>
</div>
</Typography>
{!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"
description="no warehouses info"
id="productVariantWarehouseSectionDescription"
/>{" "}
<Link onClick={onWarehouseConfigure}>
<FormattedMessage
defaultMessage="configure a warehouse"
description="no warehouses info"
id="productVariantWarehouseSectionDescriptionLink"
/>
</Link>
</>
) : (
<>
<FormattedMessage
defaultMessage="There are no warehouses set up for your store. To add stock quantity to the product please"
description="no warehouses info"
id="productWarehouseSectionDescription"
/>{" "}
<Link onClick={onWarehouseConfigure}>
<FormattedMessage
defaultMessage="configure a warehouse"
description="no warehouses info"
id="productWarehouseSectionDescriptionLink"
/>
</Link>
</>
)}
</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"
}}
onChange={event => onChange(stock.id, event.target.value)}
value={stock.value}
{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

@ -126,7 +126,7 @@ const ProductVariantCreatorStock: React.FC<ProductVariantCreatorStockProps> = pr
{!warehouses.length ? (
<Typography color="textSecondary">
<FormattedMessage
defaultMessage="There are no warehouses set up for your store. You can configure your variants without providing stock quantites."
defaultMessage="There are no warehouses set up for your store. You can configure variants without providing stock quantities."
description="no warehouses info"
id="productVariantCreatorWarehouseSectionDescription"
/>

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

@ -9,6 +9,7 @@ import { Route, RouteComponentProps, Switch } from "react-router-dom";
import { WindowTitle } from "../components/WindowTitle";
import {
productAddPath,
ProductAddUrlQueryParams,
productImagePath,
ProductImageUrlQueryParams,
productListPath,
@ -17,11 +18,12 @@ import {
productPath,
ProductUrlQueryParams,
productVariantAddPath,
ProductVariantAddUrlQueryParams,
productVariantCreatorPath,
productVariantEditPath,
ProductVariantEditUrlQueryParams
} from "./urls";
import ProductCreate from "./views/ProductCreate";
import ProductCreateComponent from "./views/ProductCreate";
import ProductImageComponent from "./views/ProductImage";
import ProductListComponent from "./views/ProductList";
import ProductUpdateComponent from "./views/ProductUpdate";
@ -45,6 +47,13 @@ const ProductList: React.FC<RouteComponentProps<any>> = ({ location }) => {
return <ProductListComponent params={params} />;
};
const ProductCreate: React.FC<RouteComponentProps> = () => {
const qs = parseQs(location.search.substr(1));
const params: ProductAddUrlQueryParams = qs;
return <ProductCreateComponent params={params} />;
};
const ProductUpdate: React.FC<RouteComponentProps<any>> = ({ match }) => {
const qs = parseQs(location.search.substr(1));
const params: ProductUrlQueryParams = qs;
@ -91,11 +100,17 @@ const ProductImage: React.FC<RouteComponentProps<any>> = ({
const ProductVariantCreate: React.FC<RouteComponentProps<any>> = ({
match
}) => (
<ProductVariantCreateComponent
productId={decodeURIComponent(match.params.id)}
/>
);
}) => {
const qs = parseQs(location.search.substr(1));
const params: ProductVariantAddUrlQueryParams = qs;
return (
<ProductVariantCreateComponent
productId={decodeURIComponent(match.params.id)}
params={params}
/>
);
};
const ProductVariantCreator: React.FC<RouteComponentProps<{
id: string;

View file

@ -16,7 +16,10 @@ import { stringifyQs } from "../utils/urls";
const productSection = "/products/";
export const productAddPath = urlJoin(productSection, "add");
export const productAddUrl = productAddPath;
export type ProductAddUrlDialog = "leave-screen";
export type ProductAddUrlQueryParams = Dialog<ProductAddUrlDialog>;
export const productAddUrl = (params?: ProductAddUrlQueryParams) =>
productAddPath + "?" + stringifyQs(params);
export const productListPath = productSection;
export type ProductListUrlDialog =
@ -66,14 +69,14 @@ export const productListUrl = (params?: ProductListUrlQueryParams): string =>
productListPath + "?" + stringifyQs(params);
export const productPath = (id: string) => urlJoin(productSection + id);
export type ProductUrlDialog = "remove" | "remove-variants";
export type ProductUrlDialog = "remove" | "remove-variants" | "leave-screen";
export type ProductUrlQueryParams = BulkAction & Dialog<ProductUrlDialog>;
export const productUrl = (id: string, params?: ProductUrlQueryParams) =>
productPath(encodeURIComponent(id)) + "?" + stringifyQs(params);
export const productVariantEditPath = (productId: string, variantId: string) =>
urlJoin(productSection, productId, "variant", variantId);
export type ProductVariantEditUrlDialog = "remove";
export type ProductVariantEditUrlDialog = "remove" | "leave-screen";
export type ProductVariantEditUrlQueryParams = Dialog<
ProductVariantEditUrlDialog
>;
@ -96,8 +99,17 @@ export const productVariantCreatorUrl = (productId: string) =>
export const productVariantAddPath = (productId: string) =>
urlJoin(productSection, productId, "variant/add");
export const productVariantAddUrl = (productId: string): string =>
productVariantAddPath(encodeURIComponent(productId));
export type ProductVariantAddUrlDialog = "leave-screen";
export type ProductVariantAddUrlQueryParams = Dialog<
ProductVariantAddUrlDialog
>;
export const productVariantAddUrl = (
productId: string,
params?: ProductVariantAddUrlQueryParams
): string =>
productVariantAddPath(encodeURIComponent(productId)) +
"?" +
stringifyQs(params);
export const productImagePath = (productId: string, imageId: string) =>
urlJoin(productSection, productId, "image", imageId);

View file

@ -1,3 +1,4 @@
import LeaveScreenDialog from "@saleor/components/LeaveScreenDialog";
import { WindowTitle } from "@saleor/components/WindowTitle";
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
import useNavigator from "@saleor/hooks/useNavigator";
@ -8,12 +9,14 @@ import useCategorySearch from "@saleor/searches/useCategorySearch";
import useCollectionSearch from "@saleor/searches/useCollectionSearch";
import useProductTypeSearch from "@saleor/searches/useProductTypeSearch";
import { useTaxTypeList } from "@saleor/taxes/queries";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler";
import {
useMetadataUpdate,
usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseList } from "@saleor/warehouses/queries";
import { warehouseListPath } from "@saleor/warehouses/urls";
import React from "react";
import { useIntl } from "react-intl";
@ -25,9 +28,22 @@ import {
useProductCreateMutation,
useProductSetAvailabilityForPurchase
} from "../mutations";
import { productListUrl, productUrl } from "../urls";
import {
productAddUrl,
ProductAddUrlDialog,
ProductAddUrlQueryParams,
productListUrl,
productUrl
} from "../urls";
export const ProductCreateView: React.FC = () => {
interface ProductCreateViewProps {
params: ProductAddUrlQueryParams;
}
export const ProductCreateView: React.FC<ProductCreateViewProps> = ({
params
}) => {
const { action } = params;
const navigate = useNavigator();
const notify = useNotifier();
const shop = useShop();
@ -90,6 +106,11 @@ export const ProductCreateView: React.FC = () => {
}
});
const [openModal, closeModal] = createDialogActionHandlers<
ProductAddUrlDialog,
ProductAddUrlQueryParams
>(navigate, productAddUrl, params);
const handleCreate = async (formData: ProductCreatePageSubmitData) => {
const result = await productCreate({
variables: {
@ -196,12 +217,19 @@ export const ProductCreateView: React.FC = () => {
loading: searchProductTypesOpts.loading,
onFetchMore: loadMoreProductTypes
}}
onWarehouseConfigure={() => openModal("leave-screen")}
warehouses={
warehouses.data?.warehouses.edges.map(edge => edge.node) || []
}
taxTypes={taxTypes.data?.taxTypes || []}
weightUnit={shop?.defaultWeightUnit}
/>
<LeaveScreenDialog
onSubmit={() => navigate(warehouseListPath)}
onClose={closeModal}
open={action === "leave-screen"}
confirmButtonState="default"
/>
</>
);
};

View file

@ -344,7 +344,7 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
() => attributes.data.availableInGrid.pageInfo.hasNextPage,
false
)}
onAdd={() => navigate(productAddUrl)}
onAdd={() => navigate(productAddUrl())}
disabled={loading}
products={maybe(() => data.products.edges.map(edge => edge.node))}
onFetchMore={() =>

View file

@ -3,6 +3,7 @@ import DialogContentText from "@material-ui/core/DialogContentText";
import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete";
import ActionDialog from "@saleor/components/ActionDialog";
import LeaveScreenDialog from "@saleor/components/LeaveScreenDialog";
import NotFoundPage from "@saleor/components/NotFoundPage";
import { WindowTitle } from "@saleor/components/WindowTitle";
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
@ -33,6 +34,7 @@ import {
usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseList } from "@saleor/warehouses/queries";
import { warehouseListPath } from "@saleor/warehouses/urls";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
@ -64,6 +66,7 @@ interface ProductUpdateProps {
}
export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
const { action } = params;
const navigate = useNavigator();
const notify = useNotifier();
const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
@ -312,6 +315,7 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
onImageUpload={handleImageUpload}
onImageEdit={handleImageEdit}
onImageDelete={handleImageDelete}
onWarehouseConfigure={() => openModal("leave-screen")}
toolbar={
<IconButton
color="primary"
@ -392,6 +396,12 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
/>
</DialogContentText>
</ActionDialog>
<LeaveScreenDialog
onSubmit={() => navigate(warehouseListPath)}
onClose={closeModal}
open={action === "leave-screen"}
confirmButtonState="default"
/>
</>
);
};

View file

@ -1,4 +1,5 @@
import placeholderImg from "@assets/images/placeholder255x255.png";
import LeaveScreenDialog from "@saleor/components/LeaveScreenDialog";
import NotFoundPage from "@saleor/components/NotFoundPage";
import { WindowTitle } from "@saleor/components/WindowTitle";
import useNavigator from "@saleor/hooks/useNavigator";
@ -13,6 +14,7 @@ import {
usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseList } from "@saleor/warehouses/queries";
import { warehouseListPath } from "@saleor/warehouses/urls";
import React, { useEffect, useState } from "react";
import { useIntl } from "react-intl";
@ -51,6 +53,7 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
productId,
params
}) => {
const { action } = params;
const shop = useShop();
const navigate = useNavigator();
const notify = useNotifier();
@ -78,7 +81,7 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
const [updateMetadata] = useMetadataUpdate({});
const [updatePrivateMetadata] = usePrivateMetadataUpdate({});
const [openModal] = createDialogActionHandlers<
const [openModal, closeModal] = createDialogActionHandlers<
ProductVariantEditUrlDialog,
ProductVariantEditUrlQueryParams
>(
@ -220,6 +223,7 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
navigate(productVariantEditUrl(productId, variantId));
}}
onVariantReorder={handleVariantReorder}
onWarehouseConfigure={() => openModal("leave-screen")}
/>
<ProductVariantDeleteDialog
confirmButtonState={deleteVariantOpts.status}
@ -234,6 +238,12 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
open={params.action === "remove"}
name={data?.productVariant?.name}
/>
<LeaveScreenDialog
onSubmit={() => navigate(warehouseListPath)}
onClose={closeModal}
open={action === "leave-screen"}
confirmButtonState="default"
/>
</>
);
};

View file

@ -1,15 +1,18 @@
import LeaveScreenDialog from "@saleor/components/LeaveScreenDialog";
import NotFoundPage from "@saleor/components/NotFoundPage";
import { WindowTitle } from "@saleor/components/WindowTitle";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import useShop from "@saleor/hooks/useShop";
import { commonMessages } from "@saleor/intl";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler";
import {
useMetadataUpdate,
usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseList } from "@saleor/warehouses/queries";
import { warehouseListPath } from "@saleor/warehouses/urls";
import React from "react";
import { useIntl } from "react-intl";
@ -22,16 +25,26 @@ import {
useVariantCreateMutation
} from "../mutations";
import { useProductVariantCreateQuery } from "../queries";
import { productListUrl, productUrl, productVariantEditUrl } from "../urls";
import {
productListUrl,
productUrl,
productVariantAddUrl,
ProductVariantAddUrlDialog,
ProductVariantAddUrlQueryParams,
productVariantEditUrl
} from "../urls";
import { createVariantReorderHandler } from "./ProductUpdate/handlers";
interface ProductVariantCreateProps {
productId: string;
params: ProductVariantAddUrlQueryParams;
}
export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
productId
productId,
params
}) => {
const { action } = params;
const navigate = useNavigator();
const notify = useNotifier();
const shop = useShop();
@ -82,6 +95,11 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
reorderProductVariants({ variables })
);
const [openModal, closeModal] = createDialogActionHandlers<
ProductVariantAddUrlDialog,
ProductVariantAddUrlQueryParams
>(navigate, params => productVariantAddUrl(productId, params), params);
const handleBack = () => navigate(productUrl(productId));
const handleCreate = async (formData: ProductVariantCreatePageSubmitData) => {
const result = await variantCreate({
@ -143,12 +161,19 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
onSubmit={handleSubmit}
onVariantClick={handleVariantClick}
onVariantReorder={handleVariantReorder}
onWarehouseConfigure={() => openModal("leave-screen")}
saveButtonBarState={variantCreateResult.status}
warehouses={
warehouses.data?.warehouses.edges.map(edge => edge.node) || []
}
weightUnit={shop?.defaultWeightUnit}
/>
<LeaveScreenDialog
onSubmit={() => navigate(warehouseListPath)}
onClose={closeModal}
open={action === "leave-screen"}
confirmButtonState="default"
/>
</>
);
};

View file

@ -37,6 +37,7 @@ storiesOf("Views / Products / Create product", module)
warehouses={warehouseList}
taxTypes={taxTypes}
weightUnit="kg"
onWarehouseConfigure={() => undefined}
/>
))
.add("When loading", () => (
@ -60,6 +61,7 @@ storiesOf("Views / Products / Create product", module)
warehouses={undefined}
taxTypes={taxTypes}
weightUnit="kg"
onWarehouseConfigure={() => undefined}
/>
))
.add("form errors", () => (
@ -89,5 +91,6 @@ storiesOf("Views / Products / Create product", module)
warehouses={warehouseList}
taxTypes={taxTypes}
weightUnit="kg"
onWarehouseConfigure={() => undefined}
/>
));

View file

@ -39,6 +39,7 @@ const props: ProductUpdatePageProps = {
onVariantReorder: () => undefined,
onVariantShow: () => undefined,
onVariantsAdd: () => undefined,
onWarehouseConfigure: () => undefined,
placeholderImage,
product,
saveButtonBarState: "default",

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,6 @@ storiesOf("Views / Products / Create product variant", module)
onVariantReorder={() => undefined}
saveButtonBarState="default"
warehouses={warehouseList}
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,7 @@ storiesOf("Views / Products / Product variant details", module)
onVariantReorder={() => undefined}
saveButtonBarState="default"
warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/>
))
.add("attribute errors", () => (
@ -82,5 +84,6 @@ storiesOf("Views / Products / Product variant details", module)
...error
}))}
warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/>
));