diff --git a/src/discussions/post-comments/PostCommentsView.jsx b/src/discussions/post-comments/PostCommentsView.jsx
index e8e17dac..f5bb12c4 100644
--- a/src/discussions/post-comments/PostCommentsView.jsx
+++ b/src/discussions/post-comments/PostCommentsView.jsx
@@ -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';
@@ -127,15 +125,7 @@ const PostCommentsView = () => {
)}>
{!!commentsCount && }
- {type === ThreadType.DISCUSSION && (
-
- )}
- {type === ThreadType.QUESTION && (
- <>
-
-
- >
- )}
+
);
diff --git a/src/discussions/post-comments/PostCommentsView.test.jsx b/src/discussions/post-comments/PostCommentsView.test.jsx
index 53946c8b..9f858890 100644
--- a/src/discussions/post-comments/PostCommentsView.test.jsx
+++ b/src/discussions/post-comments/PostCommentsView.test.jsx
@@ -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';
@@ -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,
@@ -76,6 +76,7 @@ async function mockAxiosReturnPagedCommentsResponses() {
Factory.build('commentsResult', null, {
threadId: discussionPostId,
parentId,
+ endorsed: false,
page,
pageSize: 1,
count: 2,
@@ -201,6 +202,7 @@ describe('ThreadView', () => {
id: commentId,
rendered_body: rawBody,
raw_body: rawBody,
+ endorsed: false,
})];
});
axiosMock.onPost(commentsApiUrl).reply(({ data }) => {
@@ -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 });
@@ -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');
@@ -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');
@@ -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 });
@@ -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 () => {
@@ -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 () => {
@@ -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'))
@@ -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();
@@ -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);
});
@@ -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();
@@ -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();
@@ -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();
diff --git a/src/discussions/post-comments/comments/CommentsView.jsx b/src/discussions/post-comments/comments/CommentsView.jsx
index 30ee8c68..b8cd3afb 100644
--- a/src/discussions/post-comments/comments/CommentsView.jsx
+++ b/src/discussions/post-comments/comments/CommentsView.jsx
@@ -5,7 +5,7 @@ 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';
@@ -13,7 +13,7 @@ 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);
@@ -25,7 +25,7 @@ const CommentsView = ({ endorsed }) => {
hasMorePages,
isLoading,
handleLoadMoreResponses,
- } = usePostComments(endorsed);
+ } = usePostComments(threadType);
const handleAddResponse = useCallback(() => {
setAddingResponse(true);
@@ -45,7 +45,7 @@ const CommentsView = ({ endorsed }) => {
), []);
- const handleComments = useCallback((postCommentsIds, showLoadMoreResponses = false) => (
+ const handleComments = useCallback((postCommentsIds) => (
{postCommentsIds.map((commentId) => (
{
marginBottom={isLastElementOfList(postCommentsIds, commentId)}
/>
))}
- {hasMorePages && !isLoading && !showLoadMoreResponses && (
-
- )}
- {isLoading && !showLoadMoreResponses && (
-
-
-
- )}
), [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 &&
}
- {handleComments(unEndorsedCommentsIds, false)}
- {(isUserPrivilegedInPostingRestriction && !!unEndorsedCommentsIds.length && !isClosed) && (
-
- {!addingResponse && (
-
- )}
-
-
- )}
- >
- )}
+ {handleDefinition(messages.endorsedResponseCount, endorsedCommentsIds.length)}
+ {handleComments(endorsedCommentsIds)}
>
+ )}
+ {handleDefinition(messages.responseCount, unEndorsedCommentsIds.length)}
+ {unEndorsedCommentsIds.length > 0 && handleComments(unEndorsedCommentsIds)}
+ {hasMorePages && !isLoading && (!!unEndorsedCommentsIds.length || !!endorsedCommentsIds.length) && (
+
+ )}
+ {isLoading && (
+
+
+
+ )}
+ {(isUserPrivilegedInPostingRestriction && (!!unEndorsedCommentsIds.length || !!endorsedCommentsIds.length)
+ && !isClosed) && (
+
+ {!addingResponse && (
+
+ )}
+
+
+ )}
+ >
)
);
};
CommentsView.propTypes = {
- endorsed: PropTypes.oneOf([
- EndorsementStatus.ENDORSED, EndorsementStatus.UNENDORSED, EndorsementStatus.DISCUSSION,
+ threadType: PropTypes.oneOf([
+ ThreadType.DISCUSSION, ThreadType.QUESTION,
]).isRequired,
};
diff --git a/src/discussions/post-comments/comments/comment/Comment.jsx b/src/discussions/post-comments/comments/comment/Comment.jsx
index 02b88623..c2c5a879 100644
--- a/src/discussions/post-comments/comments/comment/Comment.jsx
+++ b/src/discussions/post-comments/comments/comment/Comment.jsx
@@ -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]);
diff --git a/src/discussions/post-comments/comments/comment/Reply.jsx b/src/discussions/post-comments/comments/comment/Reply.jsx
index 5a8d1ed6..c731213c 100644
--- a/src/discussions/post-comments/comments/comment/Reply.jsx
+++ b/src/discussions/post-comments/comments/comment/Reply.jsx
@@ -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(() => {
diff --git a/src/discussions/post-comments/data/__factories__/comments.factory.js b/src/discussions/post-comments/data/__factories__/comments.factory.js
index 939bf140..08d30baa 100644
--- a/src/discussions/post-comments/data/__factories__/comments.factory.js
+++ b/src/discussions/post-comments/data/__factories__/comments.factory.js
@@ -6,7 +6,7 @@ Factory.define('comment')
.sequence('rendered_body', ['endorsed'], (idx, endorsed) => `Some contents for ${endorsed ? 'endorsed ' : 'unendorsed '}comment number ${idx}.`)
.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))
@@ -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);
diff --git a/src/discussions/post-comments/data/api.js b/src/discussions/post-comments/data/api.js
index bf73f95c..58c4648a 100644
--- a/src/discussions/post-comments/data/api.js
+++ b/src/discussions/post-comments/data/api.js
@@ -1,7 +1,7 @@
import { ensureConfig, getConfig, snakeCaseObject } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
-import { EndorsementValue } from '../../../data/constants';
+import { ThreadType } from '../../../data/constants';
ensureConfig([
'LMS_BASE_URL',
@@ -20,7 +20,7 @@ export const getCommentsApiUrl = () => `${getConfig().LMS_BASE_URL}/api/discussi
* @returns {Promise<{}>}
*/
export const getThreadComments = async (threadId, {
- endorsed,
+ threadType,
page,
pageSize,
reverseOrder,
@@ -29,12 +29,12 @@ export const getThreadComments = async (threadId, {
} = {}) => {
const params = snakeCaseObject({
threadId,
- endorsed: EndorsementValue[endorsed],
page,
pageSize,
reverseOrder,
requestedFields: 'profile_image',
enableInContextSidebar,
+ mergeQuestionTypeResponses: threadType === ThreadType.QUESTION ? true : null,
});
const { data } = await getAuthenticatedHttpClient().get(getCommentsApiUrl(), { params: { ...params, signal } });
diff --git a/src/discussions/post-comments/data/hooks.js b/src/discussions/post-comments/data/hooks.js
index f697210e..d53c3884 100644
--- a/src/discussions/post-comments/data/hooks.js
+++ b/src/discussions/post-comments/data/hooks.js
@@ -40,13 +40,13 @@ export function usePost(postId) {
return thread || {};
}
-export function usePostComments(endorsed = null) {
+export function usePostComments(threadType) {
const { enableInContextSidebar, postId } = useContext(DiscussionContext);
const [isLoading, dispatch] = useDispatchWithState();
- const comments = useSelector(selectThreadComments(postId, endorsed));
+ const comments = useSelector(selectThreadComments(postId));
const reverseOrder = useSelector(selectCommentSortOrder);
- const hasMorePages = useSelector(selectThreadHasMorePages(postId, endorsed));
- const currentPage = useSelector(selectThreadCurrentPage(postId, endorsed));
+ const hasMorePages = useSelector(selectThreadHasMorePages(postId));
+ const currentPage = useSelector(selectThreadCurrentPage(postId));
const endorsedCommentsIds = useMemo(() => (
[...filterPosts(comments, 'endorsed')].map(comment => comment.id)
@@ -58,19 +58,19 @@ export function usePostComments(endorsed = null) {
const handleLoadMoreResponses = useCallback(async () => {
const params = {
- endorsed,
+ threadType,
page: currentPage + 1,
reverseOrder,
};
await dispatch(fetchThreadComments(postId, params));
trackLoadMoreEvent(postId, params);
- }, [currentPage, endorsed, postId, reverseOrder]);
+ }, [currentPage, threadType, postId, reverseOrder]);
useEffect(() => {
const abortController = new AbortController();
dispatch(fetchThreadComments(postId, {
- endorsed,
+ threadType,
page: 1,
reverseOrder,
enableInContextSidebar,
@@ -80,7 +80,7 @@ export function usePostComments(endorsed = null) {
return () => {
abortController.abort();
};
- }, [postId, endorsed, reverseOrder, enableInContextSidebar]);
+ }, [postId, threadType, reverseOrder, enableInContextSidebar]);
return {
endorsedCommentsIds,
diff --git a/src/discussions/post-comments/data/redux.test.js b/src/discussions/post-comments/data/redux.test.js
index dbad7cf3..2e419942 100644
--- a/src/discussions/post-comments/data/redux.test.js
+++ b/src/discussions/post-comments/data/redux.test.js
@@ -4,7 +4,7 @@ import { Factory } from 'rosie';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { initializeMockApp } from '@edx/frontend-platform/testing';
-import { EndorsementStatus } from '../../../data/constants';
+import { ThreadType } from '../../../data/constants';
import { initializeStore } from '../../../store';
import executeThunk from '../../../test-utils';
import { getCommentsApiUrl } from './api';
@@ -39,37 +39,23 @@ describe('Comments/Responses data layer tests', () => {
});
test.each([
- {
- threadType: 'discussion',
- endorsed: EndorsementStatus.DISCUSSION,
- },
- {
- threadType: 'question',
- endorsed: EndorsementStatus.UNENDORSED,
- },
- {
- threadType: 'question',
- endorsed: EndorsementStatus.ENDORSED,
- },
- ])('successfully processes comments for \'$threadType\' thread with endorsed=$endorsed', async ({
- endorsed,
- }) => {
+ ThreadType.DISCUSSION,
+ ThreadType.QUESTION,
+ ])('successfully processes comments for %s type thread', async (threadType) => {
const threadId = 'test-thread';
axiosMock.onGet(commentsApiUrl)
.reply(200, Factory.build('commentsResult'));
- await executeThunk(fetchThreadComments(threadId, { endorsed }), store.dispatch, store.getState);
+ await executeThunk(fetchThreadComments(threadId, { threadType }), store.dispatch, store.getState);
expect(store.getState().comments.commentsInThreads)
- .toEqual({ 'test-thread': { [endorsed]: ['comment-1', 'comment-2', 'comment-3'] } });
+ .toEqual({ 'test-thread': ['comment-1', 'comment-2', 'comment-3'] });
expect(store.getState().comments.pagination)
.toEqual({
'test-thread': {
- [endorsed]: {
- currentPage: 1,
- totalPages: 1,
- hasMorePages: false,
- },
+ currentPage: 1,
+ totalPages: 1,
+ hasMorePages: false,
},
});
expect(Object.keys(store.getState().comments.commentsById))
@@ -82,7 +68,7 @@ describe('Comments/Responses data layer tests', () => {
.toEqual('test-thread');
});
- test('successfully processes comment responses', async () => {
+ test('successfully processes comment replies', async () => {
const threadId = 'test-thread';
const commentId = 'comment-1';
axiosMock.onGet(commentsApiUrl)
@@ -101,7 +87,7 @@ describe('Comments/Responses data layer tests', () => {
.toEqual({ 'comment-1': ['comment-4', 'comment-5', 'comment-6'] });
});
- test('successfully handles response creation for discussion type threads', async () => {
+ test('successfully handles comment creation for threads', async () => {
const threadId = 'test-thread';
const content = 'Test comment';
axiosMock.onGet(commentsApiUrl)
@@ -119,21 +105,19 @@ describe('Comments/Responses data layer tests', () => {
await executeThunk(addComment(content, threadId, null), store.dispatch, store.getState);
expect(store.getState().comments.commentsInThreads[threadId])
- .toEqual({
- [EndorsementStatus.DISCUSSION]: [
- 'comment-1',
- 'comment-2',
- 'comment-3',
- 'comment-4',
- ],
- });
+ .toEqual([
+ 'comment-1',
+ 'comment-2',
+ 'comment-3',
+ 'comment-4',
+ ]);
expect(Object.keys(store.getState().comments.commentsById))
.toEqual(['comment-1', 'comment-2', 'comment-3', 'comment-4']);
expect(store.getState().comments.commentsById['comment-4'].threadId)
.toEqual(threadId);
});
- test('successfully handles reply creation for discussion type threads', async () => {
+ test('successfully handles reply creation for threads', async () => {
const threadId = 'test-thread';
const parentId = 'comment-1';
const content = 'Test comment';
@@ -156,13 +140,11 @@ describe('Comments/Responses data layer tests', () => {
await executeThunk(addComment(content, threadId, null), store.dispatch, store.getState);
expect(store.getState().comments.commentsInThreads[threadId])
- .toEqual({
- [EndorsementStatus.DISCUSSION]: [
- 'comment-1',
- 'comment-2',
- 'comment-3',
- ],
- });
+ .toEqual([
+ 'comment-1',
+ 'comment-2',
+ 'comment-3',
+ ]);
expect(Object.keys(store.getState().comments.commentsById))
.toEqual(['comment-1', 'comment-2', 'comment-3', 'comment-4']);
expect(store.getState().comments.commentsInComments[parentId])
@@ -173,54 +155,6 @@ describe('Comments/Responses data layer tests', () => {
.toEqual(parentId);
});
- test('successfully handles comment creation for question type threads', async () => {
- const threadId = 'test-thread';
- const content = 'Test comment';
- axiosMock.onGet(commentsApiUrl)
- .reply(200, Factory.build('commentsResult', null, { endorsed: false }));
- await executeThunk(
- fetchThreadComments(threadId, { endorsed: EndorsementStatus.UNENDORSED }),
- store.dispatch,
- store.getState,
- );
- axiosMock.onGet(commentsApiUrl)
- .reply(200, Factory.build('commentsResult', null, { endorsed: true }));
- await executeThunk(
- fetchThreadComments(threadId, { endorsed: EndorsementStatus.ENDORSED }),
- store.dispatch,
- store.getState,
- );
-
- axiosMock.onPost(commentsApiUrl)
- .reply(200, Factory.build('comment', {
- thread_id: threadId,
- raw_body: content,
- rendered_body: content,
- }));
-
- await executeThunk(addComment(content, threadId, null), store.dispatch, store.getState);
-
- expect(store.getState().comments.commentsInThreads[threadId])
- .toEqual({
- [EndorsementStatus.UNENDORSED]: [
- 'comment-1',
- 'comment-2',
- 'comment-3',
- // Newly-added comment
- 'comment-7',
- ],
- [EndorsementStatus.ENDORSED]: [
- 'comment-4',
- 'comment-5',
- 'comment-6',
- ],
- });
- expect(Object.keys(store.getState().comments.commentsById))
- .toEqual(['comment-1', 'comment-2', 'comment-3', 'comment-4', 'comment-5', 'comment-6', 'comment-7']);
- expect(store.getState().comments.commentsById['comment-7'].threadId)
- .toEqual(threadId);
- });
-
test('successfully handles comment edits', async () => {
const threadId = 'test-thread';
const commentId = 'comment-1';
@@ -271,7 +205,7 @@ describe('Comments/Responses data layer tests', () => {
.toContain(commentId);
});
- test('correctly handles comment responses pagination after posting a new response', async () => {
+ test('correctly handles comment replies pagination after posting a new reply', async () => {
const threadId = 'test-thread';
const commentId = 'comment-1';
@@ -327,15 +261,9 @@ describe('Comments/Responses data layer tests', () => {
});
test.each([
- {
- threadType: 'discussion',
- endorsed: EndorsementStatus.DISCUSSION,
- },
- {
- threadType: 'unendorsed',
- endorsed: EndorsementStatus.UNENDORSED,
- },
- ])('correctly handles `$threadType` thread comments pagination after posting a new comment', async ({ endorsed }) => {
+ ThreadType.DISCUSSION,
+ ThreadType.QUESTION,
+ ])('correctly handles %s thread comments pagination after posting a new comment', async (threadType) => {
const threadId = 'test-thread';
// Build all comments first, so we can paginate over them and they
@@ -348,7 +276,7 @@ describe('Comments/Responses data layer tests', () => {
results: allComments.slice(0, 3),
pagination: { count: 4, numPages: 2 },
});
- await executeThunk(fetchThreadComments(threadId, { endorsed }), store.dispatch, store.getState);
+ await executeThunk(fetchThreadComments(threadId, { threadType }), store.dispatch, store.getState);
// Post new comment
const comment = Factory.build('comment', { thread_id: threadId });
@@ -365,10 +293,10 @@ describe('Comments/Responses data layer tests', () => {
results: allComments.slice(3, 6),
pagination: { count: 6, numPages: 2 },
});
- await executeThunk(fetchThreadComments(threadId, { page: 2, endorsed }), store.dispatch, store.getState);
+ await executeThunk(fetchThreadComments(threadId, { page: 2, threadType }), store.dispatch, store.getState);
// sorting is implemented on backend
- expect(store.getState().comments.commentsInThreads[threadId][endorsed])
+ expect(store.getState().comments.commentsInThreads[threadId])
.toEqual([
'comment-1',
'comment-2',
diff --git a/src/discussions/post-comments/data/selectors.js b/src/discussions/post-comments/data/selectors.js
index fb04b8f3..53869046 100644
--- a/src/discussions/post-comments/data/selectors.js
+++ b/src/discussions/post-comments/data/selectors.js
@@ -8,9 +8,9 @@ export const selectCommentOrResponseById = commentOrResponseId => createSelector
comments => comments[commentOrResponseId],
);
-export const selectThreadComments = (threadId, endorsed = null) => createSelector(
+export const selectThreadComments = (threadId) => createSelector(
[
- state => state.comments.commentsInThreads[threadId]?.[endorsed] || [],
+ state => state.comments.commentsInThreads[threadId] || [],
selectCommentsById,
],
mapIdToComment,
@@ -28,12 +28,12 @@ export const selectCommentResponses = commentId => createSelector(
mapIdToComment,
);
-export const selectThreadHasMorePages = (threadId, endorsed = null) => (
- state => state.comments.pagination[threadId]?.[endorsed]?.hasMorePages || false
+export const selectThreadHasMorePages = (threadId) => (
+ state => state.comments.pagination[threadId]?.hasMorePages || false
);
-export const selectThreadCurrentPage = (threadId, endorsed = null) => (
- state => state.comments.pagination[threadId]?.[endorsed]?.currentPage || null
+export const selectThreadCurrentPage = (threadId) => (
+ state => state.comments.pagination[threadId]?.currentPage || null
);
export const selectCommentHasMorePages = commentId => (
diff --git a/src/discussions/post-comments/data/slices.js b/src/discussions/post-comments/data/slices.js
index 96ebf1f9..ca471541 100644
--- a/src/discussions/post-comments/data/slices.js
+++ b/src/discussions/post-comments/data/slices.js
@@ -1,6 +1,6 @@
import { createSlice } from '@reduxjs/toolkit';
-import { EndorsementStatus, RequestStatus } from '../../../data/constants';
+import { RequestStatus } from '../../../data/constants';
const commentsSlice = createSlice({
name: 'comments',
@@ -31,15 +31,14 @@ const commentsSlice = createSlice({
}
),
fetchCommentsSuccess: (state, { payload }) => {
- const { threadId, page, endorsed } = payload;
+ const { threadId, page } = payload;
const newState = { ...state };
newState.status = RequestStatus.SUCCESSFUL;
-
newState.commentsInThreads = {
...newState.commentsInThreads,
- [threadId]: newState.commentsInThreads[threadId] || {},
+ [threadId]: newState.commentsInThreads[threadId] || [],
};
newState.pagination = {
@@ -50,23 +49,16 @@ const commentsSlice = createSlice({
if (page === 1) {
newState.commentsInThreads = {
...newState.commentsInThreads,
- [threadId]: {
- ...newState.commentsInThreads[threadId],
- [endorsed]: payload.commentsInThreads[threadId] || [],
- },
+ [threadId]: [...payload.commentsInThreads[threadId]] || [],
};
} else {
newState.commentsInThreads = {
- ...newState.commentsInThreads,
- [threadId]: {
- ...newState.commentsInThreads[threadId],
- [endorsed]: [
- ...new Set([
- ...(newState.commentsInThreads[threadId][endorsed] || []),
- ...(payload.commentsInThreads[threadId] || []),
- ]),
- ],
- },
+ [threadId]: [
+ ...new Set([
+ ...(newState.commentsInThreads[threadId] || []),
+ ...(payload.commentsInThreads[threadId] || []),
+ ]),
+ ],
};
}
@@ -74,11 +66,9 @@ const commentsSlice = createSlice({
...newState.pagination,
[threadId]: {
...newState.pagination[threadId],
- [endorsed]: {
- currentPage: payload.page,
- totalPages: payload.pagination.numPages,
- hasMorePages: Boolean(payload.pagination.next),
- },
+ currentPage: payload.page,
+ totalPages: payload.pagination.numPages,
+ hasMorePages: Boolean(payload.pagination.next),
},
};
@@ -181,21 +171,10 @@ const commentsSlice = createSlice({
],
};
} else {
- const threadComments = newState.commentsInThreads[payload.threadId] || {};
- const endorsementStatus = threadComments[EndorsementStatus.DISCUSSION]
- ? EndorsementStatus.DISCUSSION
- : EndorsementStatus.UNENDORSED;
-
- const updatedThreadComments = {
- ...threadComments,
- [endorsementStatus]: [
- ...(threadComments[endorsementStatus] || []),
- payload.id,
- ],
- };
+ const threadComments = newState.commentsInThreads[payload.threadId] || [];
newState.commentsInThreads = {
...newState.commentsInThreads,
- [payload.threadId]: updatedThreadComments,
+ [payload.threadId]: [...threadComments, payload.id],
};
}
@@ -231,30 +210,7 @@ const commentsSlice = createSlice({
[payload.id]: payload,
},
commentDraft: null,
- }
- ),
- updateCommentsList: (state, { payload }) => {
- const { id: commentId, threadId, endorsed } = payload;
- const commentAddListtype = endorsed ? EndorsementStatus.ENDORSED : EndorsementStatus.UNENDORSED;
- const commentRemoveListType = !endorsed ? EndorsementStatus.ENDORSED : EndorsementStatus.UNENDORSED;
-
- const updatedThread = { ...state.commentsInThreads[threadId] };
-
- updatedThread[commentRemoveListType] = updatedThread[commentRemoveListType]
- ?.filter(item => item !== commentId)
- ?? [];
- updatedThread[commentAddListtype] = [
- ...(updatedThread[commentAddListtype] || []), commentId,
- ];
-
- return {
- ...state,
- commentsInThreads: {
- ...state.commentsInThreads,
- [threadId]: updatedThread,
- },
- };
- },
+ }),
deleteCommentRequest: (state) => (
{
...state,
@@ -285,12 +241,9 @@ const commentsSlice = createSlice({
commentsById: { ...state.commentsById },
};
- [EndorsementStatus.DISCUSSION, EndorsementStatus.UNENDORSED, EndorsementStatus.ENDORSED].forEach((endorsed) => {
- newState.commentsInThreads[threadId] = {
- ...newState.commentsInThreads[threadId],
- [endorsed]: newState.commentsInThreads[threadId]?.[endorsed]?.filter(item => item !== commentId),
- };
- });
+ newState.commentsInThreads[threadId] = [
+ ...newState.commentsInThreads[threadId]?.filter(item => item !== commentId) || [],
+ ];
if (parentId) {
newState.commentsInComments[parentId] = newState.commentsInComments[parentId].filter(
@@ -328,7 +281,6 @@ export const {
updateCommentFailed,
updateCommentRequest,
updateCommentSuccess,
- updateCommentsList,
deleteCommentDenied,
deleteCommentFailed,
deleteCommentRequest,
diff --git a/src/discussions/post-comments/data/thunks.js b/src/discussions/post-comments/data/thunks.js
index 311774a6..f7480153 100644
--- a/src/discussions/post-comments/data/thunks.js
+++ b/src/discussions/post-comments/data/thunks.js
@@ -1,7 +1,6 @@
import { camelCaseObject } from '@edx/frontend-platform';
import { logError } from '@edx/frontend-platform/logging';
-import { ContentActions, EndorsementStatus } from '../../../data/constants';
import { getHttpErrorStatus } from '../../utils';
import {
deleteComment, getCommentResponses, getThreadComments, postComment, updateComment,
@@ -26,7 +25,6 @@ import {
updateCommentDenied,
updateCommentFailed,
updateCommentRequest,
- updateCommentsList,
updateCommentSuccess,
} from './slices';
@@ -78,7 +76,7 @@ export function fetchThreadComments(
{
page = 1,
reverseOrder,
- endorsed = EndorsementStatus.DISCUSSION,
+ threadType,
enableInContextSidebar,
signal,
} = {},
@@ -87,11 +85,10 @@ export function fetchThreadComments(
try {
dispatch(fetchCommentsRequest());
const data = await getThreadComments(threadId, {
- page, reverseOrder, endorsed, enableInContextSidebar, signal,
+ page, reverseOrder, threadType, enableInContextSidebar, signal,
});
dispatch(fetchCommentsSuccess({
...normaliseComments(camelCaseObject(data)),
- endorsed,
page,
threadId,
}));
@@ -127,15 +124,12 @@ export function fetchCommentResponses(commentId, { page = 1, reverseOrder = true
};
}
-export function editComment(commentId, comment, action = null) {
+export function editComment(commentId, comment) {
return async (dispatch) => {
try {
dispatch(updateCommentRequest({ commentId }));
const data = await updateComment(commentId, comment);
dispatch(updateCommentSuccess(camelCaseObject(data)));
- if (action === ContentActions.ENDORSE) {
- dispatch(updateCommentsList(camelCaseObject(data)));
- }
} catch (error) {
if (getHttpErrorStatus(error) === 403) {
dispatch(updateCommentDenied());
diff --git a/src/index.scss b/src/index.scss
index e4323d24..e80990b4 100755
--- a/src/index.scss
+++ b/src/index.scss
@@ -61,10 +61,6 @@ $fa-font-path: "~font-awesome/fonts";
font-weight: 500 !important;
}
-.font-style-normal {
- font-style: normal !important;
-}
-
.post-footer-icon-dimensions {
width: 32px !important;
height: 32px !important;
@@ -496,7 +492,7 @@ code {
}
.font-style {
- font-style: normal;
+ font-style: normal !important;
}
.in-context-navbar {