feat: Add pagination to posts' comments

This change adds pagination to posts' comments.

When viewing a post, if there are more than one page of comments,
initially users will only see the first page of the comments, and can
load more comments by clicking "load more comments" button.

This change only affects comments to posts. For comments that are
responses to other comments the pagination has not been implemented.
This commit is contained in:
Maxim Beder
2021-09-10 13:05:22 +02:00
committed by Maxim Beder
parent 451495ce6a
commit 929c859046
11 changed files with 694 additions and 23 deletions

View File

@@ -45,8 +45,8 @@ describe('Comments/Responses data layer tests', () => {
expect(store.getState().comments.commentsInThreads)
.toEqual({ 'test-thread': ['comment-1', 'comment-2', 'comment-3'] });
expect(store.getState().comments.pages)
.toEqual([['comment-1', 'comment-2', 'comment-3']]);
expect(store.getState().comments.pagination)
.toEqual({ 'test-thread': { currentPage: 1, totalPages: 1, hasMorePages: false } });
expect(Object.keys(store.getState().comments.commentsById))
.toEqual(['comment-1', 'comment-2', 'comment-3']);
expect(store.getState().comments.commentsById['comment-1'])
@@ -137,8 +137,6 @@ describe('Comments/Responses data layer tests', () => {
expect(store.getState().comments.commentsById)
.toHaveProperty(commentId);
expect(store.getState().comments.pages[0])
.toContain(commentId);
axiosMock.onDelete(`${commentsApiUrl}${commentId}/`)
.reply(201);
@@ -148,9 +146,6 @@ describe('Comments/Responses data layer tests', () => {
expect(store.getState().comments.commentsById)
.not
.toHaveProperty(commentId);
expect(store.getState().comments.pages[0])
.not
.toContain(commentId);
expect(store.getState().comments.commentsInThreads[threadId])
.not
.toContain(commentId);

View File

@@ -20,4 +20,12 @@ export const selectCommentResponses = commentId => createSelector(
mapIdToComment,
);
export const selectThreadHasMorePages = threadId => (
store => store.comments.pagination[threadId]?.hasMorePages || false
);
export const selectThreadCurrentPage = threadId => (
store => store.comments.pagination[threadId]?.currentPage || null
);
export const commentsStatus = state => state.comments.status;

View File

@@ -16,13 +16,12 @@ const commentsSlice = createSlice({
commentsById: {
// Map comment ids to comments.
},
pages: [],
// Stores the comment being posted in case it needs to be reposted due to network failure.
// TODO: save in localstorage so user can continue editing?
commentDraft: null,
totalPages: null,
totalThreads: null,
postStatus: RequestStatus.SUCCESSFUL,
pagination: {
},
},
reducers: {
fetchCommentsRequest: (state) => {
@@ -30,12 +29,17 @@ const commentsSlice = createSlice({
},
fetchCommentsSuccess: (state, { payload }) => {
state.status = RequestStatus.SUCCESSFUL;
state.pages[payload.page - 1] = payload.ids;
state.commentsInThreads = { ...state.commentsInThreads, ...payload.commentsInThreads };
state.commentsInThreads[payload.threadId] = [
...(state.commentsInThreads[payload.threadId] || []),
...(payload.commentsInThreads[payload.threadId] || []),
];
state.commentsInComments = { ...state.commentsInComments, ...payload.commentsInComments };
state.commentsById = { ...state.commentsById, ...payload.commentsById };
state.totalPages = payload.pagination.numPages;
state.totalThreads = payload.pagination.count;
state.pagination[payload.threadId] = {
currentPage: payload.page,
totalPages: payload.pagination.numPages,
hasMorePages: Boolean(payload.pagination.next),
};
},
fetchCommentsFailed: (state) => {
state.status = RequestStatus.FAILED;
@@ -109,7 +113,6 @@ const commentsSlice = createSlice({
if (parentId) {
state.commentsInComments[parentId] = state.commentsInComments[parentId].filter(item => item !== commentId);
}
state.pages = state.pages.map(page => page?.filter(item => item !== commentId));
delete state.commentsById[commentId];
},
},

View File

@@ -80,6 +80,7 @@ export function fetchThreadComments(threadId, { page = 1 } = {}) {
dispatch(fetchCommentsSuccess({
...normaliseComments(camelCaseObject(data)),
page,
threadId,
}));
} catch (error) {
if (getHttpErrorStatus(error) === 403) {