From 0613656e57f2c64757d8af64e21aed75fcfc8e38 Mon Sep 17 00:00:00 2001 From: Luke Watts Date: Tue, 26 Dec 2023 20:08:04 +0000 Subject: [PATCH] feat(components): support nested comments --- .../src/CommentList/CommentList.stories.tsx | 34 +++++++++++++++--- .../src/CommentList/CommentList.test.tsx | 35 ++++++++++++++++--- .../src/CommentList/CommentList.tsx | 16 +++++++-- .../src/CommentList/createComments.tsx | 18 ---------- .../src/CommentList/createFakeComments.ts | 26 ++++++++++++++ 5 files changed, 101 insertions(+), 28 deletions(-) delete mode 100644 packages/components/src/CommentList/createComments.tsx create mode 100644 packages/components/src/CommentList/createFakeComments.ts diff --git a/packages/components/src/CommentList/CommentList.stories.tsx b/packages/components/src/CommentList/CommentList.stories.tsx index 3977165121..d71ae5f4bb 100644 --- a/packages/components/src/CommentList/CommentList.stories.tsx +++ b/packages/components/src/CommentList/CommentList.stories.tsx @@ -1,6 +1,6 @@ import type { StoryFn, Meta } from '@storybook/react' import { CommentList } from './CommentList' -import { createComments } from './createComments' +import { createFakeComments, fakeComment } from './createFakeComments' export default { title: 'Components/CommentList', @@ -9,7 +9,7 @@ export default { export const Default: StoryFn = () => ( Promise.resolve()} handleEditRequest={() => Promise.resolve()} @@ -19,7 +19,7 @@ export const Default: StoryFn = () => ( export const Expandable: StoryFn = () => ( Promise.resolve()} handleEditRequest={() => Promise.resolve()} @@ -27,7 +27,33 @@ export const Expandable: StoryFn = () => ( /> ) -const highlightedCommentList = createComments(20, { isEditable: false }) +export const WithNestedComments: StoryFn = () => { + // TODO: This is a temporary solution to get nested comments to pass type check + const comments: any = [ + fakeComment({ + replies: [ + fakeComment({ + replies: [fakeComment(), fakeComment(), fakeComment()], + }), + fakeComment(), + ], + }), + fakeComment(), + fakeComment(), + ] + + return ( + Promise.resolve()} + handleEditRequest={() => Promise.resolve()} + handleEdit={() => Promise.resolve()} + /> + ) +} + +const highlightedCommentList = createFakeComments(20, { isEditable: false }) export const Highlighted: StoryFn = () => ( { it('renders the correct number of comments initially', () => { - const mockComments: Comment[] = createComments(2) + const mockComments: Comment[] = createFakeComments(2) const screen = render( { }) it('loads more comments when show more button is clicked', () => { - const mockComments: Comment[] = createComments(20) + const mockComments: Comment[] = createFakeComments(20) const screen = render( { }) it('highlights the correct comment when highlightedCommentId is provided', () => { - const mockComments: Comment[] = createComments(10) + const mockComments: Comment[] = createFakeComments(10) const highComm = mockComments[1] const highlightedCommentId = highComm._id // Replace with an actual ID from mockComments highComm.text = 'Highlighted comment text' @@ -66,4 +66,31 @@ describe('CommentList', () => { 'border: 2px dashed black', ) }) + + it('renders nested comments correctly', () => { + const mockComments = [ + fakeComment({ + replies: [ + fakeComment({ + replies: [fakeComment(), fakeComment(), fakeComment()], + }), + fakeComment(), + ], + }), + fakeComment(), + fakeComment(), + ] + + const screen = render( + , + ) + + expect(screen.getAllByTestId('CommentList: item')).toHaveLength(8) + }) }) diff --git a/packages/components/src/CommentList/CommentList.tsx b/packages/components/src/CommentList/CommentList.tsx index 6487237d12..fd364057d3 100644 --- a/packages/components/src/CommentList/CommentList.tsx +++ b/packages/components/src/CommentList/CommentList.tsx @@ -4,8 +4,10 @@ import { Button, CommentItem } from '../' import type { CommentItemProps as Comment } from '../CommentItem/CommentItem' const MAX_COMMENTS = 5 +export type CommentWithReplies = Comment & { replies?: Comment[] } + export type CommentListProps = { - comments: Comment[] + comments: CommentWithReplies[] handleEdit: (_id: string, comment: string) => Promise handleEditRequest: () => Promise handleDelete: (_id: string) => Promise @@ -59,7 +61,7 @@ export const CommentList = ({ }} > {comments && - comments.slice(0, shownComments).map((comment: Comment) => ( + comments.slice(0, shownComments).map((comment) => ( + {comment.replies ? ( + + + + ) : null} ))} {comments && comments.length > shownComments && ( diff --git a/packages/components/src/CommentList/createComments.tsx b/packages/components/src/CommentList/createComments.tsx deleted file mode 100644 index 56cacbba3f..0000000000 --- a/packages/components/src/CommentList/createComments.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import type { CommentItemProps as Comment } from '../CommentItem/CommentItem' -import { faker } from '@faker-js/faker' - -export const createComments = ( - numberOfComments = 2, - commentOverloads = {}, -): Comment[] => - [...Array(numberOfComments).keys()].slice(0).map(() => ({ - _created: faker.date.past().toString(), - creatorCountry: faker.address.countryCode().toLowerCase(), - _creatorId: faker.internet.userName(), - _id: faker.database.mongodbObjectId(), - creatorName: faker.internet.userName(), - isUserVerified: faker.datatype.boolean(), - text: faker.lorem.text(), - isEditable: faker.datatype.boolean(), - ...commentOverloads, - })) diff --git a/packages/components/src/CommentList/createFakeComments.ts b/packages/components/src/CommentList/createFakeComments.ts new file mode 100644 index 0000000000..6667829279 --- /dev/null +++ b/packages/components/src/CommentList/createFakeComments.ts @@ -0,0 +1,26 @@ +import type { CommentWithReplies } from './CommentList' +import { faker } from '@faker-js/faker' + +export const fakeComment = ( + commentOverloads: Partial = {}, +) => ({ + _created: faker.date.past().toString(), + creatorCountry: faker.address.countryCode().toLowerCase(), + _creatorId: faker.internet.userName(), + _id: faker.database.mongodbObjectId(), + creatorName: faker.internet.userName(), + isUserVerified: faker.datatype.boolean(), + text: faker.lorem.text(), + isEditable: faker.datatype.boolean(), + ...commentOverloads, +}) + +export const createFakeComments = ( + numberOfComments = 2, + commentOverloads = {}, +): CommentWithReplies[] => + [...Array(numberOfComments).keys()].slice(0).map(() => + fakeComment({ + ...commentOverloads, + }), + )