From bd9c9ae7e2ae973969569dd434836de9f38b07d4 Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
Date: Tue, 7 Nov 2023 16:55:58 +0100
Subject: refactor(components): split Comment component into 3 components

* add ApprovedComment, PendingComment and ReplyCommentForm components
* let consumer handle reply form visibility
* move structured data into article page (each article already has the
comments data and already handle json ltd schema so I prefered to move
the schema in the final consumer instead of adding a script element
foreach comment)
---
 .../comment/approved-comment/approved-comment.tsx  | 177 +++++++++++++++++++++
 1 file changed, 177 insertions(+)
 create mode 100644 src/components/organisms/comment/approved-comment/approved-comment.tsx

(limited to 'src/components/organisms/comment/approved-comment/approved-comment.tsx')

diff --git a/src/components/organisms/comment/approved-comment/approved-comment.tsx b/src/components/organisms/comment/approved-comment/approved-comment.tsx
new file mode 100644
index 0000000..db5345b
--- /dev/null
+++ b/src/components/organisms/comment/approved-comment/approved-comment.tsx
@@ -0,0 +1,177 @@
+import NextImage from 'next/image';
+import { type ForwardRefRenderFunction, forwardRef, useCallback } from 'react';
+import { useIntl } from 'react-intl';
+import { Button, Link, Time } from '../../../atoms';
+import {
+  Card,
+  CardBody,
+  CardCover,
+  CardHeader,
+  CardMeta,
+  type CardProps,
+  CardTitle,
+  CardFooter,
+  CardActions,
+} from '../../../molecules';
+import styles from './approved-comment.module.scss';
+
+export type CommentAuthorAvatar = {
+  /**
+   * The alternative text for the avatar.
+   */
+  alt: string;
+  /**
+   * The avatar url.
+   */
+  src: string;
+};
+
+export type CommentAuthor = {
+  /**
+   * The author avatar.
+   */
+  avatar?: CommentAuthorAvatar;
+  /**
+   * The author name.
+   */
+  name: string;
+  /**
+   * The author website.
+   */
+  website?: string;
+};
+
+export type CommentReplyHandler = (id: number) => void | Promise<void>;
+
+export type ApprovedCommentProps = Omit<
+  CardProps<undefined>,
+  | 'children'
+  | 'content'
+  | 'cover'
+  | 'id'
+  | 'isCentered'
+  | 'linkTo'
+  | 'meta'
+  | 'variant'
+> & {
+  /**
+   * The author data.
+   */
+  author: CommentAuthor;
+  /**
+   * The comment.
+   */
+  content: string;
+  /**
+   * The comment id.
+   */
+  id: number;
+  /**
+   * A callback function to handle reply.
+   */
+  onReply?: CommentReplyHandler;
+  /**
+   * The publication date of the comment.
+   */
+  publicationDate: string;
+  /**
+   * Add a reply button to the comment by providing a label.
+   */
+  replyBtn?: string;
+};
+
+const ApprovedCommentWithRef: ForwardRefRenderFunction<
+  HTMLDivElement,
+  ApprovedCommentProps
+> = (
+  {
+    author,
+    className = '',
+    content,
+    id,
+    onReply,
+    publicationDate,
+    replyBtn,
+    ...props
+  },
+  ref
+) => {
+  const intl = useIntl();
+  const commentClass = `${className}`;
+  const commentId = `comment-${id}`;
+  const commentLink = `#${commentId}`;
+  const publicationDateLabel = intl.formatMessage({
+    defaultMessage: 'Published on:',
+    description: 'ApprovedComment: publication date label',
+    id: 'NzeU3V',
+  });
+
+  const handleReply = useCallback(() => {
+    if (onReply) onReply(id);
+  }, [id, onReply]);
+
+  return (
+    <Card
+      {...props}
+      className={commentClass}
+      cover={
+        author.avatar ? (
+          <CardCover hasBorders>
+            <NextImage
+              alt={author.avatar.alt}
+              height={96}
+              src={author.avatar.src}
+              width={96}
+            />
+          </CardCover>
+        ) : undefined
+      }
+      id={commentId}
+      ref={ref}
+      variant={2}
+    >
+      <CardHeader>
+        <CardTitle className={styles.author} isFake>
+          {author.website ? (
+            <Link href={author.website}>{author.name}</Link>
+          ) : (
+            author.name
+          )}
+        </CardTitle>
+        <CardMeta
+          hasInlinedItems
+          items={[
+            {
+              id: 'publication-date',
+              label: publicationDateLabel,
+              value: (
+                <Link href={commentLink}>
+                  <Time date={publicationDate} showTime />
+                </Link>
+              ),
+            },
+          ]}
+        />
+      </CardHeader>
+      <CardBody
+        className={styles.body}
+        dangerouslySetInnerHTML={{ __html: content }}
+      />
+      {replyBtn ? (
+        <CardFooter>
+          <CardActions>
+            <Button
+              // eslint-disable-next-line react/jsx-no-literals
+              kind="tertiary"
+              onClick={handleReply}
+            >
+              {replyBtn}
+            </Button>
+          </CardActions>
+        </CardFooter>
+      ) : null}
+    </Card>
+  );
+};
+
+export const ApprovedComment = forwardRef(ApprovedCommentWithRef);
-- 
cgit v1.2.3

