Use error codes in navigation section
This commit is contained in:
parent
5146386ee5
commit
61c3eb51fd
9 changed files with 95 additions and 22 deletions
|
@ -12,8 +12,9 @@ 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 { getFieldError } from "@saleor/utils/errors";
|
import { MenuErrorFragment } from "@saleor/navigation/types/MenuErrorFragment";
|
||||||
import { UserError } from "@saleor/types";
|
import { getFormErrors } from "@saleor/utils/errors";
|
||||||
|
import getMenuErrorMessage from "@saleor/utils/errors/menu";
|
||||||
|
|
||||||
export interface MenuCreateDialogFormData {
|
export interface MenuCreateDialogFormData {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -22,7 +23,7 @@ export interface MenuCreateDialogFormData {
|
||||||
export interface MenuCreateDialogProps {
|
export interface MenuCreateDialogProps {
|
||||||
confirmButtonState: ConfirmButtonTransitionState;
|
confirmButtonState: ConfirmButtonTransitionState;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
errors: UserError[];
|
errors: MenuErrorFragment[];
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onConfirm: (data: MenuCreateDialogFormData) => void;
|
onConfirm: (data: MenuCreateDialogFormData) => void;
|
||||||
|
@ -42,6 +43,8 @@ const MenuCreateDialog: React.FC<MenuCreateDialogProps> = ({
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const formErrors = getFormErrors(["name"], errors);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog onClose={onClose} maxWidth="sm" fullWidth open={open}>
|
<Dialog onClose={onClose} maxWidth="sm" fullWidth open={open}>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
|
@ -57,9 +60,9 @@ const MenuCreateDialog: React.FC<MenuCreateDialogProps> = ({
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<TextField
|
<TextField
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
error={!!getFieldError(errors, "name")}
|
error={!!formErrors.name}
|
||||||
fullWidth
|
fullWidth
|
||||||
helperText={getFieldError(errors, "name")?.message}
|
helperText={getMenuErrorMessage(formErrors.name, intl)}
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
defaultMessage: "Menu Title",
|
defaultMessage: "Menu Title",
|
||||||
id: "menuCreateDialogMenuTitleLabel"
|
id: "menuCreateDialogMenuTitleLabel"
|
||||||
|
|
|
@ -10,6 +10,7 @@ import Form from "@saleor/components/Form";
|
||||||
import Grid from "@saleor/components/Grid";
|
import Grid from "@saleor/components/Grid";
|
||||||
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
|
import { MenuErrorFragment } from "@saleor/navigation/types/MenuErrorFragment";
|
||||||
import { maybe } from "../../../misc";
|
import { maybe } from "../../../misc";
|
||||||
import { MenuDetails_menu } from "../../types/MenuDetails";
|
import { MenuDetails_menu } from "../../types/MenuDetails";
|
||||||
import { MenuItemType } from "../MenuItemDialog";
|
import { MenuItemType } from "../MenuItemDialog";
|
||||||
|
@ -28,6 +29,7 @@ export interface MenuDetailsSubmitData extends MenuDetailsFormData {
|
||||||
export interface MenuDetailsPageProps {
|
export interface MenuDetailsPageProps {
|
||||||
saveButtonState: ConfirmButtonTransitionState;
|
saveButtonState: ConfirmButtonTransitionState;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
|
errors: MenuErrorFragment[];
|
||||||
menu: MenuDetails_menu;
|
menu: MenuDetails_menu;
|
||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
|
@ -39,6 +41,7 @@ export interface MenuDetailsPageProps {
|
||||||
|
|
||||||
const MenuDetailsPage: React.FC<MenuDetailsPageProps> = ({
|
const MenuDetailsPage: React.FC<MenuDetailsPageProps> = ({
|
||||||
disabled,
|
disabled,
|
||||||
|
errors,
|
||||||
menu,
|
menu,
|
||||||
saveButtonState,
|
saveButtonState,
|
||||||
onBack,
|
onBack,
|
||||||
|
@ -98,6 +101,7 @@ const MenuDetailsPage: React.FC<MenuDetailsPageProps> = ({
|
||||||
<MenuProperties
|
<MenuProperties
|
||||||
data={data}
|
data={data}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
errors={errors}
|
||||||
onChange={change}
|
onChange={change}
|
||||||
/>
|
/>
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
|
|
|
@ -21,9 +21,10 @@ import { buttonMessages, sectionNames } from "@saleor/intl";
|
||||||
import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories";
|
import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories";
|
||||||
import { SearchCollections_search_edges_node } from "@saleor/searches/types/SearchCollections";
|
import { SearchCollections_search_edges_node } from "@saleor/searches/types/SearchCollections";
|
||||||
import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPages";
|
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 { 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 type MenuItemType = "category" | "collection" | "link" | "page";
|
||||||
export interface MenuItemData {
|
export interface MenuItemData {
|
||||||
|
@ -38,7 +39,7 @@ export interface MenuItemDialogFormData extends MenuItemData {
|
||||||
export interface MenuItemDialogProps {
|
export interface MenuItemDialogProps {
|
||||||
confirmButtonState: ConfirmButtonTransitionState;
|
confirmButtonState: ConfirmButtonTransitionState;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
errors: UserError[];
|
errors: MenuErrorFragment[];
|
||||||
initial?: MenuItemDialogFormData;
|
initial?: MenuItemDialogFormData;
|
||||||
initialDisplayValue?: string;
|
initialDisplayValue?: string;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
@ -112,7 +113,11 @@ const MenuItemDialog: React.FC<MenuItemDialogProps> = ({
|
||||||
initialDisplayValue
|
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 = [];
|
let options: IMenu = [];
|
||||||
|
|
||||||
|
@ -208,10 +213,6 @@ const MenuItemDialog: React.FC<MenuItemDialogProps> = ({
|
||||||
|
|
||||||
const handleSubmit = () => onSubmit(data);
|
const handleSubmit = () => onSubmit(data);
|
||||||
|
|
||||||
const idError = ["category", "collection", "page", "url"]
|
|
||||||
.map(field => getFieldError(errors, field))
|
|
||||||
.reduce((acc, err) => acc || err);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
|
@ -252,8 +253,8 @@ const MenuItemDialog: React.FC<MenuItemDialogProps> = ({
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
name="name"
|
name="name"
|
||||||
error={!!getFieldError(errors, "name")}
|
error={!!formErrors.name}
|
||||||
helperText={getFieldError(errors, "name")?.message}
|
helperText={getMenuErrorMessage(formErrors.name, intl)}
|
||||||
/>
|
/>
|
||||||
<FormSpacer />
|
<FormSpacer />
|
||||||
<AutocompleteSelectMenu
|
<AutocompleteSelectMenu
|
||||||
|
@ -269,7 +270,7 @@ const MenuItemDialog: React.FC<MenuItemDialogProps> = ({
|
||||||
loading={loading}
|
loading={loading}
|
||||||
options={options}
|
options={options}
|
||||||
error={!!idError}
|
error={!!idError}
|
||||||
helperText={idError?.message}
|
helperText={getMenuErrorMessage(idError, intl)}
|
||||||
placeholder={intl.formatMessage({
|
placeholder={intl.formatMessage({
|
||||||
defaultMessage: "Start typing to begin search...",
|
defaultMessage: "Start typing to begin search...",
|
||||||
id: "menuItemDialogLinkPlaceholder"
|
id: "menuItemDialogLinkPlaceholder"
|
||||||
|
@ -280,8 +281,8 @@ const MenuItemDialog: React.FC<MenuItemDialogProps> = ({
|
||||||
<>
|
<>
|
||||||
<FormSpacer />
|
<FormSpacer />
|
||||||
{mutationErrors.map(err => (
|
{mutationErrors.map(err => (
|
||||||
<Typography key={err} color="error">
|
<Typography key={err.code} color="error">
|
||||||
{err}
|
{getMenuErrorMessage(err, intl)}
|
||||||
</Typography>
|
</Typography>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -6,21 +6,28 @@ import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import CardTitle from "@saleor/components/CardTitle";
|
import CardTitle from "@saleor/components/CardTitle";
|
||||||
import { commonMessages } from "@saleor/intl";
|
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";
|
import { MenuDetailsFormData } from "../MenuDetailsPage";
|
||||||
|
|
||||||
export interface MenuPropertiesProps {
|
export interface MenuPropertiesProps {
|
||||||
data: MenuDetailsFormData;
|
data: MenuDetailsFormData;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
|
errors: MenuErrorFragment[];
|
||||||
onChange: (event: React.ChangeEvent<any>) => void;
|
onChange: (event: React.ChangeEvent<any>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MenuProperties: React.FC<MenuPropertiesProps> = ({
|
const MenuProperties: React.FC<MenuPropertiesProps> = ({
|
||||||
data,
|
data,
|
||||||
disabled,
|
disabled,
|
||||||
|
errors,
|
||||||
onChange
|
onChange
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const formErrors = getFormErrors(["name"], errors);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardTitle
|
<CardTitle
|
||||||
|
@ -29,12 +36,14 @@ const MenuProperties: React.FC<MenuPropertiesProps> = ({
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<TextField
|
<TextField
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
error={!!formErrors.name}
|
||||||
name={"name" as keyof MenuDetailsFormData}
|
name={"name" as keyof MenuDetailsFormData}
|
||||||
fullWidth
|
fullWidth
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
defaultMessage: "Menu Title",
|
defaultMessage: "Menu Title",
|
||||||
id: "menuPropertiesMenuTitle"
|
id: "menuPropertiesMenuTitle"
|
||||||
})}
|
})}
|
||||||
|
helperText={getMenuErrorMessage(formErrors.name, intl)}
|
||||||
value={data.name}
|
value={data.name}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -169,6 +169,11 @@ const MenuDetails: React.FC<MenuDetailsProps> = ({ id, params }) => {
|
||||||
<>
|
<>
|
||||||
<MenuDetailsPage
|
<MenuDetailsPage
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
|
errors={[
|
||||||
|
...(menuUpdateOpts.data?.menuUpdate.errors || []),
|
||||||
|
...(menuUpdateOpts.data?.menuItemMove.errors || []),
|
||||||
|
...(menuUpdateOpts.data?.menuUpdate.errors || [])
|
||||||
|
]}
|
||||||
menu={maybe(() => data.menu)}
|
menu={maybe(() => data.menu)}
|
||||||
onBack={() => navigate(menuListUrl())}
|
onBack={() => navigate(menuListUrl())}
|
||||||
onDelete={() =>
|
onDelete={() =>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { storiesOf } from "@storybook/react";
|
import { storiesOf } from "@storybook/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { formError } from "@saleor/storybook/misc";
|
import { MenuErrorCode } from "@saleor/types/globalTypes";
|
||||||
import MenuCreateDialog, {
|
import MenuCreateDialog, {
|
||||||
MenuCreateDialogProps
|
MenuCreateDialogProps
|
||||||
} from "../../../navigation/components/MenuCreateDialog";
|
} from "../../../navigation/components/MenuCreateDialog";
|
||||||
|
@ -23,5 +23,12 @@ storiesOf("Navigation / Menu create", module)
|
||||||
<MenuCreateDialog {...props} disabled={true} confirmButtonState="loading" />
|
<MenuCreateDialog {...props} disabled={true} confirmButtonState="loading" />
|
||||||
))
|
))
|
||||||
.add("form errors", () => (
|
.add("form errors", () => (
|
||||||
<MenuCreateDialog {...props} errors={["name"].map(formError)} />
|
<MenuCreateDialog
|
||||||
|
{...props}
|
||||||
|
errors={["name"].map(field => ({
|
||||||
|
__typename: "MenuError",
|
||||||
|
code: MenuErrorCode.INVALID,
|
||||||
|
field
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
));
|
));
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { storiesOf } from "@storybook/react";
|
import { storiesOf } from "@storybook/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
import { MenuErrorCode } from "@saleor/types/globalTypes";
|
||||||
import MenuDetailsPage, {
|
import MenuDetailsPage, {
|
||||||
MenuDetailsPageProps
|
MenuDetailsPageProps
|
||||||
} from "../../../navigation/components/MenuDetailsPage";
|
} from "../../../navigation/components/MenuDetailsPage";
|
||||||
|
@ -9,6 +10,7 @@ import Decorator from "../../Decorator";
|
||||||
|
|
||||||
const props: MenuDetailsPageProps = {
|
const props: MenuDetailsPageProps = {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
errors: [],
|
||||||
menu,
|
menu,
|
||||||
onBack: () => undefined,
|
onBack: () => undefined,
|
||||||
onDelete: () => undefined,
|
onDelete: () => undefined,
|
||||||
|
@ -33,4 +35,14 @@ storiesOf("Views / Navigation / Menu details", module)
|
||||||
items: []
|
items: []
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
))
|
||||||
|
.add("form errors", () => (
|
||||||
|
<MenuDetailsPage
|
||||||
|
{...props}
|
||||||
|
errors={["name"].map(field => ({
|
||||||
|
__typename: "MenuError",
|
||||||
|
code: MenuErrorCode.INVALID,
|
||||||
|
field
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
));
|
));
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { storiesOf } from "@storybook/react";
|
import { storiesOf } from "@storybook/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { formError } from "@saleor/storybook/misc";
|
import { MenuErrorCode } from "@saleor/types/globalTypes";
|
||||||
import MenuItemDialog, {
|
import MenuItemDialog, {
|
||||||
MenuItemDialogProps
|
MenuItemDialogProps
|
||||||
} from "../../../navigation/components/MenuItemDialog";
|
} from "../../../navigation/components/MenuItemDialog";
|
||||||
|
@ -48,6 +48,10 @@ storiesOf("Navigation / Menu item", module)
|
||||||
.add("errors", () => (
|
.add("errors", () => (
|
||||||
<MenuItemDialog
|
<MenuItemDialog
|
||||||
{...props}
|
{...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
28
src/utils/errors/menu.ts
Normal 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;
|
Loading…
Reference in a new issue