diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-04-22 17:27:01 +0200 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2022-04-22 17:34:04 +0200 |
| commit | cb6a54e54f2f013e06049b20388ca78e26201e16 (patch) | |
| tree | eac5f3a2200d9f5b776c999825a8e28098b46193 /src/components/organisms/layout | |
| parent | fd9831446ff87414da772b17327368cb291192e6 (diff) | |
chore: add a CommentsList component
Diffstat (limited to 'src/components/organisms/layout')
7 files changed, 291 insertions, 7 deletions
diff --git a/src/components/organisms/layout/comment.stories.tsx b/src/components/organisms/layout/comment.stories.tsx index 01d9ac6..b14621b 100644 --- a/src/components/organisms/layout/comment.stories.tsx +++ b/src/components/organisms/layout/comment.stories.tsx @@ -109,7 +109,6 @@ Comment.args = { content: 'Harum aut cumque iure fugit neque sequi cupiditate repudiandae laudantium. Ratione aut assumenda qui illum voluptas accusamus quis officiis exercitationem. Consectetur est harum eius perspiciatis officiis nihil. Aut corporis minima debitis adipisci possimus debitis et.', id: 2, - postId: 21, publication: '2021-04-03 23:04:24', saveComment: () => null, // @ts-ignore - Needed because of the placeholder image. diff --git a/src/components/organisms/layout/comment.test.tsx b/src/components/organisms/layout/comment.test.tsx index 942ed0f..9e537e5 100644 --- a/src/components/organisms/layout/comment.test.tsx +++ b/src/components/organisms/layout/comment.test.tsx @@ -11,13 +11,11 @@ const content = 'Harum aut cumque iure fugit neque sequi cupiditate repudiandae laudantium. Ratione aut assumenda qui illum voluptas accusamus quis officiis exercitationem. Consectetur est harum eius perspiciatis officiis nihil. Aut corporis minima debitis adipisci possimus debitis et.'; const publication = '2021-04-03 23:04:24'; const id = 5; -const postId = 31; const data = { author, content, id, - postId, publication, saveComment: () => null, }; diff --git a/src/components/organisms/layout/comment.tsx b/src/components/organisms/layout/comment.tsx index f4b822a..6d41c00 100644 --- a/src/components/organisms/layout/comment.tsx +++ b/src/components/organisms/layout/comment.tsx @@ -41,10 +41,6 @@ export type CommentProps = { */ id: number | string; /** - * The post id. - */ - postId: number | string; - /** * The comment date. */ publication: string; diff --git a/src/components/organisms/layout/comments-list.module.scss b/src/components/organisms/layout/comments-list.module.scss new file mode 100644 index 0000000..803a418 --- /dev/null +++ b/src/components/organisms/layout/comments-list.module.scss @@ -0,0 +1,16 @@ +@use "@styles/abstracts/placeholders"; + +.list { + @extend %reset-ordered-list; + + & & { + margin: var(--spacing-sm) 0; + padding-left: var(--spacing-sm); + } +} + +.item { + &:not(:last-child) { + margin-bottom: var(--spacing-sm); + } +} diff --git a/src/components/organisms/layout/comments-list.stories.tsx b/src/components/organisms/layout/comments-list.stories.tsx new file mode 100644 index 0000000..9edf368 --- /dev/null +++ b/src/components/organisms/layout/comments-list.stories.tsx @@ -0,0 +1,144 @@ +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import { IntlProvider } from 'react-intl'; +import CommentsListComponent, { Comment } from './comments-list'; + +/** + * CommentsList - Storybook Meta + */ +export default { + title: 'Organisms/Layout/CommentsList', + component: CommentsListComponent, + argTypes: { + comments: { + control: { + type: null, + }, + description: 'An array of comments.', + type: { + name: 'object', + required: true, + value: {}, + }, + }, + depth: { + control: { + type: 'number', + }, + description: 'The maximum depth. Use `0` to not display nested comments.', + type: { + name: 'number', + required: true, + }, + }, + saveComment: { + control: { + type: null, + }, + description: 'A callback function to save the comment form data.', + table: { + category: 'Events', + }, + type: { + name: 'function', + required: true, + }, + }, + }, + decorators: [ + (Story) => ( + <IntlProvider locale="en"> + <Story /> + </IntlProvider> + ), + ], +} as ComponentMeta<typeof CommentsListComponent>; + +const Template: ComponentStory<typeof CommentsListComponent> = (args) => ( + <CommentsListComponent {...args} /> +); + +const comments: Comment[] = [ + { + author: { + avatar: 'http://placeimg.com/640/480', + name: 'Author 1', + }, + content: + 'Voluptas ducimus inventore. Libero ut et doloribus. Earum nostrum ab. Aliquam rem dolores omnis voluptate. Sunt aut ut et.', + id: 1, + publication: '2021-04-03 18:04:11', + // @ts-ignore - Needed because of the placeholder image. + unoptimized: true, + }, + { + child: [ + { + author: { + avatar: 'http://placeimg.com/640/480', + name: 'Author 4', + }, + content: + 'Vel ullam in porro tempore. Maiores quos quia magnam beatae nemo libero velit numquam. Sapiente aliquid cumque. Velit neque in adipisci aut assumenda voluptates earum. Autem esse autem provident in tempore. Aut distinctio dolor qui repellat et et adipisci velit aspernatur.', + id: 4, + publication: '2021-04-03 23:04:24', + // @ts-ignore - Needed because of the placeholder image. + unoptimized: true, + }, + { + author: { + avatar: 'http://placeimg.com/640/480', + name: 'Author 1', + }, + content: + 'Sed non omnis. Quam porro est. Quae tempore quae. Exercitationem eos non velit voluptatem velit voluptas iusto. Sit debitis qui ipsam quo asperiores numquam veniam praesentium ut.', + id: 5, + publication: '2021-04-04 08:05:14', + // @ts-ignore - Needed because of the placeholder image. + unoptimized: true, + }, + ], + author: { + avatar: 'http://placeimg.com/640/480', + name: 'Author 2', + url: '#', + }, + content: + 'Sit sed error quasi voluptatem velit voluptas aut. Aut debitis eveniet. Praesentium dolores quia voluptate vero quis dicta quasi vel. Aut voluptas accusantium ut aut quidem consectetur itaque laboriosam occaecati.', + id: 2, + publication: '2021-04-03 23:30:20', + // @ts-ignore - Needed because of the placeholder image. + unoptimized: true, + }, + { + author: { + avatar: 'http://placeimg.com/640/480', + name: 'Author 3', + }, + content: + 'Natus consequatur maiores aperiam dolore eius nesciunt ut qui et. Ab ea nobis est. Eaque dolor corrupti id aut. Impedit architecto autem qui neque rerum ab dicta dignissimos voluptates.', + id: 3, + publication: '2021-09-13 13:24:54', + // @ts-ignore - Needed because of the placeholder image. + unoptimized: true, + }, +]; + +/** + * Layout Stories - Without child comments + */ +export const WithoutChildComments = Template.bind({}); +WithoutChildComments.args = { + comments, + depth: 0, + saveComment: () => null, +}; + +/** + * Layout Stories - With child comments + */ +export const WithChildComments = Template.bind({}); +WithChildComments.args = { + comments, + depth: 1, + saveComment: () => null, +}; diff --git a/src/components/organisms/layout/comments-list.test.tsx b/src/components/organisms/layout/comments-list.test.tsx new file mode 100644 index 0000000..542b1df --- /dev/null +++ b/src/components/organisms/layout/comments-list.test.tsx @@ -0,0 +1,66 @@ +import { render } from '@test-utils'; +import CommentsList, { type Comment } from './comments-list'; + +const comments: Comment[] = [ + { + author: { + avatar: 'http://placeimg.com/640/480', + name: 'Author 1', + }, + content: + 'Voluptas ducimus inventore. Libero ut et doloribus. Earum nostrum ab. Aliquam rem dolores omnis voluptate. Sunt aut ut et.', + id: 1, + publication: '2021-04-03 18:04:11', + }, + { + child: [ + { + author: { + avatar: 'http://placeimg.com/640/480', + name: 'Author 4', + }, + content: + 'Vel ullam in porro tempore. Maiores quos quia magnam beatae nemo libero velit numquam. Sapiente aliquid cumque. Velit neque in adipisci aut assumenda voluptates earum. Autem esse autem provident in tempore. Aut distinctio dolor qui repellat et et adipisci velit aspernatur.', + id: 4, + publication: '2021-04-03 23:04:24', + }, + { + author: { + avatar: 'http://placeimg.com/640/480', + name: 'Author 1', + }, + content: + 'Sed non omnis. Quam porro est. Quae tempore quae. Exercitationem eos non velit voluptatem velit voluptas iusto. Sit debitis qui ipsam quo asperiores numquam veniam praesentium ut.', + id: 5, + publication: '2021-04-04 08:05:14', + }, + ], + author: { + avatar: 'http://placeimg.com/640/480', + name: 'Author 2', + url: '#', + }, + content: + 'Sit sed error quasi voluptatem velit voluptas aut. Aut debitis eveniet. Praesentium dolores quia voluptate vero quis dicta quasi vel. Aut voluptas accusantium ut aut quidem consectetur itaque laboriosam occaecati.', + id: 2, + publication: '2021-04-03 23:30:20', + }, + { + author: { + avatar: 'http://placeimg.com/640/480', + name: 'Author 3', + }, + content: + 'Natus consequatur maiores aperiam dolore eius nesciunt ut qui et. Ab ea nobis est. Eaque dolor corrupti id aut. Impedit architecto autem qui neque rerum ab dicta dignissimos voluptates.', + id: 3, + publication: '2021-05-13 13:24:54', + }, +]; + +describe('CommentsList', () => { + it('renders a comments list', () => { + render( + <CommentsList comments={comments} depth={1} saveComment={() => null} /> + ); + }); +}); diff --git a/src/components/organisms/layout/comments-list.tsx b/src/components/organisms/layout/comments-list.tsx new file mode 100644 index 0000000..03f508e --- /dev/null +++ b/src/components/organisms/layout/comments-list.tsx @@ -0,0 +1,65 @@ +import SingleComment, { + type CommentProps, +} from '@components/organisms/layout/comment'; +import { FC } from 'react'; +import styles from './comments-list.module.scss'; + +export type Comment = Omit<CommentProps, 'canReply' | 'saveComment'> & { + child?: Comment[]; +}; + +export type CommentsListProps = { + /** + * An array of comments. + */ + comments: Comment[]; + /** + * The maximum depth. Use `0` to not display nested comments. + */ + depth: 0 | 1 | 2 | 3 | 4; + /** + * A callback function to save comment form data. + */ + saveComment: CommentProps['saveComment']; +}; + +/** + * CommentsList component + * + * Render a comments list. + */ +const CommentsList: FC<CommentsListProps> = ({ + comments, + depth, + saveComment, +}) => { + /** + * Get each comment wrapped in a list item. + * + * @param {Comment[]} commentsList - An array of comments. + * @returns {JSX.Element[]} The list items. + */ + const getItems = ( + commentsList: Comment[], + startLevel: number + ): JSX.Element[] => { + const isLastLevel = startLevel === depth; + + return commentsList.map(({ child, ...comment }) => ( + <li key={comment.id} className={styles.item}> + <SingleComment + saveComment={saveComment} + canReply={!isLastLevel} + {...comment} + /> + {child && !isLastLevel && ( + <ol className={styles.list}>{getItems(child, startLevel + 1)}</ol> + )} + </li> + )); + }; + + return <ol className={styles.list}>{getItems(comments, 0)}</ol>; +}; + +export default CommentsList; |
