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";
|
||||
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"
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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>
|
||||
))}
|
||||
</>
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
|
|
|
@ -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={() =>
|
||||
|
|
|
@ -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
|
||||
}))}
|
||||
/>
|
||||
));
|
||||
|
|
|
@ -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
|
||||
}))}
|
||||
/>
|
||||
));
|
||||
|
|
|
@ -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
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