diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-05-24 19:35:12 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-05-24 19:35:12 +0200 |
| commit | c85ab5ad43ccf52881ee224672c41ec30021cf48 (patch) | |
| tree | 8058808d9bfca19383f120c46b34d99ff2f89f63 /src/components/organisms/forms/comment-form.tsx | |
| parent | 52404177c07a2aab7fc894362fb3060dff2431a0 (diff) | |
| parent | 11b9de44a4b2f305a6a484187805e429b2767118 (diff) | |
refactor: use storybook and atomic design (#16)
BREAKING CHANGE: rewrite most of the Typescript types, so the content format (the meta in particular) needs to be updated.
Diffstat (limited to 'src/components/organisms/forms/comment-form.tsx')
| -rw-r--r-- | src/components/organisms/forms/comment-form.tsx | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/src/components/organisms/forms/comment-form.tsx b/src/components/organisms/forms/comment-form.tsx new file mode 100644 index 0000000..b2c725f --- /dev/null +++ b/src/components/organisms/forms/comment-form.tsx @@ -0,0 +1,193 @@ +import Button from '@components/atoms/buttons/button'; +import Form, { type FormProps } from '@components/atoms/forms/form'; +import Heading, { + type HeadingProps, + type HeadingLevel, +} from '@components/atoms/headings/heading'; +import Spinner from '@components/atoms/loaders/spinner'; +import LabelledField from '@components/molecules/forms/labelled-field'; +import { FC, ReactNode, useState } from 'react'; +import { useIntl } from 'react-intl'; +import styles from './comment-form.module.scss'; + +export type CommentFormData = { + comment: string; + email: string; + name: string; + parentId?: number; + website?: string; +}; + +export type CommentFormProps = Pick<FormProps, 'className'> & { + /** + * Pass a component to print a success/error message. + */ + Notice?: ReactNode; + /** + * The comment parent id. + */ + parentId?: number; + /** + * A callback function to save comment. It takes a function as parameter to + * reset the form. + */ + saveComment: (data: CommentFormData, reset: () => void) => Promise<void>; + /** + * The form title. + */ + title?: string; + /** + * The form title alignment. Default: left. + */ + titleAlignment?: HeadingProps['alignment']; + /** + * The title level. Default: 2. + */ + titleLevel?: HeadingLevel; +}; + +const CommentForm: FC<CommentFormProps> = ({ + Notice, + parentId, + saveComment, + title, + titleAlignment, + titleLevel = 2, + ...props +}) => { + const intl = useIntl(); + const [name, setName] = useState<string>(''); + const [email, setEmail] = useState<string>(''); + const [website, setWebsite] = useState<string>(''); + const [comment, setComment] = useState<string>(''); + const [isSubmitting, setIsSubmitting] = useState<boolean>(false); + + /** + * Reset all the form fields. + */ + const resetForm = () => { + setName(''); + setEmail(''); + setWebsite(''); + setComment(''); + setIsSubmitting(false); + }; + + const nameLabel = intl.formatMessage({ + defaultMessage: 'Name:', + description: 'CommentForm: name label', + id: 'ZIrTee', + }); + + const emailLabel = intl.formatMessage({ + defaultMessage: 'Email:', + description: 'CommentForm: email label', + id: 'Bh7z5v', + }); + + const websiteLabel = intl.formatMessage({ + defaultMessage: 'Website:', + description: 'CommentForm: website label', + id: 'u41qSk', + }); + + const commentLabel = intl.formatMessage({ + defaultMessage: 'Comment:', + description: 'CommentForm: comment label', + id: 'A8hGaK', + }); + + const formTitle = intl.formatMessage({ + defaultMessage: 'Comment form', + description: 'CommentForm: aria label', + id: 'dz2kDV', + }); + + const formAriaLabel = title ? undefined : formTitle; + const formId = 'comment-form-title'; + const formLabelledBy = title ? formId : undefined; + + /** + * Handle form submit. + */ + const submitHandler = () => { + setIsSubmitting(true); + saveComment({ comment, email, name, parentId, website }, resetForm).then( + () => setIsSubmitting(false) + ); + }; + + return ( + <Form + onSubmit={submitHandler} + aria-label={formAriaLabel} + aria-labelledby={formLabelledBy} + {...props} + > + {title && ( + <Heading id={formId} level={titleLevel} alignment={titleAlignment}> + {title} + </Heading> + )} + <LabelledField + type="text" + id="commenter-name" + name="commenter-name" + label={nameLabel} + required={true} + value={name} + setValue={setName} + className={styles.field} + /> + <LabelledField + type="email" + id="commenter-email" + name="commenter-email" + label={emailLabel} + required={true} + value={email} + setValue={setEmail} + className={styles.field} + /> + <LabelledField + type="text" + id="commenter-website" + name="commenter-website" + label={websiteLabel} + required={false} + value={website} + setValue={setWebsite} + className={styles.field} + /> + <LabelledField + type="textarea" + id="commenter-comment" + name="commenter-comment" + label={commentLabel} + required={true} + value={comment} + setValue={setComment} + className={styles.field} + /> + <Button type="submit" kind="primary" className={styles.button}> + {intl.formatMessage({ + defaultMessage: 'Publish', + description: 'CommentForm: submit button', + id: 'OL0Yzx', + })} + </Button> + {isSubmitting && ( + <Spinner + message={intl.formatMessage({ + defaultMessage: 'Submitting...', + description: 'CommentForm: spinner message on submit', + id: 'IY5ew6', + })} + /> + )} + {Notice} + </Form> + ); +}; + +export default CommentForm; |
