diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-04-21 18:36:45 +0200 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2022-04-21 18:36:45 +0200 |
| commit | fd9831446ff87414da772b17327368cb291192e6 (patch) | |
| tree | c0d330e594c855aaeb041aec8e84933e04fd4363 /src/components/organisms/layout/comment.tsx | |
| parent | 94a8e31f25ed3d92f9eb808e3264bd4ac8c039c7 (diff) | |
chore: add a Comment component
Diffstat (limited to 'src/components/organisms/layout/comment.tsx')
| -rw-r--r-- | src/components/organisms/layout/comment.tsx | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/src/components/organisms/layout/comment.tsx b/src/components/organisms/layout/comment.tsx new file mode 100644 index 0000000..f4b822a --- /dev/null +++ b/src/components/organisms/layout/comment.tsx @@ -0,0 +1,175 @@ +import Button from '@components/atoms/buttons/button'; +import Link from '@components/atoms/links/link'; +import DescriptionList from '@components/atoms/lists/description-list'; +import { getFormattedDate, getFormattedTime } from '@utils/helpers/format'; +import Image from 'next/image'; +import { FC, useState } from 'react'; +import { useIntl } from 'react-intl'; +import CommentForm, { type CommentFormProps } from '../forms/comment-form'; +import styles from './comment.module.scss'; + +export type CommentAuthor = { + /** + * The author avatar. + */ + avatar: string; + /** + * The author name. + */ + name: string; + /** + * The author website. + */ + url?: string; +}; + +export type CommentProps = { + /** + * The comment author data. + */ + author: CommentAuthor; + /** + * Enable or disable the reply button. Default: true. + */ + canReply?: boolean; + /** + * The comment body. + */ + content: string; + /** + * The comment id. + */ + id: number | string; + /** + * The post id. + */ + postId: number | string; + /** + * The comment date. + */ + publication: string; + /** + * A callback function to save comment form data. + */ + saveComment: CommentFormProps['saveComment']; +}; + +/** + * Comment component + * + * Render a single comment. + */ +const Comment: FC<CommentProps> = ({ + author, + canReply = true, + content, + id, + publication, + saveComment, + ...props +}) => { + const intl = useIntl(); + const [isReplying, setIsReplying] = useState<boolean>(false); + const commentDate = getFormattedDate(publication); + const commentTime = getFormattedTime(publication); + const commentDateTime = new Date(publication).toISOString(); + + const avatarAltText = intl.formatMessage( + { + defaultMessage: '{author} avatar', + description: 'Comment: avatar alternative text', + id: 'T/hUiO', + }, + { author: author.name } + ); + const buttonLabel = isReplying + ? intl.formatMessage({ + defaultMessage: 'Cancel reply', + description: 'Comment: cancel reply button', + id: 'LCorTC', + }) + : intl.formatMessage({ + defaultMessage: 'Reply', + description: 'Comment: reply button', + id: 'hzHuCc', + }); + const dateLabel = intl.formatMessage({ + defaultMessage: 'Published on:', + description: 'Comment: publication date label', + id: 'soj7do', + }); + const dateValue = intl.formatMessage( + { + defaultMessage: '{date} at {time}', + description: 'Comment: publication date and time', + id: 'Ld6yMP', + }, + { + date: commentDate, + time: commentTime, + } + ); + const formTitle = intl.formatMessage({ + defaultMessage: 'Leave a reply', + description: 'Comment: comment form title', + id: '2fD5CI', + }); + + const dateLink = ( + <Link href={`#comment-${id}`}> + <time dateTime={commentDateTime}></time> + {dateValue} + </Link> + ); + + return ( + <> + <article + id={`comment-${id}`} + className={`${styles.wrapper} ${styles['wrapper--comment']}`} + > + <header className={styles.header}> + <div className={styles.avatar}> + <Image + src={author.avatar} + alt={avatarAltText} + layout="fill" + objectFit="cover" + {...props} + /> + </div> + {author.url ? ( + <Link href={author.url} className={styles.author}> + {author.name} + </Link> + ) : ( + <span className={styles.author}>{author.name}</span> + )} + </header> + <DescriptionList + items={[{ id: 'comment-date', term: dateLabel, value: [dateLink] }]} + layout="inline" + className={styles.date} + groupClassName={styles.meta} + /> + <div className={styles.body}>{content}</div> + <footer className={styles.footer}> + {canReply && ( + <Button kind="tertiary" onClick={() => setIsReplying(!isReplying)}> + {buttonLabel} + </Button> + )} + </footer> + </article> + {isReplying && ( + <CommentForm + saveComment={saveComment} + title={formTitle} + className={`${styles.wrapper} ${styles['wrapper--form']}`} + /> + )} + </> + ); +}; + +export default Comment; |
