Use error formatting in page views
This commit is contained in:
parent
78b3feb656
commit
e1f1a217da
12 changed files with 107 additions and 44 deletions
|
@ -19,8 +19,8 @@ import SeoForm from "@saleor/components/SeoForm";
|
||||||
import VisibilityCard from "@saleor/components/VisibilityCard";
|
import VisibilityCard from "@saleor/components/VisibilityCard";
|
||||||
import useDateLocalize from "@saleor/hooks/useDateLocalize";
|
import useDateLocalize from "@saleor/hooks/useDateLocalize";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
|
import { PageErrorFragment } from "@saleor/pages/types/PageErrorFragment";
|
||||||
import { maybe } from "../../../misc";
|
import { maybe } from "../../../misc";
|
||||||
import { UserError } from "../../../types";
|
|
||||||
import { PageDetails_page } from "../../types/PageDetails";
|
import { PageDetails_page } from "../../types/PageDetails";
|
||||||
import PageInfo from "../PageInfo";
|
import PageInfo from "../PageInfo";
|
||||||
import PageSlug from "../PageSlug";
|
import PageSlug from "../PageSlug";
|
||||||
|
@ -37,7 +37,7 @@ export interface FormData {
|
||||||
|
|
||||||
export interface PageDetailsPageProps {
|
export interface PageDetailsPageProps {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
errors: UserError[];
|
errors: PageErrorFragment[];
|
||||||
page: PageDetails_page;
|
page: PageDetails_page;
|
||||||
saveButtonBarState: ConfirmButtonTransitionState;
|
saveButtonBarState: ConfirmButtonTransitionState;
|
||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
|
|
|
@ -9,16 +9,17 @@ import CardTitle from "@saleor/components/CardTitle";
|
||||||
import FormSpacer from "@saleor/components/FormSpacer";
|
import FormSpacer from "@saleor/components/FormSpacer";
|
||||||
import RichTextEditor from "@saleor/components/RichTextEditor";
|
import RichTextEditor from "@saleor/components/RichTextEditor";
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { commonMessages } from "@saleor/intl";
|
||||||
import { getFieldError } from "@saleor/utils/errors";
|
import { getFormErrors } from "@saleor/utils/errors";
|
||||||
|
import { PageErrorFragment } from "@saleor/pages/types/PageErrorFragment";
|
||||||
|
import getPageErrorMessage from "@saleor/utils/errors/page";
|
||||||
import { maybe } from "../../../misc";
|
import { maybe } from "../../../misc";
|
||||||
import { UserError } from "../../../types";
|
|
||||||
import { PageDetails_page } from "../../types/PageDetails";
|
import { PageDetails_page } from "../../types/PageDetails";
|
||||||
import { FormData } from "../PageDetailsPage";
|
import { FormData } from "../PageDetailsPage";
|
||||||
|
|
||||||
export interface PageInfoProps {
|
export interface PageInfoProps {
|
||||||
data: FormData;
|
data: FormData;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
errors: UserError[];
|
errors: PageErrorFragment[];
|
||||||
page: PageDetails_page;
|
page: PageDetails_page;
|
||||||
onChange: (event: React.ChangeEvent<any>) => void;
|
onChange: (event: React.ChangeEvent<any>) => void;
|
||||||
}
|
}
|
||||||
|
@ -34,10 +35,12 @@ const useStyles = makeStyles(
|
||||||
|
|
||||||
const PageInfo: React.FC<PageInfoProps> = props => {
|
const PageInfo: React.FC<PageInfoProps> = props => {
|
||||||
const { data, disabled, errors, page, onChange } = props;
|
const { data, disabled, errors, page, onChange } = props;
|
||||||
const classes = useStyles(props);
|
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const formErrors = getFormErrors(["title", "contentJson"], errors);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={classes.root}>
|
<Card className={classes.root}>
|
||||||
<CardTitle
|
<CardTitle
|
||||||
|
@ -46,9 +49,9 @@ const PageInfo: React.FC<PageInfoProps> = props => {
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<TextField
|
<TextField
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
error={!!getFieldError(errors, "title")}
|
error={!!formErrors.title}
|
||||||
fullWidth
|
fullWidth
|
||||||
helperText={getFieldError(errors, "title")?.message}
|
helperText={getPageErrorMessage(formErrors.title, intl)}
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
defaultMessage: "Title",
|
defaultMessage: "Title",
|
||||||
description: "page title"
|
description: "page title"
|
||||||
|
@ -60,8 +63,8 @@ const PageInfo: React.FC<PageInfoProps> = props => {
|
||||||
<FormSpacer />
|
<FormSpacer />
|
||||||
<RichTextEditor
|
<RichTextEditor
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
error={!!getFieldError(errors, "contentJson")}
|
error={!!formErrors.contentJson}
|
||||||
helperText={getFieldError(errors, "contentJson")?.message}
|
helperText={getPageErrorMessage(formErrors.contentJson, intl)}
|
||||||
initial={maybe(() => JSON.parse(page.contentJson))}
|
initial={maybe(() => JSON.parse(page.contentJson))}
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
defaultMessage: "Content",
|
defaultMessage: "Content",
|
||||||
|
|
|
@ -6,14 +6,15 @@ import { useIntl } from "react-intl";
|
||||||
import slugify from "slugify";
|
import slugify from "slugify";
|
||||||
|
|
||||||
import CardTitle from "@saleor/components/CardTitle";
|
import CardTitle from "@saleor/components/CardTitle";
|
||||||
import { UserError } from "@saleor/types";
|
import { getFormErrors } from "@saleor/utils/errors";
|
||||||
import { getFieldError } from "@saleor/utils/errors";
|
import getPageErrorMessage from "@saleor/utils/errors/page";
|
||||||
|
import { PageErrorFragment } from "@saleor/pages/types/PageErrorFragment";
|
||||||
import { FormData } from "../PageDetailsPage";
|
import { FormData } from "../PageDetailsPage";
|
||||||
|
|
||||||
export interface PageSlugProps {
|
export interface PageSlugProps {
|
||||||
data: FormData;
|
data: FormData;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
errors: UserError[];
|
errors: PageErrorFragment[];
|
||||||
onChange: (event: React.ChangeEvent<any>) => void;
|
onChange: (event: React.ChangeEvent<any>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +26,8 @@ const PageSlug: React.FC<PageSlugProps> = ({
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const formErrors = getFormErrors(["slug"], errors);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardTitle
|
<CardTitle
|
||||||
|
@ -36,13 +39,13 @@ const PageSlug: React.FC<PageSlugProps> = ({
|
||||||
<TextField
|
<TextField
|
||||||
name={"slug" as keyof FormData}
|
name={"slug" as keyof FormData}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
error={!!getFieldError(errors, "slug")}
|
error={!!formErrors.slug}
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
defaultMessage: "Slug",
|
defaultMessage: "Slug",
|
||||||
description: "page internal name"
|
description: "page internal name"
|
||||||
})}
|
})}
|
||||||
helperText={
|
helperText={
|
||||||
getFieldError(errors, "slug")?.message ||
|
getPageErrorMessage(formErrors.slug, intl) ||
|
||||||
intl.formatMessage({
|
intl.formatMessage({
|
||||||
defaultMessage:
|
defaultMessage:
|
||||||
"If empty, URL will be autogenerated from Page Name"
|
"If empty, URL will be autogenerated from Page Name"
|
||||||
|
|
|
@ -14,13 +14,20 @@ import { PageCreate, PageCreateVariables } from "./types/PageCreate";
|
||||||
import { PageRemove, PageRemoveVariables } from "./types/PageRemove";
|
import { PageRemove, PageRemoveVariables } from "./types/PageRemove";
|
||||||
import { PageUpdate, PageUpdateVariables } from "./types/PageUpdate";
|
import { PageUpdate, PageUpdateVariables } from "./types/PageUpdate";
|
||||||
|
|
||||||
|
const pageErrorFragment = gql`
|
||||||
|
fragment PageErrorFragment on PageError {
|
||||||
|
code
|
||||||
|
field
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
const pageCreate = gql`
|
const pageCreate = gql`
|
||||||
${pageDetailsFragment}
|
${pageDetailsFragment}
|
||||||
|
${pageErrorFragment}
|
||||||
mutation PageCreate($input: PageInput!) {
|
mutation PageCreate($input: PageInput!) {
|
||||||
pageCreate(input: $input) {
|
pageCreate(input: $input) {
|
||||||
errors {
|
errors: pageErrors {
|
||||||
field
|
...PageErrorFragment
|
||||||
message
|
|
||||||
}
|
}
|
||||||
page {
|
page {
|
||||||
...PageDetailsFragment
|
...PageDetailsFragment
|
||||||
|
@ -34,11 +41,11 @@ export const TypedPageCreate = TypedMutation<PageCreate, PageCreateVariables>(
|
||||||
|
|
||||||
const pageUpdate = gql`
|
const pageUpdate = gql`
|
||||||
${pageDetailsFragment}
|
${pageDetailsFragment}
|
||||||
|
${pageErrorFragment}
|
||||||
mutation PageUpdate($id: ID!, $input: PageInput!) {
|
mutation PageUpdate($id: ID!, $input: PageInput!) {
|
||||||
pageUpdate(id: $id, input: $input) {
|
pageUpdate(id: $id, input: $input) {
|
||||||
errors {
|
errors: pageErrors {
|
||||||
field
|
...PageErrorFragment
|
||||||
message
|
|
||||||
}
|
}
|
||||||
page {
|
page {
|
||||||
...PageDetailsFragment
|
...PageDetailsFragment
|
||||||
|
@ -51,11 +58,11 @@ export const TypedPageUpdate = TypedMutation<PageUpdate, PageUpdateVariables>(
|
||||||
);
|
);
|
||||||
|
|
||||||
const pageRemove = gql`
|
const pageRemove = gql`
|
||||||
|
${pageErrorFragment}
|
||||||
mutation PageRemove($id: ID!) {
|
mutation PageRemove($id: ID!) {
|
||||||
pageDelete(id: $id) {
|
pageDelete(id: $id) {
|
||||||
errors {
|
errors: pageErrors {
|
||||||
field
|
...PageErrorFragment
|
||||||
message
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { PageInput } from "./../../types/globalTypes";
|
import { PageInput, PageErrorCode } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL mutation operation: PageCreate
|
// GraphQL mutation operation: PageCreate
|
||||||
// ====================================================
|
// ====================================================
|
||||||
|
|
||||||
export interface PageCreate_pageCreate_errors {
|
export interface PageCreate_pageCreate_errors {
|
||||||
__typename: "Error";
|
__typename: "PageError";
|
||||||
|
code: PageErrorCode;
|
||||||
field: string | null;
|
field: string | null;
|
||||||
message: string | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PageCreate_pageCreate_page {
|
export interface PageCreate_pageCreate_page {
|
||||||
|
|
15
src/pages/types/PageErrorFragment.ts
Normal file
15
src/pages/types/PageErrorFragment.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
import { PageErrorCode } from "./../../types/globalTypes";
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL fragment: PageErrorFragment
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface PageErrorFragment {
|
||||||
|
__typename: "PageError";
|
||||||
|
code: PageErrorCode;
|
||||||
|
field: string | null;
|
||||||
|
}
|
|
@ -2,14 +2,16 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
import { PageErrorCode } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL mutation operation: PageRemove
|
// GraphQL mutation operation: PageRemove
|
||||||
// ====================================================
|
// ====================================================
|
||||||
|
|
||||||
export interface PageRemove_pageDelete_errors {
|
export interface PageRemove_pageDelete_errors {
|
||||||
__typename: "Error";
|
__typename: "PageError";
|
||||||
|
code: PageErrorCode;
|
||||||
field: string | null;
|
field: string | null;
|
||||||
message: string | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PageRemove_pageDelete {
|
export interface PageRemove_pageDelete {
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { PageInput } from "./../../types/globalTypes";
|
import { PageInput, PageErrorCode } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL mutation operation: PageUpdate
|
// GraphQL mutation operation: PageUpdate
|
||||||
// ====================================================
|
// ====================================================
|
||||||
|
|
||||||
export interface PageUpdate_pageUpdate_errors {
|
export interface PageUpdate_pageUpdate_errors {
|
||||||
__typename: "Error";
|
__typename: "PageError";
|
||||||
|
code: PageErrorCode;
|
||||||
field: string | null;
|
field: string | null;
|
||||||
message: string | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PageUpdate_pageUpdate_page {
|
export interface PageUpdate_pageUpdate_page {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { useIntl } from "react-intl";
|
||||||
import { WindowTitle } from "@saleor/components/WindowTitle";
|
import { WindowTitle } from "@saleor/components/WindowTitle";
|
||||||
import useNavigator from "@saleor/hooks/useNavigator";
|
import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
import useNotifier from "@saleor/hooks/useNotifier";
|
import useNotifier from "@saleor/hooks/useNotifier";
|
||||||
import { maybe } from "../../misc";
|
|
||||||
import PageDetailsPage from "../components/PageDetailsPage";
|
import PageDetailsPage from "../components/PageDetailsPage";
|
||||||
import { TypedPageCreate } from "../mutations";
|
import { TypedPageCreate } from "../mutations";
|
||||||
import { PageCreate as PageCreateData } from "../types/PageCreate";
|
import { PageCreate as PageCreateData } from "../types/PageCreate";
|
||||||
|
@ -42,7 +41,7 @@ export const PageCreate: React.FC<PageCreateProps> = () => {
|
||||||
/>
|
/>
|
||||||
<PageDetailsPage
|
<PageDetailsPage
|
||||||
disabled={pageCreateOpts.loading}
|
disabled={pageCreateOpts.loading}
|
||||||
errors={maybe(() => pageCreateOpts.data.pageCreate.errors, [])}
|
errors={pageCreateOpts.data?.pageCreate.errors || []}
|
||||||
saveButtonBarState={pageCreateOpts.status}
|
saveButtonBarState={pageCreateOpts.status}
|
||||||
page={null}
|
page={null}
|
||||||
onBack={() => navigate(pageListUrl())}
|
onBack={() => navigate(pageListUrl())}
|
||||||
|
|
|
@ -6,7 +6,8 @@ import ActionDialog from "@saleor/components/ActionDialog";
|
||||||
import { WindowTitle } from "@saleor/components/WindowTitle";
|
import { WindowTitle } from "@saleor/components/WindowTitle";
|
||||||
import useNavigator from "@saleor/hooks/useNavigator";
|
import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
import useNotifier from "@saleor/hooks/useNotifier";
|
import useNotifier from "@saleor/hooks/useNotifier";
|
||||||
import { maybe } from "../../misc";
|
import { commonMessages } from "@saleor/intl";
|
||||||
|
import { maybe, getStringOrPlaceholder } from "../../misc";
|
||||||
import { PageInput } from "../../types/globalTypes";
|
import { PageInput } from "../../types/globalTypes";
|
||||||
import PageDetailsPage, { FormData } from "../components/PageDetailsPage";
|
import PageDetailsPage, { FormData } from "../components/PageDetailsPage";
|
||||||
import { TypedPageRemove, TypedPageUpdate } from "../mutations";
|
import { TypedPageRemove, TypedPageUpdate } from "../mutations";
|
||||||
|
@ -43,9 +44,7 @@ export const PageDetails: React.FC<PageDetailsProps> = ({ id, params }) => {
|
||||||
const handlePageRemove = (data: PageRemove) => {
|
const handlePageRemove = (data: PageRemove) => {
|
||||||
if (data.pageDelete.errors.length === 0) {
|
if (data.pageDelete.errors.length === 0) {
|
||||||
notify({
|
notify({
|
||||||
text: intl.formatMessage({
|
text: intl.formatMessage(commonMessages.savedChanges)
|
||||||
defaultMessage: "Removed page"
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
navigate(pageListUrl());
|
navigate(pageListUrl());
|
||||||
}
|
}
|
||||||
|
@ -63,12 +62,9 @@ export const PageDetails: React.FC<PageDetailsProps> = ({ id, params }) => {
|
||||||
/>
|
/>
|
||||||
<PageDetailsPage
|
<PageDetailsPage
|
||||||
disabled={pageDetails.loading}
|
disabled={pageDetails.loading}
|
||||||
errors={maybe(
|
errors={pageUpdateOpts.data?.pageUpdate.errors || []}
|
||||||
() => pageUpdateOpts.data.pageUpdate.errors,
|
|
||||||
[]
|
|
||||||
)}
|
|
||||||
saveButtonBarState={pageUpdateOpts.status}
|
saveButtonBarState={pageUpdateOpts.status}
|
||||||
page={maybe(() => pageDetails.data.page)}
|
page={pageDetails.data?.page}
|
||||||
onBack={() => navigate(pageListUrl())}
|
onBack={() => navigate(pageListUrl())}
|
||||||
onRemove={() =>
|
onRemove={() =>
|
||||||
navigate(
|
navigate(
|
||||||
|
@ -104,7 +100,9 @@ export const PageDetails: React.FC<PageDetailsProps> = ({ id, params }) => {
|
||||||
values={{
|
values={{
|
||||||
title: (
|
title: (
|
||||||
<strong>
|
<strong>
|
||||||
{maybe(() => pageDetails.data.page.title, "...")}
|
{getStringOrPlaceholder(
|
||||||
|
pageDetails.data?.page?.title
|
||||||
|
)}
|
||||||
</strong>
|
</strong>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -519,6 +519,14 @@ export enum OrderStatusFilter {
|
||||||
UNFULFILLED = "UNFULFILLED",
|
UNFULFILLED = "UNFULFILLED",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum PageErrorCode {
|
||||||
|
GRAPHQL_ERROR = "GRAPHQL_ERROR",
|
||||||
|
INVALID = "INVALID",
|
||||||
|
NOT_FOUND = "NOT_FOUND",
|
||||||
|
REQUIRED = "REQUIRED",
|
||||||
|
UNIQUE = "UNIQUE",
|
||||||
|
}
|
||||||
|
|
||||||
export enum PageSortField {
|
export enum PageSortField {
|
||||||
CREATION_DATE = "CREATION_DATE",
|
CREATION_DATE = "CREATION_DATE",
|
||||||
PUBLICATION_DATE = "PUBLICATION_DATE",
|
PUBLICATION_DATE = "PUBLICATION_DATE",
|
||||||
|
|
28
src/utils/errors/page.ts
Normal file
28
src/utils/errors/page.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { IntlShape } from "react-intl";
|
||||||
|
|
||||||
|
import { PageErrorFragment } from "@saleor/pages/types/PageErrorFragment";
|
||||||
|
import { PageErrorCode } from "@saleor/types/globalTypes";
|
||||||
|
import { commonMessages } from "@saleor/intl";
|
||||||
|
import commonErrorMessages from "./common";
|
||||||
|
|
||||||
|
function getPageErrorMessage(
|
||||||
|
err: Omit<PageErrorFragment, "__typename"> | undefined,
|
||||||
|
intl: IntlShape
|
||||||
|
): string {
|
||||||
|
if (err) {
|
||||||
|
switch (err.code) {
|
||||||
|
case PageErrorCode.GRAPHQL_ERROR:
|
||||||
|
return intl.formatMessage(commonErrorMessages.graphqlError);
|
||||||
|
case PageErrorCode.REQUIRED:
|
||||||
|
return intl.formatMessage(commonMessages.requiredField);
|
||||||
|
case PageErrorCode.INVALID:
|
||||||
|
return intl.formatMessage(commonErrorMessages.invalid);
|
||||||
|
default:
|
||||||
|
return intl.formatMessage(commonErrorMessages.unknownError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getPageErrorMessage;
|
Loading…
Reference in a new issue