Use error codes in navigation section

This commit is contained in:
dominik-zeglen 2020-03-11 14:03:31 +01:00
parent 5146386ee5
commit 61c3eb51fd
9 changed files with 95 additions and 22 deletions

View file

@ -12,8 +12,9 @@ import ConfirmButton, {
} from "@saleor/components/ConfirmButton";
import Form from "@saleor/components/Form";
import { buttonMessages } from "@saleor/intl";
import { getFieldError } from "@saleor/utils/errors";
import { UserError } from "@saleor/types";
import { MenuErrorFragment } from "@saleor/navigation/types/MenuErrorFragment";
import { getFormErrors } from "@saleor/utils/errors";
import getMenuErrorMessage from "@saleor/utils/errors/menu";
export interface MenuCreateDialogFormData {
name: string;
@ -22,7 +23,7 @@ export interface MenuCreateDialogFormData {
export interface MenuCreateDialogProps {
confirmButtonState: ConfirmButtonTransitionState;
disabled: boolean;
errors: UserError[];
errors: MenuErrorFragment[];
open: boolean;
onClose: () => void;
onConfirm: (data: MenuCreateDialogFormData) => void;
@ -42,6 +43,8 @@ const MenuCreateDialog: React.FC<MenuCreateDialogProps> = ({
}) => {
const intl = useIntl();
const formErrors = getFormErrors(["name"], errors);
return (
<Dialog onClose={onClose} maxWidth="sm" fullWidth open={open}>
<DialogTitle>
@ -57,9 +60,9 @@ const MenuCreateDialog: React.FC<MenuCreateDialogProps> = ({
<DialogContent>
<TextField
disabled={disabled}
error={!!getFieldError(errors, "name")}
error={!!formErrors.name}
fullWidth
helperText={getFieldError(errors, "name")?.message}
helperText={getMenuErrorMessage(formErrors.name, intl)}
label={intl.formatMessage({
defaultMessage: "Menu Title",
id: "menuCreateDialogMenuTitleLabel"

View file

@ -10,6 +10,7 @@ import Form from "@saleor/components/Form";
import Grid from "@saleor/components/Grid";
import SaveButtonBar from "@saleor/components/SaveButtonBar";
import { sectionNames } from "@saleor/intl";
import { MenuErrorFragment } from "@saleor/navigation/types/MenuErrorFragment";
import { maybe } from "../../../misc";
import { MenuDetails_menu } from "../../types/MenuDetails";
import { MenuItemType } from "../MenuItemDialog";
@ -28,6 +29,7 @@ export interface MenuDetailsSubmitData extends MenuDetailsFormData {
export interface MenuDetailsPageProps {
saveButtonState: ConfirmButtonTransitionState;
disabled: boolean;
errors: MenuErrorFragment[];
menu: MenuDetails_menu;
onBack: () => void;
onDelete: () => void;
@ -39,6 +41,7 @@ export interface MenuDetailsPageProps {
const MenuDetailsPage: React.FC<MenuDetailsPageProps> = ({
disabled,
errors,
menu,
saveButtonState,
onBack,
@ -98,6 +101,7 @@ const MenuDetailsPage: React.FC<MenuDetailsPageProps> = ({
<MenuProperties
data={data}
disabled={disabled}
errors={errors}
onChange={change}
/>
<CardSpacer />

View file

@ -21,9 +21,10 @@ import { buttonMessages, sectionNames } from "@saleor/intl";
import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories";
import { SearchCollections_search_edges_node } from "@saleor/searches/types/SearchCollections";
import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPages";
import { UserError } from "@saleor/types";
import { getErrors, getFieldError } from "@saleor/utils/errors";
import { getMenuItemByValue, IMenu } from "@saleor/utils/menu";
import { MenuErrorFragment } from "@saleor/navigation/types/MenuErrorFragment";
import { getFieldError, getFormErrors } from "@saleor/utils/errors";
import getMenuErrorMessage from "@saleor/utils/errors/menu";
export type MenuItemType = "category" | "collection" | "link" | "page";
export interface MenuItemData {
@ -38,7 +39,7 @@ export interface MenuItemDialogFormData extends MenuItemData {
export interface MenuItemDialogProps {
confirmButtonState: ConfirmButtonTransitionState;
disabled: boolean;
errors: UserError[];
errors: MenuErrorFragment[];
initial?: MenuItemDialogFormData;
initialDisplayValue?: string;
loading: boolean;
@ -112,7 +113,11 @@ const MenuItemDialog: React.FC<MenuItemDialogProps> = ({
initialDisplayValue
]);
const mutationErrors = getErrors(errors);
const mutationErrors = errors.filter(err => err.field === null);
const formErrors = getFormErrors(["name"], errors);
const idError = ["category", "collection", "page", "url"]
.map(field => getFieldError(errors, field))
.reduce((acc, err) => acc || err);
let options: IMenu = [];
@ -208,10 +213,6 @@ const MenuItemDialog: React.FC<MenuItemDialogProps> = ({
const handleSubmit = () => onSubmit(data);
const idError = ["category", "collection", "page", "url"]
.map(field => getFieldError(errors, field))
.reduce((acc, err) => acc || err);
return (
<Dialog
onClose={onClose}
@ -252,8 +253,8 @@ const MenuItemDialog: React.FC<MenuItemDialogProps> = ({
}))
}
name="name"
error={!!getFieldError(errors, "name")}
helperText={getFieldError(errors, "name")?.message}
error={!!formErrors.name}
helperText={getMenuErrorMessage(formErrors.name, intl)}
/>
<FormSpacer />
<AutocompleteSelectMenu
@ -269,7 +270,7 @@ const MenuItemDialog: React.FC<MenuItemDialogProps> = ({
loading={loading}
options={options}
error={!!idError}
helperText={idError?.message}
helperText={getMenuErrorMessage(idError, intl)}
placeholder={intl.formatMessage({
defaultMessage: "Start typing to begin search...",
id: "menuItemDialogLinkPlaceholder"
@ -280,8 +281,8 @@ const MenuItemDialog: React.FC<MenuItemDialogProps> = ({
<>
<FormSpacer />
{mutationErrors.map(err => (
<Typography key={err} color="error">
{err}
<Typography key={err.code} color="error">
{getMenuErrorMessage(err, intl)}
</Typography>
))}
</>

View file

@ -6,21 +6,28 @@ import { useIntl } from "react-intl";
import CardTitle from "@saleor/components/CardTitle";
import { commonMessages } from "@saleor/intl";
import { MenuErrorFragment } from "@saleor/navigation/types/MenuErrorFragment";
import { getFormErrors } from "@saleor/utils/errors";
import getMenuErrorMessage from "@saleor/utils/errors/menu";
import { MenuDetailsFormData } from "../MenuDetailsPage";
export interface MenuPropertiesProps {
data: MenuDetailsFormData;
disabled: boolean;
errors: MenuErrorFragment[];
onChange: (event: React.ChangeEvent<any>) => void;
}
const MenuProperties: React.FC<MenuPropertiesProps> = ({
data,
disabled,
errors,
onChange
}) => {
const intl = useIntl();
const formErrors = getFormErrors(["name"], errors);
return (
<Card>
<CardTitle
@ -29,12 +36,14 @@ const MenuProperties: React.FC<MenuPropertiesProps> = ({
<CardContent>
<TextField
disabled={disabled}
error={!!formErrors.name}
name={"name" as keyof MenuDetailsFormData}
fullWidth
label={intl.formatMessage({
defaultMessage: "Menu Title",
id: "menuPropertiesMenuTitle"
})}
helperText={getMenuErrorMessage(formErrors.name, intl)}
value={data.name}
onChange={onChange}
/>

View file

@ -169,6 +169,11 @@ const MenuDetails: React.FC<MenuDetailsProps> = ({ id, params }) => {
<>
<MenuDetailsPage
disabled={loading}
errors={[
...(menuUpdateOpts.data?.menuUpdate.errors || []),
...(menuUpdateOpts.data?.menuItemMove.errors || []),
...(menuUpdateOpts.data?.menuUpdate.errors || [])
]}
menu={maybe(() => data.menu)}
onBack={() => navigate(menuListUrl())}
onDelete={() =>

View file

@ -1,7 +1,7 @@
import { storiesOf } from "@storybook/react";
import React from "react";
import { formError } from "@saleor/storybook/misc";
import { MenuErrorCode } from "@saleor/types/globalTypes";
import MenuCreateDialog, {
MenuCreateDialogProps
} from "../../../navigation/components/MenuCreateDialog";
@ -23,5 +23,12 @@ storiesOf("Navigation / Menu create", module)
<MenuCreateDialog {...props} disabled={true} confirmButtonState="loading" />
))
.add("form errors", () => (
<MenuCreateDialog {...props} errors={["name"].map(formError)} />
<MenuCreateDialog
{...props}
errors={["name"].map(field => ({
__typename: "MenuError",
code: MenuErrorCode.INVALID,
field
}))}
/>
));

View file

@ -1,6 +1,7 @@
import { storiesOf } from "@storybook/react";
import React from "react";
import { MenuErrorCode } from "@saleor/types/globalTypes";
import MenuDetailsPage, {
MenuDetailsPageProps
} from "../../../navigation/components/MenuDetailsPage";
@ -9,6 +10,7 @@ import Decorator from "../../Decorator";
const props: MenuDetailsPageProps = {
disabled: false,
errors: [],
menu,
onBack: () => undefined,
onDelete: () => undefined,
@ -33,4 +35,14 @@ storiesOf("Views / Navigation / Menu details", module)
items: []
}}
/>
))
.add("form errors", () => (
<MenuDetailsPage
{...props}
errors={["name"].map(field => ({
__typename: "MenuError",
code: MenuErrorCode.INVALID,
field
}))}
/>
));

View file

@ -1,7 +1,7 @@
import { storiesOf } from "@storybook/react";
import React from "react";
import { formError } from "@saleor/storybook/misc";
import { MenuErrorCode } from "@saleor/types/globalTypes";
import MenuItemDialog, {
MenuItemDialogProps
} from "../../../navigation/components/MenuItemDialog";
@ -48,6 +48,10 @@ storiesOf("Navigation / Menu item", module)
.add("errors", () => (
<MenuItemDialog
{...props}
errors={["", "", "name", "category"].map(formError)}
errors={[null, null, "name", "category"].map(field => ({
__typename: "MenuError",
code: MenuErrorCode.INVALID,
field
}))}
/>
));

28
src/utils/errors/menu.ts Normal file
View file

@ -0,0 +1,28 @@
import { IntlShape } from "react-intl";
import { MenuErrorCode } from "@saleor/types/globalTypes";
import { commonMessages } from "@saleor/intl";
import { MenuErrorFragment } from "@saleor/navigation/types/MenuErrorFragment";
import commonErrorMessages from "./common";
function getMenuErrorMessage(
err: Omit<MenuErrorFragment, "__typename"> | undefined,
intl: IntlShape
): string {
if (err) {
switch (err.code) {
case MenuErrorCode.GRAPHQL_ERROR:
return intl.formatMessage(commonErrorMessages.graphqlError);
case MenuErrorCode.REQUIRED:
return intl.formatMessage(commonMessages.requiredField);
case MenuErrorCode.INVALID:
return intl.formatMessage(commonErrorMessages.invalid);
default:
return intl.formatMessage(commonErrorMessages.unknownError);
}
}
return undefined;
}
export default getMenuErrorMessage;