add error handling to seo form

This commit is contained in:
Magdalena Markusik 2020-09-24 14:11:30 +02:00
parent 8093876c7b
commit 828e207209
6 changed files with 79 additions and 12 deletions

View file

@ -79,6 +79,7 @@ export const CategoryCreatePage: React.FC<CategoryCreatePageProps> = ({
/> />
<CardSpacer /> <CardSpacer />
<SeoForm <SeoForm
isCreating={true}
helperText={intl.formatMessage({ helperText={intl.formatMessage({
defaultMessage: defaultMessage:
"Add search engine title and description to make this category easier to find" "Add search engine title and description to make this category easier to find"

View file

@ -135,6 +135,7 @@ const CollectionCreatePage: React.FC<CollectionCreatePageProps> = ({
/> />
<CardSpacer /> <CardSpacer />
<SeoForm <SeoForm
isCreating={true}
description={data.seoDescription} description={data.seoDescription}
disabled={disabled} disabled={disabled}
descriptionPlaceholder="" descriptionPlaceholder=""

View file

@ -4,6 +4,11 @@ import CardContent from "@material-ui/core/CardContent";
import { makeStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import { PageErrorFragment } from "@saleor/fragments/types/PageErrorFragment";
import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment";
import { PageErrorCode, ProductErrorCode } from "@saleor/types/globalTypes";
import { getProductErrorMessage } from "@saleor/utils/errors";
import getPageErrorMessage from "@saleor/utils/errors/page";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -12,6 +17,21 @@ import slugify from "slugify";
import CardTitle from "../CardTitle"; import CardTitle from "../CardTitle";
import FormSpacer from "../FormSpacer"; import FormSpacer from "../FormSpacer";
enum SeoField {
slug = "slug",
title = "seoTitle",
description = "seoDescription"
}
const DEFAULT_INPUT_MESSAGE =
"If empty, the preview shows what will be autogenerated.";
interface Error {
__typename: "ProductError" | "PageError";
field: string | null;
code: ProductErrorCode | PageErrorCode;
}
const useStyles = makeStyles( const useStyles = makeStyles(
theme => ({ theme => ({
addressBar: { addressBar: {
@ -66,8 +86,10 @@ interface SeoFormProps {
description?: string; description?: string;
descriptionPlaceholder: string; descriptionPlaceholder: string;
disabled?: boolean; disabled?: boolean;
errors?: ProductErrorFragment[] | PageErrorFragment[];
loading?: boolean; loading?: boolean;
helperText?: string; helperText?: string;
isCreating?: boolean;
title: string; title: string;
slug: string; slug: string;
slugPlaceholder?: string; slugPlaceholder?: string;
@ -81,7 +103,9 @@ const SeoForm: React.FC<SeoFormProps> = props => {
description, description,
descriptionPlaceholder, descriptionPlaceholder,
disabled, disabled,
errors,
helperText, helperText,
isCreating = false,
loading, loading,
title, title,
slug, slug,
@ -96,6 +120,43 @@ const SeoForm: React.FC<SeoFormProps> = props => {
const toggleExpansion = () => setExpansionStatus(!expanded); const toggleExpansion = () => setExpansionStatus(!expanded);
const shouldDisplayHelperText = helperText && !expanded; const shouldDisplayHelperText = helperText && !expanded;
const getFilteredErrors = () =>
(errors as Error[])?.filter(({ field }) =>
Object.keys(SeoField).includes(field)
) || [];
const getError = (fieldName: SeoField) =>
getFilteredErrors().find(({ field }) => fieldName === field);
const isError = (fieldName: SeoField) => !!getError(fieldName);
const getSlugHelperText = () => {
const error = isError(SeoField.slug);
if (isCreating && !error) {
return intl.formatMessage({
defaultMessage: DEFAULT_INPUT_MESSAGE
});
}
if (error) {
return getSlugErrorHelperText();
}
return "";
};
const getSlugErrorHelperText = () => {
const error = getError(SeoField.slug);
const { __typename: type } = error;
return type === "ProductError"
? getProductErrorMessage(error as ProductErrorFragment, intl)
: getPageErrorMessage(error as PageErrorFragment, intl);
};
// .replace(/[^\x00-\x7F]/g, "")
return ( return (
<Card> <Card>
<CardTitle <CardTitle
@ -122,7 +183,8 @@ const SeoForm: React.FC<SeoFormProps> = props => {
{expanded && ( {expanded && (
<div className={classes.container}> <div className={classes.container}>
<TextField <TextField
name="slug" error={isError(SeoField.slug)}
name={SeoField.slug}
label={ label={
<div className={classes.labelContainer}> <div className={classes.labelContainer}>
<div className={classes.label}> <div className={classes.label}>
@ -142,10 +204,7 @@ const SeoForm: React.FC<SeoFormProps> = props => {
)} )}
</div> </div>
} }
helperText={intl.formatMessage({ helperText={getSlugHelperText()}
defaultMessage:
"If empty, the preview shows what will be autogenerated."
})}
value={slug?.slice(0, 69)} value={slug?.slice(0, 69)}
disabled={loading || disabled} disabled={loading || disabled}
placeholder={slug || slugify(slugPlaceholder, { lower: true })} placeholder={slug || slugify(slugPlaceholder, { lower: true })}
@ -154,7 +213,8 @@ const SeoForm: React.FC<SeoFormProps> = props => {
/> />
<FormSpacer /> <FormSpacer />
<TextField <TextField
name="seoTitle" name={SeoField.title}
error={isError(SeoField.title)}
label={ label={
<div className={classes.labelContainer}> <div className={classes.labelContainer}>
<div className={classes.label}> <div className={classes.label}>
@ -175,8 +235,7 @@ const SeoForm: React.FC<SeoFormProps> = props => {
</div> </div>
} }
helperText={intl.formatMessage({ helperText={intl.formatMessage({
defaultMessage: defaultMessage: DEFAULT_INPUT_MESSAGE
"If empty, the preview shows what will be autogenerated."
})} })}
value={title?.slice(0, 69)} value={title?.slice(0, 69)}
disabled={loading || disabled} disabled={loading || disabled}
@ -186,7 +245,8 @@ const SeoForm: React.FC<SeoFormProps> = props => {
/> />
<FormSpacer /> <FormSpacer />
<TextField <TextField
name="seoDescription" error={isError(SeoField.description)}
name={SeoField.description}
label={ label={
<div className={classes.labelContainer}> <div className={classes.labelContainer}>
<div className={classes.label}> <div className={classes.label}>
@ -207,8 +267,7 @@ const SeoForm: React.FC<SeoFormProps> = props => {
</div> </div>
} }
helperText={intl.formatMessage({ helperText={intl.formatMessage({
defaultMessage: defaultMessage: DEFAULT_INPUT_MESSAGE
"If empty, the preview shows what will be autogenerated."
})} })}
value={description?.slice(0, 299)} value={description?.slice(0, 299)}
onChange={onChange} onChange={onChange}

View file

@ -38,6 +38,7 @@ export interface PageDetailsPageProps {
disabled: boolean; disabled: boolean;
errors: PageErrorFragment[]; errors: PageErrorFragment[];
page: PageDetails_page; page: PageDetails_page;
isCreating?: boolean;
saveButtonBarState: ConfirmButtonTransitionState; saveButtonBarState: ConfirmButtonTransitionState;
onBack: () => void; onBack: () => void;
onRemove: () => void; onRemove: () => void;
@ -55,6 +56,7 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const localizeDate = useDateLocalize(); const localizeDate = useDateLocalize();
const pageExists = page === null;
const initialForm: FormData = { const initialForm: FormData = {
content: maybe( content: maybe(
@ -77,7 +79,7 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
</AppHeader> </AppHeader>
<PageHeader <PageHeader
title={ title={
page === null pageExists
? intl.formatMessage({ ? intl.formatMessage({
defaultMessage: "Create Page", defaultMessage: "Create Page",
description: "page header" description: "page header"
@ -96,6 +98,8 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
/> />
<CardSpacer /> <CardSpacer />
<SeoForm <SeoForm
errors={errors}
isCreating={pageExists}
description={data.seoDescription} description={data.seoDescription}
disabled={disabled} disabled={disabled}
descriptionPlaceholder={maybe( descriptionPlaceholder={maybe(

View file

@ -306,6 +306,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
</> </>
)} )}
<SeoForm <SeoForm
isCreating={true}
helperText={intl.formatMessage({ helperText={intl.formatMessage({
defaultMessage: defaultMessage:
"Add search engine title and description to make this product easier to find" "Add search engine title and description to make this product easier to find"

View file

@ -352,6 +352,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
)} )}
<CardSpacer /> <CardSpacer />
<SeoForm <SeoForm
errors={errors}
title={data.seoTitle} title={data.seoTitle}
titlePlaceholder={data.name} titlePlaceholder={data.name}
description={data.seoDescription} description={data.seoDescription}