Skip to content

Commit

Permalink
feat: updated redux structure using updated comments api (#670)
Browse files Browse the repository at this point in the history
* feat: updated redux structure and commentsview component

* test: fixed test cases

* fix: fixed lint error
  • Loading branch information
ayesha-waris authored Mar 25, 2024
1 parent 3aacdda commit 80073e3
Show file tree
Hide file tree
Showing 13 changed files with 149 additions and 289 deletions.
14 changes: 2 additions & 12 deletions src/discussions/post-comments/PostCommentsView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import { useLocation, useNavigate } from 'react-router-dom';
import { useIntl } from '@edx/frontend-platform/i18n';

import Spinner from '../../components/Spinner';
import {
EndorsementStatus, PostsPages, ThreadType,
} from '../../data/constants';
import { PostsPages } from '../../data/constants';
import useDispatchWithState from '../../data/hooks';
import DiscussionContext from '../common/context';
import { useIsOnDesktop } from '../data/hooks';
Expand Down Expand Up @@ -127,15 +125,7 @@ const PostCommentsView = () => {
</div>
<Suspense fallback={(<Spinner />)}>
{!!commentsCount && <CommentsSort />}
{type === ThreadType.DISCUSSION && (
<CommentsView endorsed={EndorsementStatus.DISCUSSION} />
)}
{type === ThreadType.QUESTION && (
<>
<CommentsView endorsed={EndorsementStatus.ENDORSED} />
<CommentsView endorsed={EndorsementStatus.UNENDORSED} />
</>
)}
<CommentsView threadType={type} />
</Suspense>
</PostCommentsContext.Provider>
);
Expand Down
36 changes: 21 additions & 15 deletions src/discussions/post-comments/PostCommentsView.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { camelCaseObject, initializeMockApp } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { AppProvider } from '@edx/frontend-platform/react';

import { getApiBaseUrl } from '../../data/constants';
import { getApiBaseUrl, ThreadType } from '../../data/constants';
import { initializeStore } from '../../store';
import executeThunk from '../../test-utils';
import { getCohortsApiUrl } from '../cohorts/data/api';
Expand Down Expand Up @@ -50,10 +50,10 @@ let testLocation;
let container;
let unmount;

async function mockAxiosReturnPagedComments(threadId, endorsed = false, page = 1, count = 2) {
async function mockAxiosReturnPagedComments(threadId, threadType = ThreadType.DISCUSSION, page = 1, count = 2) {
axiosMock.onGet(commentsApiUrl).reply(200, Factory.build('commentsResult', { can_delete: true }, {
threadId,
endorsed,
threadType,
pageSize: 1,
count,
childCount: page === 1 ? 2 : 0,
Expand All @@ -76,6 +76,7 @@ async function mockAxiosReturnPagedCommentsResponses() {
Factory.build('commentsResult', null, {
threadId: discussionPostId,
parentId,
endorsed: false,
page,
pageSize: 1,
count: 2,
Expand Down Expand Up @@ -201,6 +202,7 @@ describe('ThreadView', () => {
id: commentId,
rendered_body: rawBody,
raw_body: rawBody,
endorsed: false,
})];
});
axiosMock.onPost(commentsApiUrl).reply(({ data }) => {
Expand All @@ -209,6 +211,7 @@ describe('ThreadView', () => {
rendered_body: rawBody,
raw_body: rawBody,
thread_id: threadId,
endorsed: false,
})];
});
axiosMock.onGet(`${courseConfigApiUrl}${courseId}/`).reply(200, { isPostingEnabled: true });
Expand All @@ -230,9 +233,9 @@ describe('ThreadView', () => {
expect(JSON.parse(axiosMock.history.patch[axiosMock.history.patch.length - 1].data)).toMatchObject(data);
}

it('should not allow posting a comment on a closed post', async () => {
it('should not allow posting a reply on a closed post', async () => {
axiosMock.reset();
await mockAxiosReturnPagedComments(closedPostId, true);
await mockAxiosReturnPagedComments(closedPostId, ThreadType.QUESTION);
await waitFor(() => renderComponent(closedPostId, true));
const comments = await waitFor(() => screen.findAllByTestId('comment-comment-4'));
const hoverCard = within(comments[0]).getByTestId('hover-card-comment-4');
Expand Down Expand Up @@ -288,7 +291,7 @@ describe('ThreadView', () => {
expect(screen.queryByTestId('tinymce-editor')).not.toBeInTheDocument();
});

it('should allow posting a response', async () => {
it('should allow posting a comment', async () => {
await waitFor(() => renderComponent(discussionPostId));

const post = await screen.findByTestId('post-thread-1');
Expand Down Expand Up @@ -540,8 +543,11 @@ describe('ThreadView', () => {
// Wait for the content to load
const comment = await waitFor(() => screen.findByTestId('comment-comment-1'));
const hoverCard = within(comment).getByTestId('hover-card-comment-1');

const endorseButton = await waitFor(() => within(hoverCard).getByRole('button', { name: /Endorse/i }));

await act(async () => {
fireEvent.click(within(hoverCard).getByRole('button', { name: /Endorse/i }));
fireEvent.click(endorseButton);
});
expect(axiosMock.history.patch).toHaveLength(2);
expect(JSON.parse(axiosMock.history.patch[1].data)).toMatchObject({ endorsed: true });
Expand Down Expand Up @@ -591,7 +597,7 @@ describe('ThreadView', () => {

it('pressing load more button will load next page of comments', async () => {
await waitFor(() => renderComponent(discussionPostId));
await mockAxiosReturnPagedComments(discussionPostId, false, 2);
await mockAxiosReturnPagedComments(discussionPostId, ThreadType.DISCUSSION, 2);

const loadMoreButton = await findLoadMoreCommentsButton();
await act(async () => {
Expand All @@ -604,7 +610,7 @@ describe('ThreadView', () => {

it('newly loaded comments are appended to the old ones', async () => {
await waitFor(() => renderComponent(discussionPostId));
await mockAxiosReturnPagedComments(discussionPostId, false, 2);
await mockAxiosReturnPagedComments(discussionPostId, ThreadType.DISCUSSION, 2);

const loadMoreButton = await findLoadMoreCommentsButton();
await act(async () => {
Expand All @@ -622,7 +628,7 @@ describe('ThreadView', () => {
const findLoadMoreCommentsButtons = () => screen.findByTestId('load-more-comments');

it('initially loads only the first page', async () => {
await mockAxiosReturnPagedComments(questionPostId);
await mockAxiosReturnPagedComments(questionPostId, ThreadType.QUESTION);
act(() => renderComponent(questionPostId));

expect(await screen.findByTestId('comment-comment-4'))
Expand All @@ -633,7 +639,7 @@ describe('ThreadView', () => {
});

it('pressing load more button will load next page of comments', async () => {
await mockAxiosReturnPagedComments(questionPostId);
await mockAxiosReturnPagedComments(questionPostId, ThreadType.QUESTION);
await waitFor(() => renderComponent(questionPostId));

const loadMoreButton = await findLoadMoreCommentsButtons();
Expand All @@ -644,7 +650,7 @@ describe('ThreadView', () => {
expect(await screen.queryByTestId('comment-comment-5'))
.not
.toBeInTheDocument();
await mockAxiosReturnPagedComments(questionPostId, false, 2, 1);
await mockAxiosReturnPagedComments(questionPostId, ThreadType.QUESTION, 2, 1);
await act(async () => {
fireEvent.click(loadMoreButton);
});
Expand All @@ -664,7 +670,7 @@ describe('ThreadView', () => {
expect(screen.queryByTestId('reply-comment-3')).not.toBeInTheDocument();
});

it('pressing load more button will load next page of responses', async () => {
it('pressing load more button will load next page of replies', async () => {
await waitFor(() => renderComponent(discussionPostId));

const loadMoreButton = await findLoadMoreCommentsResponsesButton();
Expand All @@ -674,7 +680,7 @@ describe('ThreadView', () => {
await screen.findByTestId('reply-comment-3');
});

it('newly loaded responses are appended to the old ones', async () => {
it('newly loaded replies are appended to the old ones', async () => {
await waitFor(() => renderComponent(discussionPostId));

const loadMoreButton = await findLoadMoreCommentsResponsesButton();
Expand All @@ -687,7 +693,7 @@ describe('ThreadView', () => {
expect(screen.queryByTestId('reply-comment-2')).toBeInTheDocument();
});

it('load more button is hidden when no more responses pages to load', async () => {
it('load more button is hidden when no more replies pages to load', async () => {
await waitFor(() => renderComponent(discussionPostId));

const loadMoreButton = await findLoadMoreCommentsResponsesButton();
Expand Down
110 changes: 52 additions & 58 deletions src/discussions/post-comments/comments/CommentsView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { Button, Spinner } from '@openedx/paragon';

import { useIntl } from '@edx/frontend-platform/i18n';

import { EndorsementStatus } from '../../../data/constants';
import { ThreadType } from '../../../data/constants';
import { useUserPostingEnabled } from '../../data/hooks';
import { isLastElementOfList } from '../../utils';
import { usePostComments } from '../data/hooks';
import messages from '../messages';
import PostCommentsContext from '../postCommentsContext';
import { Comment, ResponseEditor } from './comment';

const CommentsView = ({ endorsed }) => {
const CommentsView = ({ threadType }) => {
const intl = useIntl();
const [addingResponse, setAddingResponse] = useState(false);
const { isClosed } = useContext(PostCommentsContext);
Expand All @@ -25,7 +25,7 @@ const CommentsView = ({ endorsed }) => {
hasMorePages,
isLoading,
handleLoadMoreResponses,
} = usePostComments(endorsed);
} = usePostComments(threadType);

const handleAddResponse = useCallback(() => {
setAddingResponse(true);
Expand All @@ -45,7 +45,7 @@ const CommentsView = ({ endorsed }) => {
</div>
), []);

const handleComments = useCallback((postCommentsIds, showLoadMoreResponses = false) => (
const handleComments = useCallback((postCommentsIds) => (
<div className="mx-4" role="list">
{postCommentsIds.map((commentId) => (
<Comment
Expand All @@ -54,72 +54,66 @@ const CommentsView = ({ endorsed }) => {
marginBottom={isLastElementOfList(postCommentsIds, commentId)}
/>
))}
{hasMorePages && !isLoading && !showLoadMoreResponses && (
<Button
onClick={handleLoadMoreResponses}
variant="link"
block="true"
className="px-4 mt-3 border-0 line-height-24 py-0 mb-2 font-style font-weight-500 font-size-14"
data-testid="load-more-comments"
>
{intl.formatMessage(messages.loadMoreResponses)}
</Button>
)}
{isLoading && !showLoadMoreResponses && (
<div className="mb-2 mt-3 d-flex justify-content-center">
<Spinner animation="border" variant="primary" className="spinner-dimensions" />
</div>
)}
</div>
), [hasMorePages, isLoading, handleLoadMoreResponses]);

return (
((hasMorePages && isLoading) || !isLoading) && (
<>
{endorsedCommentsIds.length > 0 && (
<>
{endorsedCommentsIds.length > 0 && (
<>
{handleDefinition(messages.endorsedResponseCount, endorsedCommentsIds.length)}
{endorsed === EndorsementStatus.DISCUSSION
? handleComments(endorsedCommentsIds, true)
: handleComments(endorsedCommentsIds, false)}
</>
)}
{endorsed !== EndorsementStatus.ENDORSED && (
<>
{handleDefinition(messages.responseCount, unEndorsedCommentsIds.length)}
{unEndorsedCommentsIds.length === 0 && <br />}
{handleComments(unEndorsedCommentsIds, false)}
{(isUserPrivilegedInPostingRestriction && !!unEndorsedCommentsIds.length && !isClosed) && (
<div className="mx-4">
{!addingResponse && (
<Button
variant="plain"
block="true"
className="card mb-4 px-0 border-0 py-10px mt-2 font-style font-weight-500
line-height-24 font-size-14 text-primary-500"
onClick={handleAddResponse}
data-testid="add-response"
>
{intl.formatMessage(messages.addResponse)}
</Button>
)}
<ResponseEditor
addWrappingDiv
addingResponse={addingResponse}
handleCloseEditor={handleCloseResponseEditor}
/>
</div>
)}
</>
)}
{handleDefinition(messages.endorsedResponseCount, endorsedCommentsIds.length)}
{handleComments(endorsedCommentsIds)}
</>
)}
{handleDefinition(messages.responseCount, unEndorsedCommentsIds.length)}
{unEndorsedCommentsIds.length > 0 && handleComments(unEndorsedCommentsIds)}
{hasMorePages && !isLoading && (!!unEndorsedCommentsIds.length || !!endorsedCommentsIds.length) && (
<Button
onClick={handleLoadMoreResponses}
variant="link"
block="true"
className="px-4 mt-3 border-0 line-height-24 py-0 mb-2 font-style font-weight-500 font-size-14"
data-testid="load-more-comments"
>
{intl.formatMessage(messages.loadMoreResponses)}
</Button>
)}
{isLoading && (
<div className="mb-2 mt-3 d-flex justify-content-center">
<Spinner animation="border" variant="primary" className="spinner-dimensions" />
</div>
)}
{(isUserPrivilegedInPostingRestriction && (!!unEndorsedCommentsIds.length || !!endorsedCommentsIds.length)
&& !isClosed) && (
<div className="mx-4">
{!addingResponse && (
<Button
variant="plain"
block="true"
className="card mb-4 px-0 border-0 py-10px mt-2 font-style font-weight-500
line-height-24 font-size-14 text-primary-500"
onClick={handleAddResponse}
data-testid="add-response"
>
{intl.formatMessage(messages.addResponse)}
</Button>
)}
<ResponseEditor
addWrappingDiv
addingResponse={addingResponse}
handleCloseEditor={handleCloseResponseEditor}
/>
</div>
)}
</>
)
);
};

CommentsView.propTypes = {
endorsed: PropTypes.oneOf([
EndorsementStatus.ENDORSED, EndorsementStatus.UNENDORSED, EndorsementStatus.DISCUSSION,
threadType: PropTypes.oneOf([
ThreadType.DISCUSSION, ThreadType.QUESTION,
]).isRequired,
};

Expand Down
2 changes: 1 addition & 1 deletion src/discussions/post-comments/comments/comment/Comment.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const Comment = ({
}, []);

const handleCommentEndorse = useCallback(async () => {
await dispatch(editComment(id, { endorsed: !endorsed }, ContentActions.ENDORSE));
await dispatch(editComment(id, { endorsed: !endorsed }));
await dispatch(fetchThread(threadId, courseId));
}, [id, endorsed, threadId]);

Expand Down
2 changes: 1 addition & 1 deletion src/discussions/post-comments/comments/comment/Reply.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const Reply = ({ responseId }) => {
}, []);

const handleReplyEndorse = useCallback(() => {
dispatch(editComment(id, { endorsed: !endorsed }, ContentActions.ENDORSE));
dispatch(editComment(id, { endorsed: !endorsed }));
}, [endorsed, id]);

const handleAbusedFlag = useCallback(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Factory.define('comment')
.sequence('rendered_body', ['endorsed'], (idx, endorsed) => `Some contents for <b>${endorsed ? 'endorsed ' : 'unendorsed '}comment number ${idx}</b>.`)
.attr('thread_id', null, 'test-thread')
.option('endorsedBy', null, null)
.attr('endorsed', ['endorsedBy'], (endorsedBy) => !!endorsedBy)
.attr('endorsed', ['endorsed'], (endorsed) => endorsed)
.attr('endorsed_by', ['endorsedBy'], (endorsedBy) => endorsedBy)
.attr('endorsed_by_label', ['endorsedBy'], (endorsedBy) => (endorsedBy ? 'Staff' : null))
.attr('endorsed_at', ['endorsedBy'], (endorsedBy) => (endorsedBy ? (new Date()).toISOString() : null))
Expand Down Expand Up @@ -38,7 +38,7 @@ Factory.define('commentsResult')
.option('pageSize', null, 5)
.option('threadId', null, 'test-thread')
.option('parentId', null, null)
.option('endorsed', null, null)
.option('endorsed', false, false)
.option('childCount', null, 0)
.attr('pagination', ['threadId', 'count', 'page', 'pageSize'], (threadId, count, page, pageSize) => {
const numPages = Math.ceil(count / pageSize);
Expand Down
Loading

0 comments on commit 80073e3

Please sign in to comment.