Skip to content

Commit

Permalink
Merge pull request #3112 from ONEARMY/feat/comment-list-with-nested-r…
Browse files Browse the repository at this point in the history
…eplies

feat(components): support nested comments
  • Loading branch information
thisislawatts authored Jan 3, 2024
2 parents 73e5a2f + 7fadd1b commit 633eda7
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 28 deletions.
29 changes: 25 additions & 4 deletions packages/components/src/CommentList/CommentList.stories.tsx
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -9,7 +9,7 @@ export default {

export const Default: StoryFn<typeof CommentList> = () => (
<CommentList
comments={createComments(2)}
comments={createFakeComments(2)}
articleTitle="Test article"
handleDelete={() => Promise.resolve()}
handleEditRequest={() => Promise.resolve()}
Expand All @@ -19,15 +19,36 @@ export const Default: StoryFn<typeof CommentList> = () => (

export const Expandable: StoryFn<typeof CommentList> = () => (
<CommentList
comments={createComments(20)}
comments={createFakeComments(20)}
articleTitle="Test article"
handleDelete={() => Promise.resolve()}
handleEditRequest={() => Promise.resolve()}
handleEdit={() => Promise.resolve()}
/>
)

const highlightedCommentList = createComments(20, { isEditable: false })
export const WithNestedComments: StoryFn<typeof CommentList> = () => {
// TODO: This is a temporary solution to get nested comments to pass type check
const comments: any = [
fakeComment({
replies: [fakeComment(), fakeComment()],
}),
fakeComment(),
fakeComment(),
]

return (
<CommentList
comments={comments}
articleTitle="Test article"
handleDelete={() => Promise.resolve()}
handleEditRequest={() => Promise.resolve()}
handleEdit={() => Promise.resolve()}
/>
)
}

const highlightedCommentList = createFakeComments(20, { isEditable: false })

export const Highlighted: StoryFn<typeof CommentList> = () => (
<CommentList
Expand Down
30 changes: 26 additions & 4 deletions packages/components/src/CommentList/CommentList.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { vi } from 'vitest'
import { render } from '../tests/utils'
import { CommentList } from './CommentList'
import type { CommentItemProps as Comment } from '../CommentItem/CommentItem'
import { createComments } from './createComments'
import { createFakeComments, fakeComment } from './createFakeComments'

const mockHandleEdit = vi.fn()
const mockHandleEditRequest = vi.fn()
Expand All @@ -12,7 +12,7 @@ const mockTrackEvent = vi.fn()

describe('CommentList', () => {
it('renders the correct number of comments initially', () => {
const mockComments: Comment[] = createComments(2)
const mockComments: Comment[] = createFakeComments(2)
const screen = render(
<CommentList
comments={mockComments}
Expand All @@ -28,7 +28,7 @@ describe('CommentList', () => {
})

it('loads more comments when show more button is clicked', () => {
const mockComments: Comment[] = createComments(20)
const mockComments: Comment[] = createFakeComments(20)
const screen = render(
<CommentList
comments={mockComments}
Expand All @@ -48,7 +48,7 @@ describe('CommentList', () => {
})

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'
Expand All @@ -66,4 +66,26 @@ describe('CommentList', () => {
'border: 2px dashed black',
)
})

it('renders nested comments correctly', () => {
const mockComments = [
fakeComment({
replies: [fakeComment(), fakeComment()],
}),
fakeComment(),
fakeComment(),
]

const screen = render(
<CommentList
comments={mockComments}
handleEdit={mockHandleEdit}
handleEditRequest={mockHandleEditRequest}
handleDelete={mockHandleDelete}
trackEvent={mockTrackEvent}
/>,
)

expect(screen.getAllByTestId('CommentList: item')).toHaveLength(5)
})
})
16 changes: 14 additions & 2 deletions packages/components/src/CommentList/CommentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>
handleEditRequest: () => Promise<void>
handleDelete: (_id: string) => Promise<void>
Expand Down Expand Up @@ -59,7 +61,7 @@ export const CommentList = ({
}}
>
{comments &&
comments.slice(0, shownComments).map((comment: Comment) => (
comments.slice(0, shownComments).map((comment) => (
<Box
key={comment._id}
data-testid="CommentList: item"
Expand All @@ -81,6 +83,16 @@ export const CommentList = ({
handleDelete={handleDelete}
handleEdit={handleEdit}
/>
{comment.replies ? (
<Box sx={{ pt: 4, pl: 4 }}>
<CommentList
comments={comment.replies}
handleEditRequest={handleEditRequest}
handleDelete={handleDelete}
handleEdit={handleEdit}
/>
</Box>
) : null}
</Box>
))}
{comments && comments.length > shownComments && (
Expand Down
18 changes: 0 additions & 18 deletions packages/components/src/CommentList/createComments.tsx

This file was deleted.

26 changes: 26 additions & 0 deletions packages/components/src/CommentList/createFakeComments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { CommentWithReplies } from './CommentList'
import { faker } from '@faker-js/faker'

export const fakeComment = (
commentOverloads: Partial<CommentWithReplies> = {},
) => ({
_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,
}),
)

0 comments on commit 633eda7

Please sign in to comment.