From 1b34f85f0e3188861c6804666f02b4495cab033c Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Mon, 14 Feb 2022 15:48:34 +0100 Subject: chore: improve comment form user experience --- src/components/Comment/Comment.tsx | 20 ++-- src/components/CommentForm/CommentForm.tsx | 150 +++++++++++++++++++---------- src/components/Notice/Notice.tsx | 3 +- src/components/Spinner/Spinner.tsx | 11 ++- src/i18n/en.json | 44 +++++++-- src/i18n/fr.json | 44 +++++++-- src/ts/types/app.ts | 2 + 7 files changed, 191 insertions(+), 83 deletions(-) diff --git a/src/components/Comment/Comment.tsx b/src/components/Comment/Comment.tsx index ab1dffc..a263771 100644 --- a/src/components/Comment/Comment.tsx +++ b/src/components/Comment/Comment.tsx @@ -24,7 +24,7 @@ const Comment = ({ const intl = useIntl(); const router = useRouter(); const locale = router.locale ? router.locale : settings.locales.defaultLocale; - const [isReply, setIsReply] = useState(false); + const [shouldOpenForm, setShouldOpenForm] = useState(false); const firstFieldRef = useRef(null); useEffect(() => { @@ -98,21 +98,25 @@ const Comment = ({ > {!isNested && (
-
)} - {isReply && ( + {shouldOpenForm && ( )} {comment.replies.length > 0 && ( diff --git a/src/components/CommentForm/CommentForm.tsx b/src/components/CommentForm/CommentForm.tsx index 0ea3276..762bb75 100644 --- a/src/components/CommentForm/CommentForm.tsx +++ b/src/components/CommentForm/CommentForm.tsx @@ -1,68 +1,107 @@ import { ButtonSubmit } from '@components/Buttons'; import { Form, FormItem, Input, TextArea } from '@components/Form'; import Notice from '@components/Notice/Notice'; +import Spinner from '@components/Spinner/Spinner'; import { createComment } from '@services/graphql/mutations'; +import { NoticeType } from '@ts/types/app'; import { ForwardedRef, forwardRef, useState } from 'react'; import { useIntl } from 'react-intl'; import styles from './CommentForm.module.scss'; const CommentForm = ( - { - articleId, - parentId = 0, - isReply = false, - }: { - articleId: number; - parentId?: number; - isReply?: boolean; - }, + { articleId, parentId = 0 }: { articleId: number; parentId?: number }, ref: ForwardedRef ) => { const intl = useIntl(); - const [name, setName] = useState(''); - const [email, setEmail] = useState(''); - const [website, setWebsite] = useState(''); - const [message, setMessage] = useState(''); - const [isSuccess, setIsSuccess] = useState(false); - const [isApproved, setIsApproved] = useState(false); + const [name, setName] = useState(''); + const [email, setEmail] = useState(''); + const [website, setWebsite] = useState(''); + const [comment, setComment] = useState(''); + const [isSubmitting, setIsSubmitting] = useState(false); + const [notice, setNotice] = useState(); + const [noticeType, setNoticeType] = useState('success'); const resetForm = () => { setName(''); setEmail(''); setWebsite(''); - setMessage(''); + setComment(''); + setIsSubmitting(false); }; - const submitHandler = async (e: SubmitEvent) => { - e.preventDefault(); + const isEmptyString = (value: string): boolean => value.trim() === ''; + const areRequiredFieldsSet = (): boolean => + !isEmptyString(name) && !isEmptyString(email) && !isEmptyString(comment); - if (name && email && message && articleId) { - const data = { - author: name, - authorEmail: email, - authorUrl: website, - content: message, - parent: parentId, - commentOn: articleId, - mutationId: 'createComment', - }; - const createdComment = await createComment(data); + const sendComment = async () => { + const data = { + author: name, + authorEmail: email, + authorUrl: website, + content: comment, + parent: parentId, + commentOn: articleId, + mutationId: 'createComment', + }; - if (createdComment.success) setIsSuccess(true); - if (isSuccess) { - resetForm(); - if (createdComment.comment?.approved) setIsApproved(true); + const createdComment = await createComment(data); - setTimeout(() => { - setIsSuccess(false); - setIsApproved(false); - }, 8000); + if (createdComment.success) { + resetForm(); + setNoticeType('success'); + if (createdComment.comment?.approved) { + setNotice( + intl.formatMessage({ + defaultMessage: 'Thanks for your comment!', + description: 'CommentForm: success notice', + }) + ); + } else { + setNotice( + intl.formatMessage({ + defaultMessage: + 'Thanks for your comment! It is now awaiting moderation.', + description: 'CommentForm: success notice but awaiting moderation', + }) + ); } + + setTimeout(() => { + setNotice(undefined); + }, 10000); + } else { + setNoticeType('error'); + setNotice( + intl.formatMessage({ + defaultMessage: + 'An unexpected error happened. Comment cannot be submitted.', + description: 'CommentForm: error notice', + }) + ); + } + }; + + const submitHandler = async (e: SubmitEvent) => { + e.preventDefault(); + setNotice(undefined); + setIsSubmitting(true); + + if (areRequiredFieldsSet()) { + sendComment(); } else { - setIsSuccess(false); + setIsSubmitting(false); + setNoticeType('warning'); + setNotice( + intl.formatMessage({ + defaultMessage: + 'Some required fields are empty. Comment cannot be submitted.', + description: 'CommentForm: missing required fields', + }) + ); } }; + const isReply = parentId !== 0; const wrapperClasses = `${styles.wrapper} ${ isReply ? styles['wrapper--reply'] : '' }`; @@ -72,7 +111,7 @@ const CommentForm = (

{intl.formatMessage({ defaultMessage: 'Leave a comment', - description: 'CommentForm: form title', + description: 'CommentForm: Form title', })}