Display order errors

This commit is contained in:
dominik-zeglen 2020-03-16 13:28:52 +01:00
parent f43326b660
commit b4d16517b0
26 changed files with 888 additions and 416 deletions

View file

@ -14,6 +14,10 @@ import ConfirmButton, {
import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
import Form from "@saleor/components/Form"; import Form from "@saleor/components/Form";
import { buttonMessages } from "@saleor/intl"; import { buttonMessages } from "@saleor/intl";
import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment";
import FormSpacer from "@saleor/components/FormSpacer";
import getOrderErrorMessage from "@saleor/utils/errors/order";
import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors";
export interface FormData { export interface FormData {
restock: boolean; restock: boolean;
@ -32,8 +36,9 @@ const useStyles = makeStyles(
{ name: "OrderCancelDialog" } { name: "OrderCancelDialog" }
); );
interface OrderCancelDialogProps { export interface OrderCancelDialogProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[];
number: string; number: string;
open: boolean; open: boolean;
onClose?(); onClose?();
@ -43,14 +48,16 @@ interface OrderCancelDialogProps {
const OrderCancelDialog: React.FC<OrderCancelDialogProps> = props => { const OrderCancelDialog: React.FC<OrderCancelDialogProps> = props => {
const { const {
confirmButtonState, confirmButtonState,
errors: apiErrors,
number: orderNumber, number: orderNumber,
open, open,
onSubmit, onSubmit,
onClose onClose
} = props; } = props;
const classes = useStyles(props);
const classes = useStyles(props);
const intl = useIntl(); const intl = useIntl();
const errors = useModalDialogErrors(apiErrors, open);
return ( return (
<Dialog onClose={onClose} open={open}> <Dialog onClose={onClose} open={open}>
@ -87,6 +94,16 @@ const OrderCancelDialog: React.FC<OrderCancelDialogProps> = props => {
onChange={change} onChange={change}
/> />
</DialogContentText> </DialogContentText>
{errors.length > 0 && (
<>
<FormSpacer />
{errors.map(err => (
<DialogContentText color="error">
{getOrderErrorMessage(err, intl)}
</DialogContentText>
))}
</>
)}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClose}> <Button onClick={onClose}>

View file

@ -4,9 +4,14 @@ import { FormattedMessage, useIntl } from "react-intl";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment";
import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors";
import FormSpacer from "@saleor/components/FormSpacer";
import getOrderErrorMessage from "@saleor/utils/errors/order";
export interface OrderDraftCancelDialogProps { export interface OrderDraftCancelDialogProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[];
open: boolean; open: boolean;
onClose: () => void; onClose: () => void;
onConfirm: () => void; onConfirm: () => void;
@ -15,12 +20,14 @@ export interface OrderDraftCancelDialogProps {
const OrderDraftCancelDialog: React.FC<OrderDraftCancelDialogProps> = ({ const OrderDraftCancelDialog: React.FC<OrderDraftCancelDialogProps> = ({
confirmButtonState, confirmButtonState,
errors: apiErrors,
onClose, onClose,
onConfirm, onConfirm,
open, open,
orderNumber orderNumber
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const errors = useModalDialogErrors(apiErrors, open);
return ( return (
<ActionDialog <ActionDialog
@ -42,6 +49,16 @@ const OrderDraftCancelDialog: React.FC<OrderDraftCancelDialogProps> = ({
}} }}
/> />
</DialogContentText> </DialogContentText>
{errors.length > 0 && (
<>
<FormSpacer />
{errors.map(err => (
<DialogContentText color="error">
{getOrderErrorMessage(err, intl)}
</DialogContentText>
))}
</>
)}
</ActionDialog> </ActionDialog>
); );
}; };

View file

@ -4,6 +4,10 @@ import { FormattedMessage, IntlShape, useIntl } from "react-intl";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment";
import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors";
import FormSpacer from "@saleor/components/FormSpacer";
import getOrderErrorMessage from "@saleor/utils/errors/order";
export enum OrderDraftFinalizeWarning { export enum OrderDraftFinalizeWarning {
NO_SHIPPING, NO_SHIPPING,
@ -15,6 +19,7 @@ export enum OrderDraftFinalizeWarning {
export interface OrderDraftFinalizeDialogProps { export interface OrderDraftFinalizeDialogProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[];
open: boolean; open: boolean;
orderNumber: string; orderNumber: string;
warnings: OrderDraftFinalizeWarning[]; warnings: OrderDraftFinalizeWarning[];
@ -48,6 +53,7 @@ function translateWarnings(
const OrderDraftFinalizeDialog: React.FC<OrderDraftFinalizeDialogProps> = ({ const OrderDraftFinalizeDialog: React.FC<OrderDraftFinalizeDialogProps> = ({
confirmButtonState, confirmButtonState,
errors: apiErrors,
open, open,
warnings, warnings,
onClose, onClose,
@ -55,6 +61,8 @@ const OrderDraftFinalizeDialog: React.FC<OrderDraftFinalizeDialogProps> = ({
orderNumber orderNumber
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const errors = useModalDialogErrors(apiErrors, open);
const translatedWarnings = translateWarnings(intl); const translatedWarnings = translateWarnings(intl);
return ( return (
@ -99,6 +107,16 @@ const OrderDraftFinalizeDialog: React.FC<OrderDraftFinalizeDialogProps> = ({
orderNumber orderNumber
}} }}
/> />
{errors.length > 0 && (
<>
<FormSpacer />
{errors.map(err => (
<DialogContentText color="error">
{getOrderErrorMessage(err, intl)}
</DialogContentText>
))}
</>
)}
</DialogContentText> </DialogContentText>
</ActionDialog> </ActionDialog>
); );

View file

@ -14,6 +14,9 @@ import ConfirmButton, {
import { ControlledCheckbox } from "@saleor/components/ControlledCheckbox"; import { ControlledCheckbox } from "@saleor/components/ControlledCheckbox";
import Form from "@saleor/components/Form"; import Form from "@saleor/components/Form";
import { buttonMessages } from "@saleor/intl"; import { buttonMessages } from "@saleor/intl";
import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment";
import FormSpacer from "@saleor/components/FormSpacer";
import getOrderErrorMessage from "@saleor/utils/errors/order";
export interface FormData { export interface FormData {
restock: boolean; restock: boolean;
@ -32,29 +35,22 @@ const useStyles = makeStyles(
{ name: "OrderFulfillmentCancelDialog" } { name: "OrderFulfillmentCancelDialog" }
); );
interface OrderFulfillmentCancelDialogProps { export interface OrderFulfillmentCancelDialogProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[];
open: boolean; open: boolean;
onClose(); onClose();
onConfirm(data: FormData); onConfirm(data: FormData);
} }
const OrderFulfillmentCancelDialog: React.FC< const OrderFulfillmentCancelDialog: React.FC<OrderFulfillmentCancelDialogProps> = props => {
OrderFulfillmentCancelDialogProps const { confirmButtonState, errors, open, onConfirm, onClose } = props;
> = props => {
const {
confirmButtonState,
open,
onConfirm,
onClose
} = props;
const classes = useStyles(props); const classes = useStyles(props);
const intl = useIntl(); const intl = useIntl();
return ( return (
<Dialog onClose={onClose} open={open}> <Dialog onClose={onClose} open={open} fullWidth maxWidth="xs">
<Form initial={{ restock: true }} onSubmit={onConfirm}> <Form initial={{ restock: true }} onSubmit={onConfirm}>
{({ change, data, submit }) => ( {({ change, data, submit }) => (
<> <>
@ -77,6 +73,16 @@ const OrderFulfillmentCancelDialog: React.FC<
name="restock" name="restock"
onChange={change} onChange={change}
/> />
{errors.length > 0 && (
<>
<FormSpacer />
{errors.map(err => (
<DialogContentText color="error">
{getOrderErrorMessage(err, intl)}
</DialogContentText>
))}
</>
)}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClose}> <Button onClick={onClose}>

View file

@ -2,6 +2,7 @@ import Button from "@material-ui/core/Button";
import Dialog from "@material-ui/core/Dialog"; import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions"; import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent"; import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle"; import DialogTitle from "@material-ui/core/DialogTitle";
import { makeStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import TableBody from "@material-ui/core/TableBody"; import TableBody from "@material-ui/core/TableBody";
@ -22,8 +23,11 @@ import TableCellAvatar, {
AVATAR_MARGIN AVATAR_MARGIN
} from "@saleor/components/TableCellAvatar"; } from "@saleor/components/TableCellAvatar";
import { buttonMessages } from "@saleor/intl"; import { buttonMessages } from "@saleor/intl";
import { maybe } from "../../../misc"; import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment";
import { getFormErrors } from "@saleor/utils/errors";
import getOrderErrorMessage from "@saleor/utils/errors/order";
import { OrderDetails_order_lines } from "../../types/OrderDetails"; import { OrderDetails_order_lines } from "../../types/OrderDetails";
import { maybe } from "../../../misc";
export interface FormData { export interface FormData {
lines: number[]; lines: number[];
@ -65,6 +69,7 @@ const useStyles = makeStyles(
export interface OrderFulfillmentDialogProps { export interface OrderFulfillmentDialogProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[];
open: boolean; open: boolean;
lines: OrderDetails_order_lines[]; lines: OrderDetails_order_lines[];
onClose(); onClose();
@ -72,11 +77,14 @@ export interface OrderFulfillmentDialogProps {
} }
const OrderFulfillmentDialog: React.FC<OrderFulfillmentDialogProps> = props => { const OrderFulfillmentDialog: React.FC<OrderFulfillmentDialogProps> = props => {
const { confirmButtonState, open, lines, onClose, onSubmit } = props; const { confirmButtonState, errors, open, lines, onClose, onSubmit } = props;
const classes = useStyles(props); const classes = useStyles(props);
const intl = useIntl(); const intl = useIntl();
const formFields = ["trackingNumber"];
const formErrors = getFormErrors(formFields, errors);
return ( return (
<Dialog onClose={onClose} open={open}> <Dialog onClose={onClose} open={open}>
<Form <Form
@ -165,8 +173,13 @@ const OrderFulfillmentDialog: React.FC<OrderFulfillmentDialogProps> = props => {
handleQuantityChange(productIndex, event) handleQuantityChange(productIndex, event)
} }
error={ error={
!!formErrors.trackingNumber ||
remainingQuantity < data.lines[productIndex] remainingQuantity < data.lines[productIndex]
} }
helperText={getOrderErrorMessage(
formErrors.trackingNumber,
intl
)}
/> />
<div className={classes.remainingQuantity}> <div className={classes.remainingQuantity}>
/ {remainingQuantity} / {remainingQuantity}
@ -181,7 +194,12 @@ const OrderFulfillmentDialog: React.FC<OrderFulfillmentDialogProps> = props => {
<DialogContent> <DialogContent>
<FormSpacer /> <FormSpacer />
<TextField <TextField
error={!!formErrors.trackingNumber}
fullWidth fullWidth
helperText={getOrderErrorMessage(
formErrors.trackingNumber,
intl
)}
label={intl.formatMessage({ label={intl.formatMessage({
defaultMessage: "Tracking number", defaultMessage: "Tracking number",
description: "fulfillment group" description: "fulfillment group"
@ -190,6 +208,18 @@ const OrderFulfillmentDialog: React.FC<OrderFulfillmentDialogProps> = props => {
value={data.trackingNumber} value={data.trackingNumber}
onChange={change} onChange={change}
/> />
{errors.length > 0 && (
<>
<FormSpacer />
{errors
.filter(err => !formFields.includes(err.field))
.map(err => (
<DialogContentText color="error">
{getOrderErrorMessage(err, intl)}
</DialogContentText>
))}
</>
)}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClose}> <Button onClick={onClose}>

View file

@ -2,6 +2,7 @@ import Button from "@material-ui/core/Button";
import Dialog from "@material-ui/core/Dialog"; import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions"; import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent"; import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle"; import DialogTitle from "@material-ui/core/DialogTitle";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import React from "react"; import React from "react";
@ -12,26 +13,41 @@ import ConfirmButton, {
} from "@saleor/components/ConfirmButton"; } from "@saleor/components/ConfirmButton";
import Form from "@saleor/components/Form"; import Form from "@saleor/components/Form";
import { buttonMessages } from "@saleor/intl"; import { buttonMessages } from "@saleor/intl";
import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment";
import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors";
import getOrderErrorMessage from "@saleor/utils/errors/order";
import { getFormErrors } from "@saleor/utils/errors";
import FormSpacer from "@saleor/components/FormSpacer";
export interface FormData { export interface FormData {
trackingNumber: string; trackingNumber: string;
} }
interface OrderFulfillmentTrackingDialogProps { export interface OrderFulfillmentTrackingDialogProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[];
open: boolean; open: boolean;
trackingNumber: string; trackingNumber: string;
onClose(); onClose();
onConfirm(data: FormData); onConfirm(data: FormData);
} }
const OrderFulfillmentTrackingDialog: React.FC< const OrderFulfillmentTrackingDialog: React.FC<OrderFulfillmentTrackingDialogProps> = ({
OrderFulfillmentTrackingDialogProps confirmButtonState,
> = ({ confirmButtonState, open, trackingNumber, onConfirm, onClose }) => { errors: apiErrors,
open,
trackingNumber,
onConfirm,
onClose
}) => {
const intl = useIntl(); const intl = useIntl();
const errors = useModalDialogErrors(apiErrors, open);
const formFields = ["trackingNumber"];
const formErrors = getFormErrors(formFields, errors);
return ( return (
<Dialog onClose={onClose} open={open}> <Dialog onClose={onClose} open={open} fullWidth maxWidth="xs">
<Form initial={{ trackingNumber }} onSubmit={onConfirm}> <Form initial={{ trackingNumber }} onSubmit={onConfirm}>
{({ change, data, submit }) => ( {({ change, data, submit }) => (
<> <>
@ -43,6 +59,11 @@ const OrderFulfillmentTrackingDialog: React.FC<
</DialogTitle> </DialogTitle>
<DialogContent> <DialogContent>
<TextField <TextField
error={!!formErrors.trackingNumber}
helperText={getOrderErrorMessage(
formErrors.trackingNumber,
intl
)}
label={intl.formatMessage({ label={intl.formatMessage({
defaultMessage: "Tracking number" defaultMessage: "Tracking number"
})} })}
@ -51,6 +72,18 @@ const OrderFulfillmentTrackingDialog: React.FC<
value={data.trackingNumber} value={data.trackingNumber}
fullWidth fullWidth
/> />
{errors.length > 0 && (
<>
<FormSpacer />
{errors
.filter(err => !formFields.includes(err.field))
.map(err => (
<DialogContentText color="error">
{getOrderErrorMessage(err, intl)}
</DialogContentText>
))}
</>
)}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClose}> <Button onClick={onClose}>

View file

@ -4,9 +4,14 @@ import { FormattedMessage, useIntl } from "react-intl";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment";
import FormSpacer from "@saleor/components/FormSpacer";
import getOrderErrorMessage from "@saleor/utils/errors/order";
import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors";
export interface OrderMarkAsPaidDialogProps { export interface OrderMarkAsPaidDialogProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[];
open: boolean; open: boolean;
onClose: () => void; onClose: () => void;
onConfirm: () => void; onConfirm: () => void;
@ -14,11 +19,13 @@ export interface OrderMarkAsPaidDialogProps {
const OrderMarkAsPaidDialog: React.FC<OrderMarkAsPaidDialogProps> = ({ const OrderMarkAsPaidDialog: React.FC<OrderMarkAsPaidDialogProps> = ({
confirmButtonState, confirmButtonState,
errors: apiErrors,
onClose, onClose,
onConfirm, onConfirm,
open open
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const errors = useModalDialogErrors(apiErrors, open);
return ( return (
<ActionDialog <ActionDialog
@ -34,6 +41,16 @@ const OrderMarkAsPaidDialog: React.FC<OrderMarkAsPaidDialogProps> = ({
<DialogContentText> <DialogContentText>
<FormattedMessage defaultMessage="Are you sure you want to mark this order as paid?" /> <FormattedMessage defaultMessage="Are you sure you want to mark this order as paid?" />
</DialogContentText> </DialogContentText>
{errors.length > 0 && (
<>
<FormSpacer />
{errors.map(err => (
<DialogContentText color="error">
{getOrderErrorMessage(err, intl)}
</DialogContentText>
))}
</>
)}
</ActionDialog> </ActionDialog>
); );
}; };

View file

@ -2,6 +2,7 @@ import Button from "@material-ui/core/Button";
import Dialog from "@material-ui/core/Dialog"; import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions"; import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent"; import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle"; import DialogTitle from "@material-ui/core/DialogTitle";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import React from "react"; import React from "react";
@ -12,22 +13,28 @@ import ConfirmButton, {
} from "@saleor/components/ConfirmButton"; } from "@saleor/components/ConfirmButton";
import Form from "@saleor/components/Form"; import Form from "@saleor/components/Form";
import { buttonMessages } from "@saleor/intl"; import { buttonMessages } from "@saleor/intl";
import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment";
import getOrderErrorMessage from "@saleor/utils/errors/order";
import { getFormErrors } from "@saleor/utils/errors";
import FormSpacer from "@saleor/components/FormSpacer";
export interface FormData { export interface FormData {
amount: number; amount: number;
} }
interface OrderPaymentDialogProps { export interface OrderPaymentDialogProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[];
open: boolean; open: boolean;
initial: number; initial: number;
variant: string; variant: "capture" | "refund";
onClose: () => void; onClose: () => void;
onSubmit: (data: FormData) => void; onSubmit: (data: FormData) => void;
} }
const OrderPaymentDialog: React.FC<OrderPaymentDialogProps> = ({ const OrderPaymentDialog: React.FC<OrderPaymentDialogProps> = ({
confirmButtonState, confirmButtonState,
errors,
open, open,
initial, initial,
variant, variant,
@ -36,16 +43,16 @@ const OrderPaymentDialog: React.FC<OrderPaymentDialogProps> = ({
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const formFields = ["payment"];
const formErrors = getFormErrors(formFields, errors);
return ( return (
<Dialog onClose={onClose} open={open}> <Dialog onClose={onClose} open={open} fullWidth maxWidth="xs">
<Form <Form
initial={{ initial={{
amount: initial amount: initial
}} }}
onSubmit={data => { onSubmit={onSubmit}
onSubmit(data);
onClose();
}}
> >
{({ data, change, submit }) => ( {({ data, change, submit }) => (
<> <>
@ -60,10 +67,11 @@ const OrderPaymentDialog: React.FC<OrderPaymentDialogProps> = ({
description: "dialog header" description: "dialog header"
})} })}
</DialogTitle> </DialogTitle>
<DialogContent> <DialogContent>
<TextField <TextField
error={!!formErrors.payment}
fullWidth fullWidth
helperText={getOrderErrorMessage(formErrors.payment, intl)}
label={intl.formatMessage({ label={intl.formatMessage({
defaultMessage: "Amount", defaultMessage: "Amount",
description: "amount of refunded money" description: "amount of refunded money"
@ -76,6 +84,18 @@ const OrderPaymentDialog: React.FC<OrderPaymentDialogProps> = ({
type="number" type="number"
value={data.amount} value={data.amount}
/> />
{errors.length > 0 && (
<>
<FormSpacer />
{errors
.filter(err => !formFields.includes(err.field))
.map(err => (
<DialogContentText color="error">
{getOrderErrorMessage(err, intl)}
</DialogContentText>
))}
</>
)}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClose}> <Button onClick={onClose}>
@ -85,10 +105,7 @@ const OrderPaymentDialog: React.FC<OrderPaymentDialogProps> = ({
transitionState={confirmButtonState} transitionState={confirmButtonState}
color="primary" color="primary"
variant="contained" variant="contained"
onClick={() => { onClick={submit}
onClose();
submit();
}}
> >
<FormattedMessage {...buttonMessages.confirm} /> <FormattedMessage {...buttonMessages.confirm} />
</ConfirmButton> </ConfirmButton>

View file

@ -5,15 +5,19 @@ import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle"; import DialogTitle from "@material-ui/core/DialogTitle";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import ConfirmButton, { import ConfirmButton, {
ConfirmButtonTransitionState ConfirmButtonTransitionState
} from "@saleor/components/ConfirmButton"; } from "@saleor/components/ConfirmButton";
import { buttonMessages } from "@saleor/intl"; import { buttonMessages } from "@saleor/intl";
import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment";
import FormSpacer from "@saleor/components/FormSpacer";
import getOrderErrorMessage from "@saleor/utils/errors/order";
interface OrderPaymentVoidDialogProps { export interface OrderPaymentVoidDialogProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[];
open: boolean; open: boolean;
onClose?(); onClose?();
onConfirm?(); onConfirm?();
@ -21,36 +25,51 @@ interface OrderPaymentVoidDialogProps {
const OrderPaymentVoidDialog: React.FC<OrderPaymentVoidDialogProps> = ({ const OrderPaymentVoidDialog: React.FC<OrderPaymentVoidDialogProps> = ({
confirmButtonState, confirmButtonState,
errors,
open, open,
onConfirm, onConfirm,
onClose onClose
}) => ( }) => {
<Dialog onClose={onClose} open={open}> const intl = useIntl();
<DialogTitle>
<FormattedMessage return (
defaultMessage="Void Payment" <Dialog onClose={onClose} open={open}>
description="dialog header" <DialogTitle>
/> <FormattedMessage
</DialogTitle> defaultMessage="Void Payment"
<DialogContent> description="dialog header"
<DialogContentText> />
<FormattedMessage defaultMessage="Are you sure you want to void this payment?" /> </DialogTitle>
</DialogContentText> <DialogContent>
</DialogContent> <DialogContentText>
<DialogActions> <FormattedMessage defaultMessage="Are you sure you want to void this payment?" />
<Button onClick={onClose}> </DialogContentText>
<FormattedMessage {...buttonMessages.back} /> {errors.length > 0 && (
</Button> <>
<ConfirmButton <FormSpacer />
transitionState={confirmButtonState} {errors.map(err => (
color="primary" <DialogContentText color="error">
variant="contained" {getOrderErrorMessage(err, intl)}
onClick={onConfirm} </DialogContentText>
> ))}
<FormattedMessage {...buttonMessages.confirm} /> </>
</ConfirmButton> )}
</DialogActions> </DialogContent>
</Dialog> <DialogActions>
); <Button onClick={onClose}>
<FormattedMessage {...buttonMessages.back} />
</Button>
<ConfirmButton
transitionState={confirmButtonState}
color="primary"
variant="contained"
onClick={onConfirm}
>
<FormattedMessage {...buttonMessages.confirm} />
</ConfirmButton>
</DialogActions>
</Dialog>
);
};
OrderPaymentVoidDialog.displayName = "OrderPaymentVoidDialog"; OrderPaymentVoidDialog.displayName = "OrderPaymentVoidDialog";
export default OrderPaymentVoidDialog; export default OrderPaymentVoidDialog;

View file

@ -3,6 +3,7 @@ import CircularProgress from "@material-ui/core/CircularProgress";
import Dialog from "@material-ui/core/Dialog"; import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions"; import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent"; import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle"; import DialogTitle from "@material-ui/core/DialogTitle";
import { makeStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import TableBody from "@material-ui/core/TableBody"; import TableBody from "@material-ui/core/TableBody";
@ -24,6 +25,10 @@ import useSearchQuery from "@saleor/hooks/useSearchQuery";
import { buttonMessages } from "@saleor/intl"; import { buttonMessages } from "@saleor/intl";
import { maybe, renderCollection } from "@saleor/misc"; import { maybe, renderCollection } from "@saleor/misc";
import { FetchMoreProps } from "@saleor/types"; import { FetchMoreProps } from "@saleor/types";
import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment";
import getOrderErrorMessage from "@saleor/utils/errors/order";
import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors";
import FormSpacer from "@saleor/components/FormSpacer";
import { import {
SearchOrderVariant_search_edges_node, SearchOrderVariant_search_edges_node,
SearchOrderVariant_search_edges_node_variants SearchOrderVariant_search_edges_node_variants
@ -50,7 +55,8 @@ const useStyles = makeStyles(
alignItems: "center", alignItems: "center",
display: "flex", display: "flex",
height: theme.spacing(3), height: theme.spacing(3),
justifyContent: "center" justifyContent: "center",
marginTop: theme.spacing(3)
}, },
overflow: { overflow: {
overflowY: "visible" overflowY: "visible"
@ -79,8 +85,9 @@ type SetVariantsAction = (
data: SearchOrderVariant_search_edges_node_variants[] data: SearchOrderVariant_search_edges_node_variants[]
) => void; ) => void;
interface OrderProductAddDialogProps extends FetchMoreProps { export interface OrderProductAddDialogProps extends FetchMoreProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[];
open: boolean; open: boolean;
products: SearchOrderVariant_search_edges_node[]; products: SearchOrderVariant_search_edges_node[];
onClose: () => void; onClose: () => void;
@ -154,6 +161,7 @@ const onVariantAdd = (
const OrderProductAddDialog: React.FC<OrderProductAddDialogProps> = props => { const OrderProductAddDialog: React.FC<OrderProductAddDialogProps> = props => {
const { const {
confirmButtonState, confirmButtonState,
errors: apiErrors,
open, open,
loading, loading,
hasMore, hasMore,
@ -163,13 +171,14 @@ const OrderProductAddDialog: React.FC<OrderProductAddDialogProps> = props => {
onClose, onClose,
onSubmit onSubmit
} = props; } = props;
const classes = useStyles(props);
const classes = useStyles(props);
const intl = useIntl(); const intl = useIntl();
const [query, onQueryChange] = useSearchQuery(onFetch); const [query, onQueryChange] = useSearchQuery(onFetch);
const [variants, setVariants] = React.useState< const [variants, setVariants] = React.useState<
SearchOrderVariant_search_edges_node_variants[] SearchOrderVariant_search_edges_node_variants[]
>([]); >([]);
const errors = useModalDialogErrors(apiErrors, open);
const selectedVariantsToProductsMap = products const selectedVariantsToProductsMap = products
? products.map(product => ? products.map(product =>
@ -323,6 +332,16 @@ const OrderProductAddDialog: React.FC<OrderProductAddDialogProps> = props => {
</TableBody> </TableBody>
</ResponsiveTable> </ResponsiveTable>
</InfiniteScroll> </InfiniteScroll>
{errors.length > 0 && (
<>
<FormSpacer />
{errors.map(err => (
<DialogContentText color="error">
{getOrderErrorMessage(err, intl)}
</DialogContentText>
))}
</>
)}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClose}> <Button onClick={onClose}>

View file

@ -2,10 +2,11 @@ import Button from "@material-ui/core/Button";
import Dialog from "@material-ui/core/Dialog"; import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions"; import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent"; import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle"; import DialogTitle from "@material-ui/core/DialogTitle";
import { makeStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import ConfirmButton, { import ConfirmButton, {
ConfirmButtonTransitionState ConfirmButtonTransitionState
@ -14,6 +15,11 @@ import Form from "@saleor/components/Form";
import Money from "@saleor/components/Money"; import Money from "@saleor/components/Money";
import { SingleSelectField } from "@saleor/components/SingleSelectField"; import { SingleSelectField } from "@saleor/components/SingleSelectField";
import { buttonMessages } from "@saleor/intl"; import { buttonMessages } from "@saleor/intl";
import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment";
import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors";
import { getFormErrors } from "@saleor/utils/errors";
import getOrderErrorMessage from "@saleor/utils/errors/order";
import FormSpacer from "@saleor/components/FormSpacer";
import { OrderDetails_order_availableShippingMethods } from "../../types/OrderDetails"; import { OrderDetails_order_availableShippingMethods } from "../../types/OrderDetails";
export interface FormData { export interface FormData {
@ -45,8 +51,9 @@ const useStyles = makeStyles(
{ name: "OrderShippingMethodEditDialog" } { name: "OrderShippingMethodEditDialog" }
); );
interface OrderShippingMethodEditDialogProps { export interface OrderShippingMethodEditDialogProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[];
open: boolean; open: boolean;
shippingMethod: string; shippingMethod: string;
shippingMethods?: OrderDetails_order_availableShippingMethods[]; shippingMethods?: OrderDetails_order_availableShippingMethods[];
@ -54,11 +61,10 @@ interface OrderShippingMethodEditDialogProps {
onSubmit?(data: FormData); onSubmit?(data: FormData);
} }
const OrderShippingMethodEditDialog: React.FC< const OrderShippingMethodEditDialog: React.FC<OrderShippingMethodEditDialogProps> = props => {
OrderShippingMethodEditDialogProps
> = props => {
const { const {
confirmButtonState, confirmButtonState,
errors: apiErrors,
open, open,
shippingMethod, shippingMethod,
shippingMethods, shippingMethods,
@ -66,6 +72,12 @@ const OrderShippingMethodEditDialog: React.FC<
onSubmit onSubmit
} = props; } = props;
const classes = useStyles(props); const classes = useStyles(props);
const errors = useModalDialogErrors(apiErrors, open);
const intl = useIntl();
const formFields = ["shippingMethod"];
const formErrors = getFormErrors(formFields, errors);
const nonFieldErrors = errors.filter(err => !formFields.includes(err.field));
const choices = shippingMethods const choices = shippingMethods
? shippingMethods.map(s => ({ ? shippingMethods.map(s => ({
@ -84,6 +96,7 @@ const OrderShippingMethodEditDialog: React.FC<
const initialForm: FormData = { const initialForm: FormData = {
shippingMethod shippingMethod
}; };
return ( return (
<Dialog onClose={onClose} open={open} classes={{ paper: classes.dialog }}> <Dialog onClose={onClose} open={open} classes={{ paper: classes.dialog }}>
<DialogTitle> <DialogTitle>
@ -98,10 +111,22 @@ const OrderShippingMethodEditDialog: React.FC<
<DialogContent className={classes.root}> <DialogContent className={classes.root}>
<SingleSelectField <SingleSelectField
choices={choices} choices={choices}
error={!!formErrors.shippingMethod}
hint={getOrderErrorMessage(formErrors.shippingMethod, intl)}
name="shippingMethod" name="shippingMethod"
value={data.shippingMethod} value={data.shippingMethod}
onChange={change} onChange={change}
/> />
{nonFieldErrors.length > 0 && (
<>
<FormSpacer />
{nonFieldErrors.map(err => (
<DialogContentText color="error">
{getOrderErrorMessage(err, intl)}
</DialogContentText>
))}
</>
)}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClose}> <Button onClick={onClose}>

View file

@ -3,7 +3,7 @@ import { useIntl } from "react-intl";
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 { maybe } from "../../../misc"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import { OrderAddNote } from "../../types/OrderAddNote"; import { OrderAddNote } from "../../types/OrderAddNote";
import { OrderCancel } from "../../types/OrderCancel"; import { OrderCancel } from "../../types/OrderCancel";
import { OrderCapture } from "../../types/OrderCapture"; import { OrderCapture } from "../../types/OrderCapture";
@ -21,7 +21,7 @@ import { OrderRefund } from "../../types/OrderRefund";
import { OrderShippingMethodUpdate } from "../../types/OrderShippingMethodUpdate"; import { OrderShippingMethodUpdate } from "../../types/OrderShippingMethodUpdate";
import { OrderUpdate } from "../../types/OrderUpdate"; import { OrderUpdate } from "../../types/OrderUpdate";
import { OrderVoid } from "../../types/OrderVoid"; import { OrderVoid } from "../../types/OrderVoid";
import { orderListUrl, orderUrl } from "../../urls"; import { orderUrl, OrderUrlQueryParams } from "../../urls";
interface OrderDetailsMessages { interface OrderDetailsMessages {
children: (props: { children: (props: {
@ -45,260 +45,207 @@ interface OrderDetailsMessages {
handleShippingMethodUpdate: (data: OrderShippingMethodUpdate) => void; handleShippingMethodUpdate: (data: OrderShippingMethodUpdate) => void;
handleUpdate: (data: OrderUpdate) => void; handleUpdate: (data: OrderUpdate) => void;
}) => React.ReactElement; }) => React.ReactElement;
id: string;
params: OrderUrlQueryParams;
} }
export const OrderDetailsMessages: React.FC<OrderDetailsMessages> = ({ export const OrderDetailsMessages: React.FC<OrderDetailsMessages> = ({
children children,
id,
params
}) => { }) => {
const navigate = useNavigator(); const navigate = useNavigator();
const pushMessage = useNotifier(); const pushMessage = useNotifier();
const intl = useIntl(); const intl = useIntl();
const [, closeModal] = createDialogActionHandlers(
navigate,
params => orderUrl(id, params),
params
);
const handlePaymentCapture = (data: OrderCapture) => { const handlePaymentCapture = (data: OrderCapture) => {
if (!maybe(() => data.orderCapture.errors.length)) { const errs = data.orderCapture?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Payment successfully captured" defaultMessage: "Payment successfully captured"
}) })
}); });
} else { closeModal();
pushMessage({
text: intl.formatMessage(
{
defaultMessage: "Payment not captured: {errorMessage}"
},
{
errorMessage: data.orderCapture.errors.find(
error => error.field === "payment"
).message
}
)
});
} }
}; };
const handlePaymentRefund = (data: OrderRefund) => { const handlePaymentRefund = (data: OrderRefund) => {
if (!maybe(() => data.orderRefund.errors.length)) { const errs = data.orderRefund?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Payment successfully refunded" defaultMessage: "Payment successfully refunded"
}) })
}); });
} else { closeModal();
pushMessage({
text: intl.formatMessage(
{
defaultMessage: "Payment not refunded: {errorMessage}",
description: "notification"
},
{
errorMessage: data.orderRefund.errors.find(
error => error.field === "payment"
).message
}
)
});
} }
}; };
const handleOrderFulfillmentCreate = (data: OrderCreateFulfillment) => { const handleOrderFulfillmentCreate = (data: OrderCreateFulfillment) => {
if (!maybe(() => data.orderFulfillmentCreate.errors.length)) { const errs = data.orderFulfillmentCreate?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Items successfully fulfilled" defaultMessage: "Items successfully fulfilled"
}) })
}); });
navigate(orderUrl(data.orderFulfillmentCreate.order.id), true); closeModal();
} else {
pushMessage({
text: intl.formatMessage({
defaultMessage: "Could not fulfill items"
})
});
} }
}; };
const handleOrderMarkAsPaid = (data: OrderMarkAsPaid) => { const handleOrderMarkAsPaid = (data: OrderMarkAsPaid) => {
if (!maybe(() => data.orderMarkAsPaid.errors.length)) { const errs = data.orderMarkAsPaid?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Order marked as paid" defaultMessage: "Order marked as paid"
}) })
}); });
navigate(orderUrl(data.orderMarkAsPaid.order.id), true); closeModal();
} else {
pushMessage({
text: intl.formatMessage({
defaultMessage: "Could not mark order as paid"
})
});
} }
}; };
const handleOrderCancel = (data: OrderCancel) => { const handleOrderCancel = (data: OrderCancel) => {
pushMessage({ const errs = data.orderCancel?.errors;
text: intl.formatMessage({ if (errs.length === 0) {
defaultMessage: "Order successfully cancelled" pushMessage({
}) text: intl.formatMessage({
}); defaultMessage: "Order successfully cancelled"
navigate(orderUrl(data.orderCancel.order.id), true); })
});
closeModal();
}
}; };
const handleDraftCancel = () => { const handleDraftCancel = (data: OrderDraftCancel) => {
pushMessage({ const errs = data.draftOrderDelete?.errors;
text: intl.formatMessage({ if (errs.length === 0) {
defaultMessage: "Order successfully cancelled" pushMessage({
}) text: intl.formatMessage({
}); defaultMessage: "Order successfully cancelled"
navigate(orderListUrl(), true); })
});
closeModal();
}
}; };
const handleOrderVoid = () => { const handleOrderVoid = (data: OrderVoid) => {
pushMessage({ const errs = data.orderVoid?.errors;
text: intl.formatMessage({ if (errs.length === 0) {
defaultMessage: "Order payment successfully voided" pushMessage({
}) text: intl.formatMessage({
}); defaultMessage: "Order payment successfully voided"
})
});
closeModal();
}
}; };
const handleNoteAdd = (data: OrderAddNote) => { const handleNoteAdd = (data: OrderAddNote) => {
if (!maybe(() => data.orderAddNote.errors.length)) { const errs = data.orderAddNote?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Note successfully added" defaultMessage: "Note successfully added"
}) })
}); });
} else {
pushMessage({
text: intl.formatMessage({
defaultMessage: "Could not add note"
})
});
} }
}; };
const handleUpdate = (data: OrderUpdate) => { const handleUpdate = (data: OrderUpdate) => {
if (!maybe(() => data.orderUpdate.errors.length)) { const errs = data.orderUpdate?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Order successfully updated" defaultMessage: "Order successfully updated"
}) })
}); });
navigate(orderUrl(data.orderUpdate.order.id), true);
} }
}; };
const handleDraftUpdate = (data: OrderDraftUpdate) => { const handleDraftUpdate = (data: OrderDraftUpdate) => {
if (!maybe(() => data.draftOrderUpdate.errors.length)) { const errs = data.draftOrderUpdate?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Order successfully updated" defaultMessage: "Order successfully updated"
}) })
}); });
navigate(orderUrl(data.draftOrderUpdate.order.id), true);
} }
}; };
const handleShippingMethodUpdate = (data: OrderShippingMethodUpdate) => { const handleShippingMethodUpdate = (data: OrderShippingMethodUpdate) => {
if (!maybe(() => data.orderUpdateShipping.errors.length)) { const errs = data.orderUpdateShipping?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Shipping method successfully updated" defaultMessage: "Shipping method successfully updated"
}) })
}); });
} else { closeModal();
pushMessage({
text: intl.formatMessage({
defaultMessage: "Could not update shipping method"
})
});
} }
navigate(orderUrl(data.orderUpdateShipping.order.id), true);
}; };
const handleOrderLineDelete = (data: OrderLineDelete) => { const handleOrderLineDelete = (data: OrderLineDelete) => {
if (!maybe(() => data.draftOrderLineDelete.errors.length)) { const errs = data.draftOrderLineDelete?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Order line deleted" defaultMessage: "Order line deleted"
}) })
}); });
} else {
pushMessage({
text: intl.formatMessage({
defaultMessage: "Could not delete order line"
})
});
} }
}; };
const handleOrderLinesAdd = (data: OrderLinesAdd) => { const handleOrderLinesAdd = (data: OrderLinesAdd) => {
if (!maybe(() => data.draftOrderLinesCreate.errors.length)) { const errs = data.draftOrderLinesCreate?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Order line added" defaultMessage: "Order line added"
}) })
}); });
navigate(orderUrl(data.draftOrderLinesCreate.order.id), true); closeModal();
} else {
pushMessage({
text: intl.formatMessage({
defaultMessage: "Could not create order line"
})
});
} }
}; };
const handleOrderLineUpdate = (data: OrderLineUpdate) => { const handleOrderLineUpdate = (data: OrderLineUpdate) => {
if (!maybe(() => data.draftOrderLineUpdate.errors.length)) { const errs = data.draftOrderLineUpdate?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Order line updated" defaultMessage: "Order line updated"
}) })
}); });
} else {
pushMessage({
text: intl.formatMessage({
defaultMessage: "Could not update order line"
})
});
} }
}; };
const handleOrderFulfillmentCancel = (data: OrderFulfillmentCancel) => { const handleOrderFulfillmentCancel = (data: OrderFulfillmentCancel) => {
if (!maybe(() => data.orderFulfillmentCancel.errors.length)) { const errs = data.orderFulfillmentCancel?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Fulfillment successfully cancelled" defaultMessage: "Fulfillment successfully cancelled"
}) })
}); });
navigate(orderUrl(data.orderFulfillmentCancel.order.id), true); closeModal();
} else {
pushMessage({
text: intl.formatMessage({
defaultMessage: "Could not cancel fulfillment"
})
});
} }
}; };
const handleOrderFulfillmentUpdate = ( const handleOrderFulfillmentUpdate = (
data: OrderFulfillmentUpdateTracking data: OrderFulfillmentUpdateTracking
) => { ) => {
if (!maybe(() => data.orderFulfillmentUpdateTracking.errors.length)) { const errs = data.orderFulfillmentUpdateTracking?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Fulfillment successfully updated" defaultMessage: "Fulfillment successfully updated"
}) })
}); });
navigate(orderUrl(data.orderFulfillmentUpdateTracking.order.id), true); closeModal();
} else {
pushMessage({
text: intl.formatMessage({
defaultMessage: "Could not update fulfillment"
})
});
} }
}; };
const handleDraftFinalize = (data: OrderDraftFinalize) => { const handleDraftFinalize = (data: OrderDraftFinalize) => {
if (!maybe(() => data.draftOrderComplete.errors.length)) { const errs = data.draftOrderComplete?.errors;
if (errs.length === 0) {
pushMessage({ pushMessage({
text: intl.formatMessage({ text: intl.formatMessage({
defaultMessage: "Draft order successfully finalized" defaultMessage: "Draft order successfully finalized"
}) })
}); });
navigate(orderUrl(data.draftOrderComplete.order.id), true); closeModal();
} else {
pushMessage({
text: intl.formatMessage({
defaultMessage: "Could not finalize draft"
})
});
} }
}; };

View file

@ -1,3 +1,4 @@
import { useIntl } from "react-intl";
import React from "react"; import React from "react";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
@ -8,7 +9,11 @@ import useCustomerSearch from "@saleor/searches/useCustomerSearch";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import NotFoundPage from "@saleor/components/NotFoundPage"; import NotFoundPage from "@saleor/components/NotFoundPage";
import { customerUrl } from "../../../customers/urls"; import { customerUrl } from "../../../customers/urls";
import { getMutationState, maybe, transformAddressToForm } from "../../../misc"; import {
maybe,
transformAddressToForm,
getStringOrPlaceholder
} from "../../../misc";
import { productUrl } from "../../../products/urls"; import { productUrl } from "../../../products/urls";
import { OrderStatus } from "../../../types/globalTypes"; import { OrderStatus } from "../../../types/globalTypes";
import OrderAddressEditDialog from "../../components/OrderAddressEditDialog"; import OrderAddressEditDialog from "../../components/OrderAddressEditDialog";
@ -90,6 +95,12 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
} = useOrderVariantSearch({ } = useOrderVariantSearch({
variables: DEFAULT_INITIAL_SEARCH_DATA variables: DEFAULT_INITIAL_SEARCH_DATA
}); });
const intl = useIntl();
const [openModal, closeModal] = createDialogActionHandlers<
OrderUrlDialog,
OrderUrlQueryParams
>(navigate, params => orderUrl(id, params), params);
const handleBack = () => navigate(orderListUrl()); const handleBack = () => navigate(orderListUrl());
@ -102,13 +113,8 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
return <NotFoundPage onBack={handleBack} />; return <NotFoundPage onBack={handleBack} />;
} }
const [openModal, closeModal] = createDialogActionHandlers<
OrderUrlDialog,
OrderUrlQueryParams
>(navigate, params => orderUrl(id, params), params);
return ( return (
<OrderDetailsMessages> <OrderDetailsMessages id={id} params={params}>
{orderMessages => ( {orderMessages => (
<OrderOperations <OrderOperations
order={id} order={id}
@ -158,10 +164,20 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
orderPaymentMarkAsPaid orderPaymentMarkAsPaid
}) => ( }) => (
<> <>
{maybe(() => order.status !== OrderStatus.DRAFT) ? ( {order?.status !== OrderStatus.DRAFT ? (
<> <>
<WindowTitle <WindowTitle
title={maybe(() => "Order #" + data.order.number)} title={intl.formatMessage(
{
defaultMessage: "Order #{orderNumber}",
description: "window title"
},
{
orderNumber: getStringOrPlaceholder(
data?.order?.number
)
}
)}
/> />
<OrderDetailsPage <OrderDetailsPage
onNoteAdd={variables => onNoteAdd={variables =>
@ -211,12 +227,11 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
} }
/> />
<OrderCancelDialog <OrderCancelDialog
confirmButtonState={getMutationState( confirmButtonState={orderCancel.opts.status}
orderCancel.opts.called, errors={
orderCancel.opts.loading,
orderCancel.opts.data?.orderCancel.errors || [] orderCancel.opts.data?.orderCancel.errors || []
)} }
number={maybe(() => order.number)} number={order?.number}
open={params.action === "cancel"} open={params.action === "cancel"}
onClose={closeModal} onClose={closeModal}
onSubmit={variables => onSubmit={variables =>
@ -227,15 +242,13 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
} }
/> />
<OrderMarkAsPaidDialog <OrderMarkAsPaidDialog
confirmButtonState={getMutationState( confirmButtonState={
orderPaymentMarkAsPaid.opts.called, orderPaymentMarkAsPaid.opts.status
orderPaymentMarkAsPaid.opts.loading, }
maybe( errors={
() => orderPaymentMarkAsPaid.opts.data?.orderMarkAsPaid
orderPaymentMarkAsPaid.opts.data.orderMarkAsPaid .errors || []
.errors }
)
)}
onClose={closeModal} onClose={closeModal}
onConfirm={() => onConfirm={() =>
orderPaymentMarkAsPaid.mutate({ orderPaymentMarkAsPaid.mutate({
@ -245,26 +258,19 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
open={params.action === "mark-paid"} open={params.action === "mark-paid"}
/> />
<OrderPaymentVoidDialog <OrderPaymentVoidDialog
confirmButtonState={getMutationState( confirmButtonState={orderVoid.opts.status}
orderVoid.opts.called, errors={orderVoid.opts.data?.orderVoid.errors || []}
orderVoid.opts.loading,
maybe(() => orderVoid.opts.data.orderVoid.errors)
)}
open={params.action === "void"} open={params.action === "void"}
onClose={closeModal} onClose={closeModal}
onConfirm={() => orderVoid.mutate({ id })} onConfirm={() => orderVoid.mutate({ id })}
/> />
<OrderPaymentDialog <OrderPaymentDialog
confirmButtonState={getMutationState( confirmButtonState={orderPaymentCapture.opts.status}
orderPaymentCapture.opts.called, errors={
orderPaymentCapture.opts.loading, orderPaymentCapture.opts.data?.orderCapture
maybe( .errors || []
() => }
orderPaymentCapture.opts.data.orderCapture initial={order?.total.gross.amount}
.errors
)
)}
initial={maybe(() => order.total.gross.amount)}
open={params.action === "capture"} open={params.action === "capture"}
variant="capture" variant="capture"
onClose={closeModal} onClose={closeModal}
@ -276,13 +282,12 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
} }
/> />
<OrderPaymentDialog <OrderPaymentDialog
confirmButtonState={getMutationState( confirmButtonState={orderPaymentRefund.opts.status}
orderPaymentRefund.opts.called, errors={
orderPaymentRefund.opts.loading,
orderPaymentRefund.opts.data?.orderRefund.errors || orderPaymentRefund.opts.data?.orderRefund.errors ||
[] []
)} }
initial={maybe(() => order.total.gross.amount)} initial={order?.total.gross.amount}
open={params.action === "refund"} open={params.action === "refund"}
variant="refund" variant="refund"
onClose={closeModal} onClose={closeModal}
@ -294,15 +299,13 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
} }
/> />
<OrderFulfillmentDialog <OrderFulfillmentDialog
confirmButtonState={getMutationState( confirmButtonState={
orderCreateFulfillment.opts.called, orderCreateFulfillment.opts.status
orderCreateFulfillment.opts.loading, }
maybe( errors={
() => orderCreateFulfillment.opts.data
orderCreateFulfillment.opts.data ?.orderFulfillmentCreate.errors || []
.orderFulfillmentCreate.errors }
)
)}
open={params.action === "fulfill"} open={params.action === "fulfill"}
lines={maybe(() => order.lines, []).filter( lines={maybe(() => order.lines, []).filter(
line => line.quantityFulfilled < line.quantity line => line.quantityFulfilled < line.quantity
@ -328,15 +331,13 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
} }
/> />
<OrderFulfillmentCancelDialog <OrderFulfillmentCancelDialog
confirmButtonState={getMutationState( confirmButtonState={
orderFulfillmentCancel.opts.called, orderFulfillmentCancel.opts.status
orderFulfillmentCancel.opts.loading, }
maybe( errors={
() => orderFulfillmentCancel.opts.data
orderFulfillmentCancel.opts.data ?.orderFulfillmentCancel.errors || []
.orderFulfillmentCancel.errors }
)
)}
open={params.action === "cancel-fulfillment"} open={params.action === "cancel-fulfillment"}
onConfirm={variables => onConfirm={variables =>
orderFulfillmentCancel.mutate({ orderFulfillmentCancel.mutate({
@ -347,21 +348,18 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
onClose={closeModal} onClose={closeModal}
/> />
<OrderFulfillmentTrackingDialog <OrderFulfillmentTrackingDialog
confirmButtonState={getMutationState( confirmButtonState={
orderFulfillmentUpdateTracking.opts.called, orderFulfillmentUpdateTracking.opts.status
orderFulfillmentUpdateTracking.opts.loading, }
maybe( errors={
() => orderFulfillmentUpdateTracking.opts.data
orderFulfillmentUpdateTracking.opts.data ?.orderFulfillmentUpdateTracking.errors || []
.orderFulfillmentUpdateTracking.errors }
)
)}
open={params.action === "edit-fulfillment"} open={params.action === "edit-fulfillment"}
trackingNumber={maybe( trackingNumber={getStringOrPlaceholder(
() => data?.order?.fulfillments.find(
data.order.fulfillments.find( fulfillment => fulfillment.id === params.id
fulfillment => fulfillment.id === params.id )?.trackingNumber
).trackingNumber
)} )}
onConfirm={variables => onConfirm={variables =>
orderFulfillmentUpdateTracking.mutate({ orderFulfillmentUpdateTracking.mutate({
@ -378,8 +376,16 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
) : ( ) : (
<> <>
<WindowTitle <WindowTitle
title={maybe( title={intl.formatMessage(
() => "Draft order #" + data.order.number {
defaultMessage: "Draft Order #{orderNumber}",
description: "window title"
},
{
orderNumber: getStringOrPlaceholder(
data?.order?.number
)
}
)} )}
/> />
<OrderDraftPage <OrderDraftPage
@ -447,46 +453,39 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
userPermissions={maybe(() => user.permissions, [])} userPermissions={maybe(() => user.permissions, [])}
/> />
<OrderDraftCancelDialog <OrderDraftCancelDialog
confirmButtonState={getMutationState( confirmButtonState={orderDraftCancel.opts.status}
orderDraftCancel.opts.called, errors={
orderDraftCancel.opts.loading, orderDraftCancel.opts.data?.draftOrderDelete
maybe( .errors || []
() => }
orderDraftCancel.opts.data.draftOrderDelete
.errors
)
)}
onClose={closeModal} onClose={closeModal}
onConfirm={() => orderDraftCancel.mutate({ id })} onConfirm={() => orderDraftCancel.mutate({ id })}
open={params.action === "cancel"} open={params.action === "cancel"}
orderNumber={maybe(() => order.number)} orderNumber={getStringOrPlaceholder(order?.number)}
/> />
<OrderDraftFinalizeDialog <OrderDraftFinalizeDialog
confirmButtonState={orderDraftFinalize.opts.status} confirmButtonState={orderDraftFinalize.opts.status}
errors={
orderDraftFinalize.opts.data?.draftOrderComplete
.errors || []
}
onClose={closeModal} onClose={closeModal}
onConfirm={() => orderDraftFinalize.mutate({ id })} onConfirm={() => orderDraftFinalize.mutate({ id })}
open={params.action === "finalize"} open={params.action === "finalize"}
orderNumber={maybe(() => order.number)} orderNumber={getStringOrPlaceholder(order?.number)}
warnings={orderDraftFinalizeWarnings(order)} warnings={orderDraftFinalizeWarnings(order)}
/> />
<OrderShippingMethodEditDialog <OrderShippingMethodEditDialog
confirmButtonState={getMutationState( confirmButtonState={
orderShippingMethodUpdate.opts.called, orderShippingMethodUpdate.opts.status
orderShippingMethodUpdate.opts.loading, }
maybe( errors={
() => orderShippingMethodUpdate.opts.data
orderShippingMethodUpdate.opts.data ?.orderUpdateShipping.errors || []
.orderUpdateShipping.errors }
)
)}
open={params.action === "edit-shipping"} open={params.action === "edit-shipping"}
shippingMethod={maybe( shippingMethod={order?.shippingMethod?.id}
() => order.shippingMethod.id, shippingMethods={order?.availableShippingMethods}
"..."
)}
shippingMethods={maybe(
() => order.availableShippingMethods
)}
onClose={closeModal} onClose={closeModal}
onSubmit={variables => onSubmit={variables =>
orderShippingMethodUpdate.mutate({ orderShippingMethodUpdate.mutate({
@ -498,25 +497,18 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
} }
/> />
<OrderProductAddDialog <OrderProductAddDialog
confirmButtonState={getMutationState( confirmButtonState={orderLinesAdd.opts.status}
orderLinesAdd.opts.called, errors={
orderLinesAdd.opts.loading, orderLinesAdd.opts.data?.draftOrderLinesCreate
maybe( .errors || []
() => }
orderLinesAdd.opts.data.draftOrderLinesCreate
.errors
)
)}
loading={variantSearchOpts.loading} loading={variantSearchOpts.loading}
open={params.action === "add-order-line"} open={params.action === "add-order-line"}
hasMore={maybe( hasMore={
() => variantSearchOpts.data?.search.pageInfo.hasNextPage
variantSearchOpts.data.search.pageInfo.hasNextPage }
)} products={variantSearchOpts.data?.search.edges.map(
products={maybe(() => edge => edge.node
variantSearchOpts.data.search.edges.map(
edge => edge.node
)
)} )}
onClose={closeModal} onClose={closeModal}
onFetch={variantSearch} onFetch={variantSearch}
@ -534,24 +526,15 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
</> </>
)} )}
<OrderAddressEditDialog <OrderAddressEditDialog
confirmButtonState={getMutationState( confirmButtonState={orderUpdate.opts.status}
orderUpdate.opts.called, address={transformAddressToForm(order?.shippingAddress)}
orderUpdate.opts.loading, countries={
maybe(() => orderUpdate.opts.data.orderUpdate.errors) data?.shop?.countries.map(country => ({
)}
address={transformAddressToForm(
maybe(() => order.shippingAddress)
)}
countries={maybe(() => data.shop.countries, []).map(
country => ({
code: country.code, code: country.code,
label: country.country label: country.country
}) })) || []
)} }
errors={maybe( errors={orderUpdate.opts.data?.orderUpdate.errors || []}
() => orderUpdate.opts.data.orderUpdate.errors,
[]
)}
open={params.action === "edit-shipping-address"} open={params.action === "edit-shipping-address"}
variant="shipping" variant="shipping"
onClose={closeModal} onClose={closeModal}
@ -565,24 +548,15 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
} }
/> />
<OrderAddressEditDialog <OrderAddressEditDialog
confirmButtonState={getMutationState( confirmButtonState={orderUpdate.opts.status}
orderUpdate.opts.called, address={transformAddressToForm(order?.billingAddress)}
orderUpdate.opts.loading, countries={
maybe(() => orderUpdate.opts.data.orderUpdate.errors) data?.shop?.countries.map(country => ({
)}
address={transformAddressToForm(
maybe(() => order.billingAddress)
)}
countries={maybe(() => data.shop.countries, []).map(
country => ({
code: country.code, code: country.code,
label: country.country label: country.country
}) })) || []
)} }
errors={maybe( errors={orderUpdate.opts.data?.orderUpdate.errors || []}
() => orderUpdate.opts.data.orderUpdate.errors,
[]
)}
open={params.action === "edit-billing-address"} open={params.action === "edit-billing-address"}
variant="billing" variant="billing"
onClose={closeModal} onClose={closeModal}

View file

@ -7939,6 +7939,12 @@ exports[`Storyshots Orders / OrderCancelDialog default 1`] = `
/> />
`; `;
exports[`Storyshots Orders / OrderCancelDialog errors 1`] = `
<div
style="padding:24px"
/>
`;
exports[`Storyshots Orders / OrderCustomer default 1`] = ` exports[`Storyshots Orders / OrderCustomer default 1`] = `
<div <div
style="padding:24px" style="padding:24px"
@ -8522,12 +8528,24 @@ exports[`Storyshots Orders / OrderDraftCancelDialog default 1`] = `
/> />
`; `;
exports[`Storyshots Orders / OrderDraftCancelDialog errors 1`] = `
<div
style="padding:24px"
/>
`;
exports[`Storyshots Orders / OrderDraftFinalizeDialog default 1`] = ` exports[`Storyshots Orders / OrderDraftFinalizeDialog default 1`] = `
<div <div
style="padding:24px" style="padding:24px"
/> />
`; `;
exports[`Storyshots Orders / OrderDraftFinalizeDialog with errors 1`] = `
<div
style="padding:24px"
/>
`;
exports[`Storyshots Orders / OrderDraftFinalizeDialog with warnings 1`] = ` exports[`Storyshots Orders / OrderDraftFinalizeDialog with warnings 1`] = `
<div <div
style="padding:24px" style="padding:24px"
@ -8540,18 +8558,36 @@ exports[`Storyshots Orders / OrderFulfillmentCancelDialog default 1`] = `
/> />
`; `;
exports[`Storyshots Orders / OrderFulfillmentCancelDialog error 1`] = `
<div
style="padding:24px"
/>
`;
exports[`Storyshots Orders / OrderFulfillmentDialog default 1`] = ` exports[`Storyshots Orders / OrderFulfillmentDialog default 1`] = `
<div <div
style="padding:24px" style="padding:24px"
/> />
`; `;
exports[`Storyshots Orders / OrderFulfillmentDialog errors 1`] = `
<div
style="padding:24px"
/>
`;
exports[`Storyshots Orders / OrderFulfillmentTrackingDialog default 1`] = ` exports[`Storyshots Orders / OrderFulfillmentTrackingDialog default 1`] = `
<div <div
style="padding:24px" style="padding:24px"
/> />
`; `;
exports[`Storyshots Orders / OrderFulfillmentTrackingDialog errors 1`] = `
<div
style="padding:24px"
/>
`;
exports[`Storyshots Orders / OrderHistory default 1`] = ` exports[`Storyshots Orders / OrderHistory default 1`] = `
<div <div
style="padding:24px" style="padding:24px"
@ -8681,12 +8717,24 @@ exports[`Storyshots Orders / OrderMarkAsPaidDialog default 1`] = `
/> />
`; `;
exports[`Storyshots Orders / OrderMarkAsPaidDialog errors 1`] = `
<div
style="padding:24px"
/>
`;
exports[`Storyshots Orders / OrderPaymentDialog capture payment 1`] = ` exports[`Storyshots Orders / OrderPaymentDialog capture payment 1`] = `
<div <div
style="padding:24px" style="padding:24px"
/> />
`; `;
exports[`Storyshots Orders / OrderPaymentDialog errors 1`] = `
<div
style="padding:24px"
/>
`;
exports[`Storyshots Orders / OrderPaymentDialog refund payment 1`] = ` exports[`Storyshots Orders / OrderPaymentDialog refund payment 1`] = `
<div <div
style="padding:24px" style="padding:24px"
@ -8699,18 +8747,36 @@ exports[`Storyshots Orders / OrderPaymentVoidDialog default 1`] = `
/> />
`; `;
exports[`Storyshots Orders / OrderPaymentVoidDialog errors 1`] = `
<div
style="padding:24px"
/>
`;
exports[`Storyshots Orders / OrderProductAddDialog default 1`] = ` exports[`Storyshots Orders / OrderProductAddDialog default 1`] = `
<div <div
style="padding:24px" style="padding:24px"
/> />
`; `;
exports[`Storyshots Orders / OrderProductAddDialog errors 1`] = `
<div
style="padding:24px"
/>
`;
exports[`Storyshots Orders / OrderShippingMethodEditDialog default 1`] = ` exports[`Storyshots Orders / OrderShippingMethodEditDialog default 1`] = `
<div <div
style="padding:24px" style="padding:24px"
/> />
`; `;
exports[`Storyshots Orders / OrderShippingMethodEditDialog errors 1`] = `
<div
style="padding:24px"
/>
`;
exports[`Storyshots Product types / ProductTypeDeleteDialog default 1`] = ` exports[`Storyshots Product types / ProductTypeDeleteDialog default 1`] = `
<div <div
style="padding:24px" style="padding:24px"

View file

@ -1,17 +1,42 @@
import { storiesOf } from "@storybook/react"; import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import OrderCancelDialog from "../../../orders/components/OrderCancelDialog"; import { OrderErrorCode } from "@saleor/types/globalTypes";
import OrderCancelDialog, {
OrderCancelDialogProps
} from "../../../orders/components/OrderCancelDialog";
import Decorator from "../../Decorator"; import Decorator from "../../Decorator";
const props: OrderCancelDialogProps = {
confirmButtonState: "default",
errors: [],
number: "123",
onClose: () => undefined,
onSubmit: () => undefined,
open: true
};
storiesOf("Orders / OrderCancelDialog", module) storiesOf("Orders / OrderCancelDialog", module)
.addDecorator(Decorator) .addDecorator(Decorator)
.add("default", () => ( .add("default", () => (
<OrderCancelDialog <OrderCancelDialog
confirmButtonState="default" confirmButtonState="default"
errors={[]}
open={true} open={true}
number="123" number="123"
onSubmit={undefined} onSubmit={undefined}
onClose={undefined} onClose={undefined}
/> />
))
.add("errors", () => (
<OrderCancelDialog
{...props}
errors={[
{
__typename: "OrderError",
code: OrderErrorCode.CANNOT_CANCEL_ORDER,
field: null
}
]}
/>
)); ));

View file

@ -1,6 +1,7 @@
import { storiesOf } from "@storybook/react"; import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { OrderErrorCode } from "@saleor/types/globalTypes";
import OrderDraftCancelDialog, { import OrderDraftCancelDialog, {
OrderDraftCancelDialogProps OrderDraftCancelDialogProps
} from "../../../orders/components/OrderDraftCancelDialog"; } from "../../../orders/components/OrderDraftCancelDialog";
@ -8,6 +9,7 @@ import Decorator from "../../Decorator";
const props: OrderDraftCancelDialogProps = { const props: OrderDraftCancelDialogProps = {
confirmButtonState: "default", confirmButtonState: "default",
errors: [],
onClose: () => undefined, onClose: () => undefined,
onConfirm: () => undefined, onConfirm: () => undefined,
open: true, open: true,
@ -16,4 +18,16 @@ const props: OrderDraftCancelDialogProps = {
storiesOf("Orders / OrderDraftCancelDialog", module) storiesOf("Orders / OrderDraftCancelDialog", module)
.addDecorator(Decorator) .addDecorator(Decorator)
.add("default", () => <OrderDraftCancelDialog {...props} />); .add("default", () => <OrderDraftCancelDialog {...props} />)
.add("errors", () => (
<OrderDraftCancelDialog
{...props}
errors={[
{
__typename: "OrderError",
code: OrderErrorCode.GRAPHQL_ERROR,
field: null
}
]}
/>
));

View file

@ -1,6 +1,7 @@
import { storiesOf } from "@storybook/react"; import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { OrderErrorCode } from "@saleor/types/globalTypes";
import OrderDraftFinalize, { import OrderDraftFinalize, {
OrderDraftFinalizeDialogProps, OrderDraftFinalizeDialogProps,
OrderDraftFinalizeWarning OrderDraftFinalizeWarning
@ -9,6 +10,7 @@ import Decorator from "../../Decorator";
const props: OrderDraftFinalizeDialogProps = { const props: OrderDraftFinalizeDialogProps = {
confirmButtonState: "default", confirmButtonState: "default",
errors: [],
onClose: () => undefined, onClose: () => undefined,
onConfirm: () => undefined, onConfirm: () => undefined,
open: true, open: true,
@ -29,4 +31,16 @@ storiesOf("Orders / OrderDraftFinalizeDialog", module)
OrderDraftFinalizeWarning.NO_USER OrderDraftFinalizeWarning.NO_USER
]} ]}
/> />
))
.add("with errors", () => (
<OrderDraftFinalize
{...props}
errors={[
{
__typename: "OrderError",
code: OrderErrorCode.GRAPHQL_ERROR,
field: null
}
]}
/>
)); ));

View file

@ -1,16 +1,32 @@
import { storiesOf } from "@storybook/react"; import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import OrderFulfillmentCancelDialog from "../../../orders/components/OrderFulfillmentCancelDialog"; import { OrderErrorCode } from "@saleor/types/globalTypes";
import OrderFulfillmentCancelDialog, {
OrderFulfillmentCancelDialogProps
} from "../../../orders/components/OrderFulfillmentCancelDialog";
import Decorator from "../../Decorator"; import Decorator from "../../Decorator";
const props: OrderFulfillmentCancelDialogProps = {
confirmButtonState: "default",
errors: [],
onClose: () => undefined,
onConfirm: () => undefined,
open: true
};
storiesOf("Orders / OrderFulfillmentCancelDialog", module) storiesOf("Orders / OrderFulfillmentCancelDialog", module)
.addDecorator(Decorator) .addDecorator(Decorator)
.add("default", () => ( .add("default", () => <OrderFulfillmentCancelDialog {...props} />)
.add("error", () => (
<OrderFulfillmentCancelDialog <OrderFulfillmentCancelDialog
confirmButtonState="default" {...props}
open={true} errors={[
onConfirm={undefined} {
onClose={undefined} __typename: "OrderError",
code: OrderErrorCode.GRAPHQL_ERROR,
field: null
}
]}
/> />
)); ));

View file

@ -3,6 +3,7 @@ import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import placeholderImage from "@assets/images/placeholder60x60.png"; import placeholderImage from "@assets/images/placeholder60x60.png";
import { OrderErrorCode } from "@saleor/types/globalTypes";
import OrderFulfillmentDialog, { import OrderFulfillmentDialog, {
OrderFulfillmentDialogProps OrderFulfillmentDialogProps
} from "../../../orders/components/OrderFulfillmentDialog"; } from "../../../orders/components/OrderFulfillmentDialog";
@ -13,6 +14,7 @@ const order = orderFixture(placeholderImage);
const props: Omit<OrderFulfillmentDialogProps, "classes"> = { const props: Omit<OrderFulfillmentDialogProps, "classes"> = {
confirmButtonState: "default", confirmButtonState: "default",
errors: [],
lines: order.lines, lines: order.lines,
onClose: undefined, onClose: undefined,
onSubmit: undefined, onSubmit: undefined,
@ -21,4 +23,21 @@ const props: Omit<OrderFulfillmentDialogProps, "classes"> = {
storiesOf("Orders / OrderFulfillmentDialog", module) storiesOf("Orders / OrderFulfillmentDialog", module)
.addDecorator(Decorator) .addDecorator(Decorator)
.add("default", () => <OrderFulfillmentDialog {...props} />); .add("default", () => <OrderFulfillmentDialog {...props} />)
.add("errors", () => (
<OrderFulfillmentDialog
{...props}
errors={[
{
__typename: "OrderError",
code: OrderErrorCode.FULFILL_ORDER_LINE,
field: null
},
{
__typename: "OrderError",
code: OrderErrorCode.INVALID,
field: "trackingNumber"
}
]}
/>
));

View file

@ -1,17 +1,38 @@
import { storiesOf } from "@storybook/react"; import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import OrderFulfillmentTrackingDialog from "../../../orders/components/OrderFulfillmentTrackingDialog"; import { OrderErrorCode } from "@saleor/types/globalTypes";
import OrderFulfillmentTrackingDialog, {
OrderFulfillmentTrackingDialogProps
} from "../../../orders/components/OrderFulfillmentTrackingDialog";
import Decorator from "../../Decorator"; import Decorator from "../../Decorator";
const props: OrderFulfillmentTrackingDialogProps = {
confirmButtonState: "default",
errors: [],
onClose: () => undefined,
onConfirm: () => undefined,
open: true,
trackingNumber: "21kn7526v1"
};
storiesOf("Orders / OrderFulfillmentTrackingDialog", module) storiesOf("Orders / OrderFulfillmentTrackingDialog", module)
.addDecorator(Decorator) .addDecorator(Decorator)
.add("default", () => ( .add("default", () => <OrderFulfillmentTrackingDialog {...props} />)
.add("errors", () => (
<OrderFulfillmentTrackingDialog <OrderFulfillmentTrackingDialog
confirmButtonState="default" {...props}
open={true} errors={[
trackingNumber="21kn7526v1" {
onConfirm={undefined} __typename: "OrderError",
onClose={undefined} code: OrderErrorCode.GRAPHQL_ERROR,
field: null
},
{
__typename: "OrderError",
code: OrderErrorCode.INVALID,
field: "trackingNumber"
}
]}
/> />
)); ));

View file

@ -1,6 +1,7 @@
import { storiesOf } from "@storybook/react"; import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { OrderErrorCode } from "@saleor/types/globalTypes";
import OrderMarkAsPaidDialog, { import OrderMarkAsPaidDialog, {
OrderMarkAsPaidDialogProps OrderMarkAsPaidDialogProps
} from "../../../orders/components/OrderMarkAsPaidDialog"; } from "../../../orders/components/OrderMarkAsPaidDialog";
@ -8,6 +9,7 @@ import Decorator from "../../Decorator";
const props: OrderMarkAsPaidDialogProps = { const props: OrderMarkAsPaidDialogProps = {
confirmButtonState: "default", confirmButtonState: "default",
errors: [],
onClose: () => undefined, onClose: () => undefined,
onConfirm: () => undefined, onConfirm: () => undefined,
open: true open: true
@ -15,4 +17,16 @@ const props: OrderMarkAsPaidDialogProps = {
storiesOf("Orders / OrderMarkAsPaidDialog", module) storiesOf("Orders / OrderMarkAsPaidDialog", module)
.addDecorator(Decorator) .addDecorator(Decorator)
.add("default", () => <OrderMarkAsPaidDialog {...props} />); .add("default", () => <OrderMarkAsPaidDialog {...props} />)
.add("errors", () => (
<OrderMarkAsPaidDialog
{...props}
errors={[
{
__typename: "OrderError",
code: OrderErrorCode.GRAPHQL_ERROR,
field: null
}
]}
/>
));

View file

@ -1,28 +1,43 @@
import { storiesOf } from "@storybook/react"; import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import OrderPaymentDialog from "../../../orders/components/OrderPaymentDialog"; import { OrderErrorCode } from "@saleor/types/globalTypes";
import OrderPaymentDialog, {
OrderPaymentDialogProps
} from "../../../orders/components/OrderPaymentDialog";
import Decorator from "../../Decorator"; import Decorator from "../../Decorator";
const props: OrderPaymentDialogProps = {
confirmButtonState: "default",
errors: [],
initial: 0,
onClose: () => undefined,
onSubmit: () => undefined,
open: true,
variant: "capture"
};
storiesOf("Orders / OrderPaymentDialog", module) storiesOf("Orders / OrderPaymentDialog", module)
.addDecorator(Decorator) .addDecorator(Decorator)
.add("capture payment", () => ( .add("capture payment", () => <OrderPaymentDialog {...props} />)
<OrderPaymentDialog
confirmButtonState="default"
initial={0}
variant="capture"
open={true}
onClose={undefined}
onSubmit={undefined}
/>
))
.add("refund payment", () => ( .add("refund payment", () => (
<OrderPaymentDialog {...props} variant="refund" />
))
.add("errors", () => (
<OrderPaymentDialog <OrderPaymentDialog
confirmButtonState="default" {...props}
initial={0} errors={[
{
__typename: "OrderError",
code: OrderErrorCode.CANNOT_REFUND,
field: null
},
{
__typename: "OrderError",
code: OrderErrorCode.INVALID,
field: "payment"
}
]}
variant="refund" variant="refund"
open={true}
onClose={undefined}
onSubmit={undefined}
/> />
)); ));

View file

@ -1,16 +1,32 @@
import { storiesOf } from "@storybook/react"; import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import OrderPaymentVoidDialog from "../../../orders/components/OrderPaymentVoidDialog"; import { OrderErrorCode } from "@saleor/types/globalTypes";
import OrderPaymentVoidDialog, {
OrderPaymentVoidDialogProps
} from "../../../orders/components/OrderPaymentVoidDialog";
import Decorator from "../../Decorator"; import Decorator from "../../Decorator";
const props: OrderPaymentVoidDialogProps = {
confirmButtonState: "default",
errors: [],
onClose: () => undefined,
onConfirm: () => undefined,
open: true
};
storiesOf("Orders / OrderPaymentVoidDialog", module) storiesOf("Orders / OrderPaymentVoidDialog", module)
.addDecorator(Decorator) .addDecorator(Decorator)
.add("default", () => ( .add("default", () => <OrderPaymentVoidDialog {...props} />)
.add("errors", () => (
<OrderPaymentVoidDialog <OrderPaymentVoidDialog
confirmButtonState="default" {...props}
open={true} errors={[
onConfirm={undefined} {
onClose={undefined} __typename: "OrderError",
code: OrderErrorCode.VOID_INACTIVE_PAYMENT,
field: null
}
]}
/> />
)); ));

View file

@ -2,22 +2,37 @@ import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import placeholderImage from "@assets/images/placeholder60x60.png"; import placeholderImage from "@assets/images/placeholder60x60.png";
import OrderProductAddDialog from "../../../orders/components/OrderProductAddDialog"; import { fetchMoreProps } from "@saleor/fixtures";
import { OrderErrorCode } from "@saleor/types/globalTypes";
import OrderProductAddDialog, {
OrderProductAddDialogProps
} from "../../../orders/components/OrderProductAddDialog";
import { orderLineSearch } from "../../../orders/fixtures"; import { orderLineSearch } from "../../../orders/fixtures";
import Decorator from "../../Decorator"; import Decorator from "../../Decorator";
const props: OrderProductAddDialogProps = {
...fetchMoreProps,
confirmButtonState: "default",
errors: [],
onClose: () => undefined,
onFetch: () => undefined,
onSubmit: () => undefined,
open: true,
products: orderLineSearch(placeholderImage)
};
storiesOf("Orders / OrderProductAddDialog", module) storiesOf("Orders / OrderProductAddDialog", module)
.addDecorator(Decorator) .addDecorator(Decorator)
.add("default", () => ( .add("default", () => <OrderProductAddDialog {...props} />)
.add("errors", () => (
<OrderProductAddDialog <OrderProductAddDialog
confirmButtonState="default" {...props}
loading={false} errors={[
open={true} {
onClose={undefined} __typename: "OrderError",
onSubmit={undefined} code: OrderErrorCode.GRAPHQL_ERROR,
hasMore={false} field: null
onFetch={() => undefined} }
onFetchMore={() => undefined} ]}
products={orderLineSearch(placeholderImage)}
/> />
)); ));

View file

@ -1,21 +1,41 @@
import { storiesOf } from "@storybook/react"; import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import OrderShippingMethodEditDialog from "../../../orders/components/OrderShippingMethodEditDialog"; import { OrderErrorCode } from "@saleor/types/globalTypes";
import OrderShippingMethodEditDialog, {
OrderShippingMethodEditDialogProps
} from "../../../orders/components/OrderShippingMethodEditDialog";
import { order as orderFixture } from "../../../orders/fixtures"; import { order as orderFixture } from "../../../orders/fixtures";
import Decorator from "../../Decorator"; import Decorator from "../../Decorator";
const order = orderFixture(""); const order = orderFixture("");
const props: OrderShippingMethodEditDialogProps = {
confirmButtonState: "default",
errors: [],
onClose: () => undefined,
onSubmit: () => undefined,
open: true,
shippingMethod: null,
shippingMethods: order.availableShippingMethods
};
storiesOf("Orders / OrderShippingMethodEditDialog", module) storiesOf("Orders / OrderShippingMethodEditDialog", module)
.addDecorator(Decorator) .addDecorator(Decorator)
.add("default", () => ( .add("default", () => <OrderShippingMethodEditDialog {...props} />)
.add("errors", () => (
<OrderShippingMethodEditDialog <OrderShippingMethodEditDialog
confirmButtonState="default" {...props}
onClose={undefined} errors={[
onSubmit={undefined} {
open={true} __typename: "OrderError",
shippingMethod={null} code: OrderErrorCode.SHIPPING_METHOD_NOT_APPLICABLE,
shippingMethods={order.availableShippingMethods} field: "shippingMethod"
},
{
__typename: "OrderError",
code: OrderErrorCode.GRAPHQL_ERROR,
field: null
}
]}
/> />
)); ));

View file

@ -1,22 +1,100 @@
import { IntlShape } from "react-intl"; import { IntlShape, defineMessages } from "react-intl";
import { OrderErrorCode } from "@saleor/types/globalTypes"; import { OrderErrorCode } from "@saleor/types/globalTypes";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment"; import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment";
import commonErrorMessages from "./common"; import commonErrorMessages from "./common";
const messages = defineMessages({
billingNotSet: {
defaultMessage: "Billing address is not set",
description: "error message"
},
cannotCancelFulfillment: {
defaultMessage: "This fulfillment cannot be cancelled",
description: "error message"
},
cannotCancelOrder: {
defaultMessage: "This order cannot be cancelled",
description: "error message"
},
cannotFulfillLine: {
defaultMessage: "Not enough items to fulfill",
description: "error message"
},
cannotRefund: {
defaultMessage: "Manual payments can not be refunded",
description: "error message"
},
cannotVoid: {
defaultMessage: "Only pre-authorized payments can be voided",
description: "error message"
},
captureInactive: {
defaultMessage: "Only pre-authorized payments can be captured",
description: "error message"
},
noShippingAddress: {
defaultMessage:
"Cannot choose a shipping method for an order without the shipping address",
description: "error message"
},
notEditable: {
defaultMessage: "Only draft orders can be edited",
description: "error message"
},
paymentMissing: {
defaultMessage: "There's no payment associated with the order",
description: "error message"
},
shippingNotApplicable: {
defaultMessage: "Shipping method is not valid for chosen shipping address",
description: "error message"
},
shippingRequired: {
defaultMessage: "Shipping method is required for this order",
description: "error message"
}
});
// cannot_delete
function getOrderErrorMessage( function getOrderErrorMessage(
err: OrderErrorFragment, err: OrderErrorFragment,
intl: IntlShape intl: IntlShape
): string { ): string {
if (err) { if (err) {
switch (err.code) { switch (err.code) {
case OrderErrorCode.BILLING_ADDRESS_NOT_SET:
return intl.formatMessage(messages.billingNotSet);
case OrderErrorCode.CANNOT_CANCEL_FULFILLMENT:
return intl.formatMessage(messages.cannotCancelFulfillment);
case OrderErrorCode.CANNOT_CANCEL_ORDER:
return intl.formatMessage(messages.cannotCancelOrder);
case OrderErrorCode.CANNOT_REFUND:
return intl.formatMessage(messages.cannotRefund);
case OrderErrorCode.CAPTURE_INACTIVE_PAYMENT:
return intl.formatMessage(messages.captureInactive);
case OrderErrorCode.FULFILL_ORDER_LINE:
return intl.formatMessage(messages.cannotFulfillLine);
case OrderErrorCode.GRAPHQL_ERROR: case OrderErrorCode.GRAPHQL_ERROR:
return intl.formatMessage(commonErrorMessages.graphqlError); return intl.formatMessage(commonErrorMessages.graphqlError);
case OrderErrorCode.INVALID: case OrderErrorCode.INVALID:
return intl.formatMessage(commonErrorMessages.invalid); return intl.formatMessage(commonErrorMessages.invalid);
case OrderErrorCode.NOT_EDITABLE:
return intl.formatMessage(messages.notEditable);
case OrderErrorCode.ORDER_NO_SHIPPING_ADDRESS:
return intl.formatMessage(messages.noShippingAddress);
case OrderErrorCode.PAYMENT_MISSING:
return intl.formatMessage(messages.paymentMissing);
case OrderErrorCode.REQUIRED: case OrderErrorCode.REQUIRED:
return intl.formatMessage(commonMessages.requiredField); return intl.formatMessage(commonMessages.requiredField);
case OrderErrorCode.SHIPPING_METHOD_NOT_APPLICABLE:
return intl.formatMessage(messages.shippingNotApplicable);
case OrderErrorCode.SHIPPING_METHOD_REQUIRED:
return intl.formatMessage(messages.shippingRequired);
case OrderErrorCode.VOID_INACTIVE_PAYMENT:
return intl.formatMessage(messages.cannotVoid);
default: default:
return intl.formatMessage(commonErrorMessages.unknownError); return intl.formatMessage(commonErrorMessages.unknownError);
} }