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": { "productVariantCreatorWarehouseSectionDescription": {
"context": "no warehouses info", "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": { "productVariantCreatorWarehouseSectionHeader": {
"context": "header", "context": "header",
@ -314,6 +314,22 @@
"context": "optional field", "context": "optional field",
"string": "Optional" "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": { "saleDetailsPageCategoriesQuantity": {
"context": "number of categories", "context": "number of categories",
"string": "Categories ({quantity})" "string": "Categories ({quantity})"
@ -1577,6 +1593,10 @@
"context": "button", "context": "button",
"string": "{languageName} - {languageCode}" "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": { "src_dot_components_dot_ListField_dot_3099331554": {
"context": "button", "context": "button",
"string": "Add" "string": "Add"

View file

@ -211,7 +211,7 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
disabled={loading} disabled={loading}
errors={updateResult.data?.categoryUpdate.errors || []} errors={updateResult.data?.categoryUpdate.errors || []}
onAddCategory={() => navigate(categoryAddUrl(id))} onAddCategory={() => navigate(categoryAddUrl(id))}
onAddProduct={() => navigate(productAddUrl)} onAddProduct={() => navigate(productAddUrl())}
onBack={() => onBack={() =>
navigate( navigate(
maybe(() => categoryUrl(data.category.parent.id), categoryListUrl()) 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), label: intl.formatMessage(messages.createProduct),
onClick: () => { onClick: () => {
navigate(productAddUrl); navigate(productAddUrl());
return false; return false;
} }
}, },

View file

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

View file

@ -21,6 +21,7 @@ import CardTitle from "@saleor/components/CardTitle";
import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
import FormSpacer from "@saleor/components/FormSpacer"; import FormSpacer from "@saleor/components/FormSpacer";
import Hr from "@saleor/components/Hr"; import Hr from "@saleor/components/Hr";
import Link from "@saleor/components/Link";
import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment"; import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment";
import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment"; import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment";
import { FormChange } from "@saleor/hooks/useForm"; import { FormChange } from "@saleor/hooks/useForm";
@ -41,12 +42,14 @@ export interface ProductStocksProps {
data: ProductStockFormData; data: ProductStockFormData;
disabled: boolean; disabled: boolean;
errors: ProductErrorFragment[]; errors: ProductErrorFragment[];
hasVariants: boolean;
stocks: ProductStockInput[]; stocks: ProductStockInput[];
warehouses: WarehouseFragment[]; warehouses: WarehouseFragment[];
onChange: FormsetChange; onChange: FormsetChange;
onFormDataChange: FormChange; onFormDataChange: FormChange;
onWarehouseStockAdd: (warehouseId: string) => void; onWarehouseStockAdd: (warehouseId: string) => void;
onWarehouseStockDelete: (warehouseId: string) => void; onWarehouseStockDelete: (warehouseId: string) => void;
onWarehouseConfigure: () => void;
} }
const useStyles = makeStyles( const useStyles = makeStyles(
@ -75,6 +78,9 @@ const useStyles = makeStyles(
marginBottom: theme.spacing(2) marginBottom: theme.spacing(2)
} }
}, },
noWarehouseInfo: {
marginTop: theme.spacing()
},
paper: { paper: {
padding: theme.spacing(2) padding: theme.spacing(2)
}, },
@ -105,13 +111,15 @@ const useStyles = makeStyles(
const ProductStocks: React.FC<ProductStocksProps> = ({ const ProductStocks: React.FC<ProductStocksProps> = ({
data, data,
disabled, disabled,
hasVariants,
errors, errors,
stocks, stocks,
warehouses, warehouses,
onChange, onChange,
onFormDataChange, onFormDataChange,
onWarehouseStockAdd, onWarehouseStockAdd,
onWarehouseStockDelete onWarehouseStockDelete,
onWarehouseConfigure
}) => { }) => {
const classes = useStyles({}); const classes = useStyles({});
const intl = useIntl(); const intl = useIntl();
@ -178,7 +186,43 @@ const ProductStocks: React.FC<ProductStocksProps> = ({
</span> </span>
</div> </div>
</Typography> </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> </CardContent>
{warehouses.length > 0 && (
<Table> <Table>
<TableHead> <TableHead>
<TableRow> <TableRow>
@ -236,7 +280,9 @@ const ProductStocks: React.FC<ProductStocksProps> = ({
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell className={classes.colAction}> <TableCell className={classes.colAction}>
<ClickAwayListener onClickAway={() => setExpansionState(false)}> <ClickAwayListener
onClickAway={() => setExpansionState(false)}
>
<div ref={anchor}> <div ref={anchor}>
<IconButton <IconButton
color="primary" color="primary"
@ -280,6 +326,7 @@ const ProductStocks: React.FC<ProductStocksProps> = ({
)} )}
</TableBody> </TableBody>
</Table> </Table>
)}
</Card> </Card>
); );
}; };

View file

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

View file

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

View file

@ -126,7 +126,7 @@ const ProductVariantCreatorStock: React.FC<ProductVariantCreatorStockProps> = pr
{!warehouses.length ? ( {!warehouses.length ? (
<Typography color="textSecondary"> <Typography color="textSecondary">
<FormattedMessage <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" description="no warehouses info"
id="productVariantCreatorWarehouseSectionDescription" id="productVariantCreatorWarehouseSectionDescription"
/> />

View file

@ -70,6 +70,7 @@ interface ProductVariantPageProps {
onImageSelect(id: string); onImageSelect(id: string);
onVariantClick(variantId: string); onVariantClick(variantId: string);
onSetDefaultVariant(); onSetDefaultVariant();
onWarehouseConfigure();
} }
const ProductVariantPage: React.FC<ProductVariantPageProps> = ({ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
@ -88,7 +89,8 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
onSubmit, onSubmit,
onVariantClick, onVariantClick,
onVariantReorder, onVariantReorder,
onSetDefaultVariant onSetDefaultVariant,
onWarehouseConfigure
}) => { }) => {
const attributeInput = React.useMemo( const attributeInput = React.useMemo(
() => getAttributeInputFromVariant(variant), () => getAttributeInputFromVariant(variant),
@ -240,6 +242,7 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
<ProductStocks <ProductStocks
data={data} data={data}
disabled={loading} disabled={loading}
hasVariants={true}
errors={errors} errors={errors}
stocks={stocks} stocks={stocks}
warehouses={warehouses} warehouses={warehouses}
@ -263,6 +266,7 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
triggerChange(); triggerChange();
removeStock(id); removeStock(id);
}} }}
onWarehouseConfigure={onWarehouseConfigure}
/> />
<CardSpacer /> <CardSpacer />
<Metadata data={data} onChange={changeMetadata} /> <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 { WindowTitle } from "../components/WindowTitle";
import { import {
productAddPath, productAddPath,
ProductAddUrlQueryParams,
productImagePath, productImagePath,
ProductImageUrlQueryParams, ProductImageUrlQueryParams,
productListPath, productListPath,
@ -17,11 +18,12 @@ import {
productPath, productPath,
ProductUrlQueryParams, ProductUrlQueryParams,
productVariantAddPath, productVariantAddPath,
ProductVariantAddUrlQueryParams,
productVariantCreatorPath, productVariantCreatorPath,
productVariantEditPath, productVariantEditPath,
ProductVariantEditUrlQueryParams ProductVariantEditUrlQueryParams
} from "./urls"; } from "./urls";
import ProductCreate from "./views/ProductCreate"; import ProductCreateComponent from "./views/ProductCreate";
import ProductImageComponent from "./views/ProductImage"; import ProductImageComponent from "./views/ProductImage";
import ProductListComponent from "./views/ProductList"; import ProductListComponent from "./views/ProductList";
import ProductUpdateComponent from "./views/ProductUpdate"; import ProductUpdateComponent from "./views/ProductUpdate";
@ -45,6 +47,13 @@ const ProductList: React.FC<RouteComponentProps<any>> = ({ location }) => {
return <ProductListComponent params={params} />; 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 ProductUpdate: React.FC<RouteComponentProps<any>> = ({ match }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1));
const params: ProductUrlQueryParams = qs; const params: ProductUrlQueryParams = qs;
@ -91,11 +100,17 @@ const ProductImage: React.FC<RouteComponentProps<any>> = ({
const ProductVariantCreate: React.FC<RouteComponentProps<any>> = ({ const ProductVariantCreate: React.FC<RouteComponentProps<any>> = ({
match match
}) => ( }) => {
const qs = parseQs(location.search.substr(1));
const params: ProductVariantAddUrlQueryParams = qs;
return (
<ProductVariantCreateComponent <ProductVariantCreateComponent
productId={decodeURIComponent(match.params.id)} productId={decodeURIComponent(match.params.id)}
params={params}
/> />
); );
};
const ProductVariantCreator: React.FC<RouteComponentProps<{ const ProductVariantCreator: React.FC<RouteComponentProps<{
id: string; id: string;

View file

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

View file

@ -1,3 +1,4 @@
import LeaveScreenDialog from "@saleor/components/LeaveScreenDialog";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
@ -8,12 +9,14 @@ import useCategorySearch from "@saleor/searches/useCategorySearch";
import useCollectionSearch from "@saleor/searches/useCollectionSearch"; import useCollectionSearch from "@saleor/searches/useCollectionSearch";
import useProductTypeSearch from "@saleor/searches/useProductTypeSearch"; import useProductTypeSearch from "@saleor/searches/useProductTypeSearch";
import { useTaxTypeList } from "@saleor/taxes/queries"; import { useTaxTypeList } from "@saleor/taxes/queries";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler"; import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler";
import { import {
useMetadataUpdate, useMetadataUpdate,
usePrivateMetadataUpdate usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata"; } from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseList } from "@saleor/warehouses/queries"; import { useWarehouseList } from "@saleor/warehouses/queries";
import { warehouseListPath } from "@saleor/warehouses/urls";
import React from "react"; import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
@ -25,9 +28,22 @@ import {
useProductCreateMutation, useProductCreateMutation,
useProductSetAvailabilityForPurchase useProductSetAvailabilityForPurchase
} from "../mutations"; } 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 navigate = useNavigator();
const notify = useNotifier(); const notify = useNotifier();
const shop = useShop(); 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 handleCreate = async (formData: ProductCreatePageSubmitData) => {
const result = await productCreate({ const result = await productCreate({
variables: { variables: {
@ -196,12 +217,19 @@ export const ProductCreateView: React.FC = () => {
loading: searchProductTypesOpts.loading, loading: searchProductTypesOpts.loading,
onFetchMore: loadMoreProductTypes onFetchMore: loadMoreProductTypes
}} }}
onWarehouseConfigure={() => openModal("leave-screen")}
warehouses={ warehouses={
warehouses.data?.warehouses.edges.map(edge => edge.node) || [] warehouses.data?.warehouses.edges.map(edge => edge.node) || []
} }
taxTypes={taxTypes.data?.taxTypes || []} taxTypes={taxTypes.data?.taxTypes || []}
weightUnit={shop?.defaultWeightUnit} 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, () => attributes.data.availableInGrid.pageInfo.hasNextPage,
false false
)} )}
onAdd={() => navigate(productAddUrl)} onAdd={() => navigate(productAddUrl())}
disabled={loading} disabled={loading}
products={maybe(() => data.products.edges.map(edge => edge.node))} products={maybe(() => data.products.edges.map(edge => edge.node))}
onFetchMore={() => onFetchMore={() =>

View file

@ -3,6 +3,7 @@ import DialogContentText from "@material-ui/core/DialogContentText";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete"; import DeleteIcon from "@material-ui/icons/Delete";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import LeaveScreenDialog from "@saleor/components/LeaveScreenDialog";
import NotFoundPage from "@saleor/components/NotFoundPage"; import NotFoundPage from "@saleor/components/NotFoundPage";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
@ -33,6 +34,7 @@ import {
usePrivateMetadataUpdate usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata"; } from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseList } from "@saleor/warehouses/queries"; import { useWarehouseList } from "@saleor/warehouses/queries";
import { warehouseListPath } from "@saleor/warehouses/urls";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -64,6 +66,7 @@ interface ProductUpdateProps {
} }
export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => { export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
const { action } = params;
const navigate = useNavigator(); const navigate = useNavigator();
const notify = useNotifier(); const notify = useNotifier();
const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions( const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
@ -312,6 +315,7 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
onImageUpload={handleImageUpload} onImageUpload={handleImageUpload}
onImageEdit={handleImageEdit} onImageEdit={handleImageEdit}
onImageDelete={handleImageDelete} onImageDelete={handleImageDelete}
onWarehouseConfigure={() => openModal("leave-screen")}
toolbar={ toolbar={
<IconButton <IconButton
color="primary" color="primary"
@ -392,6 +396,12 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
/> />
</DialogContentText> </DialogContentText>
</ActionDialog> </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 placeholderImg from "@assets/images/placeholder255x255.png";
import LeaveScreenDialog from "@saleor/components/LeaveScreenDialog";
import NotFoundPage from "@saleor/components/NotFoundPage"; import NotFoundPage from "@saleor/components/NotFoundPage";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
@ -13,6 +14,7 @@ import {
usePrivateMetadataUpdate usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata"; } from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseList } from "@saleor/warehouses/queries"; import { useWarehouseList } from "@saleor/warehouses/queries";
import { warehouseListPath } from "@saleor/warehouses/urls";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
@ -51,6 +53,7 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
productId, productId,
params params
}) => { }) => {
const { action } = params;
const shop = useShop(); const shop = useShop();
const navigate = useNavigator(); const navigate = useNavigator();
const notify = useNotifier(); const notify = useNotifier();
@ -78,7 +81,7 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
const [updateMetadata] = useMetadataUpdate({}); const [updateMetadata] = useMetadataUpdate({});
const [updatePrivateMetadata] = usePrivateMetadataUpdate({}); const [updatePrivateMetadata] = usePrivateMetadataUpdate({});
const [openModal] = createDialogActionHandlers< const [openModal, closeModal] = createDialogActionHandlers<
ProductVariantEditUrlDialog, ProductVariantEditUrlDialog,
ProductVariantEditUrlQueryParams ProductVariantEditUrlQueryParams
>( >(
@ -220,6 +223,7 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
navigate(productVariantEditUrl(productId, variantId)); navigate(productVariantEditUrl(productId, variantId));
}} }}
onVariantReorder={handleVariantReorder} onVariantReorder={handleVariantReorder}
onWarehouseConfigure={() => openModal("leave-screen")}
/> />
<ProductVariantDeleteDialog <ProductVariantDeleteDialog
confirmButtonState={deleteVariantOpts.status} confirmButtonState={deleteVariantOpts.status}
@ -234,6 +238,12 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
open={params.action === "remove"} open={params.action === "remove"}
name={data?.productVariant?.name} 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 NotFoundPage from "@saleor/components/NotFoundPage";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import useShop from "@saleor/hooks/useShop"; import useShop from "@saleor/hooks/useShop";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler"; import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler";
import { import {
useMetadataUpdate, useMetadataUpdate,
usePrivateMetadataUpdate usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata"; } from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseList } from "@saleor/warehouses/queries"; import { useWarehouseList } from "@saleor/warehouses/queries";
import { warehouseListPath } from "@saleor/warehouses/urls";
import React from "react"; import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
@ -22,16 +25,26 @@ import {
useVariantCreateMutation useVariantCreateMutation
} from "../mutations"; } from "../mutations";
import { useProductVariantCreateQuery } from "../queries"; import { useProductVariantCreateQuery } from "../queries";
import { productListUrl, productUrl, productVariantEditUrl } from "../urls"; import {
productListUrl,
productUrl,
productVariantAddUrl,
ProductVariantAddUrlDialog,
ProductVariantAddUrlQueryParams,
productVariantEditUrl
} from "../urls";
import { createVariantReorderHandler } from "./ProductUpdate/handlers"; import { createVariantReorderHandler } from "./ProductUpdate/handlers";
interface ProductVariantCreateProps { interface ProductVariantCreateProps {
productId: string; productId: string;
params: ProductVariantAddUrlQueryParams;
} }
export const ProductVariant: React.FC<ProductVariantCreateProps> = ({ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
productId productId,
params
}) => { }) => {
const { action } = params;
const navigate = useNavigator(); const navigate = useNavigator();
const notify = useNotifier(); const notify = useNotifier();
const shop = useShop(); const shop = useShop();
@ -82,6 +95,11 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
reorderProductVariants({ variables }) reorderProductVariants({ variables })
); );
const [openModal, closeModal] = createDialogActionHandlers<
ProductVariantAddUrlDialog,
ProductVariantAddUrlQueryParams
>(navigate, params => productVariantAddUrl(productId, params), params);
const handleBack = () => navigate(productUrl(productId)); const handleBack = () => navigate(productUrl(productId));
const handleCreate = async (formData: ProductVariantCreatePageSubmitData) => { const handleCreate = async (formData: ProductVariantCreatePageSubmitData) => {
const result = await variantCreate({ const result = await variantCreate({
@ -143,12 +161,19 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
onSubmit={handleSubmit} onSubmit={handleSubmit}
onVariantClick={handleVariantClick} onVariantClick={handleVariantClick}
onVariantReorder={handleVariantReorder} onVariantReorder={handleVariantReorder}
onWarehouseConfigure={() => openModal("leave-screen")}
saveButtonBarState={variantCreateResult.status} saveButtonBarState={variantCreateResult.status}
warehouses={ warehouses={
warehouses.data?.warehouses.edges.map(edge => edge.node) || [] warehouses.data?.warehouses.edges.map(edge => edge.node) || []
} }
weightUnit={shop?.defaultWeightUnit} 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} warehouses={warehouseList}
taxTypes={taxTypes} taxTypes={taxTypes}
weightUnit="kg" weightUnit="kg"
onWarehouseConfigure={() => undefined}
/> />
)) ))
.add("When loading", () => ( .add("When loading", () => (
@ -60,6 +61,7 @@ storiesOf("Views / Products / Create product", module)
warehouses={undefined} warehouses={undefined}
taxTypes={taxTypes} taxTypes={taxTypes}
weightUnit="kg" weightUnit="kg"
onWarehouseConfigure={() => undefined}
/> />
)) ))
.add("form errors", () => ( .add("form errors", () => (
@ -89,5 +91,6 @@ storiesOf("Views / Products / Create product", module)
warehouses={warehouseList} warehouses={warehouseList}
taxTypes={taxTypes} taxTypes={taxTypes}
weightUnit="kg" weightUnit="kg"
onWarehouseConfigure={() => undefined}
/> />
)); ));

View file

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

View file

@ -26,6 +26,7 @@ storiesOf("Views / Products / Create product variant", module)
onVariantReorder={() => undefined} onVariantReorder={() => undefined}
saveButtonBarState="default" saveButtonBarState="default"
warehouses={warehouseList} warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/> />
)) ))
.add("with errors", () => ( .add("with errors", () => (
@ -58,6 +59,7 @@ storiesOf("Views / Products / Create product variant", module)
onVariantReorder={() => undefined} onVariantReorder={() => undefined}
saveButtonBarState="default" saveButtonBarState="default"
warehouses={warehouseList} warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/> />
)) ))
.add("when loading data", () => ( .add("when loading data", () => (
@ -74,6 +76,7 @@ storiesOf("Views / Products / Create product variant", module)
onVariantReorder={() => undefined} onVariantReorder={() => undefined}
saveButtonBarState="default" saveButtonBarState="default"
warehouses={warehouseList} warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/> />
)) ))
.add("add first variant", () => ( .add("add first variant", () => (
@ -93,5 +96,6 @@ storiesOf("Views / Products / Create product variant", module)
onVariantReorder={() => undefined} onVariantReorder={() => undefined}
saveButtonBarState="default" saveButtonBarState="default"
warehouses={warehouseList} warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/> />
)); ));

View file

@ -28,6 +28,7 @@ storiesOf("Views / Products / Product variant details", module)
onVariantReorder={() => undefined} onVariantReorder={() => undefined}
saveButtonBarState="default" saveButtonBarState="default"
warehouses={warehouseList} warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/> />
)) ))
.add("when loading data", () => ( .add("when loading data", () => (
@ -47,6 +48,7 @@ storiesOf("Views / Products / Product variant details", module)
onVariantReorder={() => undefined} onVariantReorder={() => undefined}
saveButtonBarState="default" saveButtonBarState="default"
warehouses={warehouseList} warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/> />
)) ))
.add("attribute errors", () => ( .add("attribute errors", () => (
@ -82,5 +84,6 @@ storiesOf("Views / Products / Product variant details", module)
...error ...error
}))} }))}
warehouses={warehouseList} warehouses={warehouseList}
onWarehouseConfigure={() => undefined}
/> />
)); ));