* feat: Modified discussions FE so that ONLY users with verified emails can create content * feat: added comment and response functionality * test: fixed test cases * refactor: refactor code and added HOC * test: added test cases * test: added test cases for failed and denied * feat: added states for button * refactor: added callback function * test: added test case to close the dialogue * refactor: refactor function
447 lines
11 KiB
JavaScript
447 lines
11 KiB
JavaScript
import { createSlice } from '@reduxjs/toolkit';
|
|
import omitBy from 'lodash/omitBy';
|
|
|
|
import {
|
|
PostsStatusFilter, RequestStatus, ThreadOrdering, ThreadType,
|
|
} from '../../../data/constants';
|
|
|
|
const mergeThreadsInTopics = (dataFromState, dataFromPayload) => {
|
|
const mergedArray = [];
|
|
mergedArray.push(dataFromState);
|
|
mergedArray.push(dataFromPayload);
|
|
return mergedArray.reduce((acc, obj) => {
|
|
const keys = Object.keys(obj);
|
|
const values = Object.values(obj);
|
|
keys.forEach((key, index) => {
|
|
if (!acc[key]) { acc[key] = []; }
|
|
if (Array.isArray(acc[key])) {
|
|
const uniqueValues = [...new Set(acc[key].concat(values[index]))];
|
|
acc[key] = uniqueValues;
|
|
} else { acc[key].push(values[index]); }
|
|
return acc;
|
|
});
|
|
return acc;
|
|
}, {});
|
|
};
|
|
|
|
const threadsSlice = createSlice({
|
|
name: 'thread',
|
|
initialState: {
|
|
status: RequestStatus.IN_PROGRESS,
|
|
avatars: {
|
|
// Mapping users to avatars
|
|
},
|
|
threadsInTopic: {
|
|
// Mapping of topic ids to thread ids in them
|
|
},
|
|
threadsById: {
|
|
// Mapping of threads ids to threads in them
|
|
},
|
|
author: null,
|
|
pages: [],
|
|
threadDraft: null,
|
|
nextPage: null,
|
|
totalPages: null,
|
|
totalThreads: null,
|
|
textSearchRewrite: null,
|
|
postStatus: RequestStatus.SUCCESSFUL,
|
|
filters: {
|
|
status: PostsStatusFilter.ALL,
|
|
postType: ThreadType.ALL,
|
|
cohort: '',
|
|
search: '',
|
|
},
|
|
postEditorVisible: false,
|
|
redirectToThread: null,
|
|
sortedBy: ThreadOrdering.BY_LAST_ACTIVITY,
|
|
confirmEmailStatus: RequestStatus.IDLE,
|
|
},
|
|
reducers: {
|
|
fetchLearnerThreadsRequest: (state, { payload }) => (
|
|
{
|
|
...state,
|
|
pages: state.author !== payload.author ? [] : state.pages,
|
|
author: state.author !== payload.author ? payload.author : state.author,
|
|
status: RequestStatus.IN_PROGRESS,
|
|
}
|
|
),
|
|
clearPostsPages: (state) => (
|
|
{
|
|
...state,
|
|
pages: [],
|
|
}
|
|
),
|
|
fetchThreadsRequest: (state) => (
|
|
{
|
|
...state,
|
|
status: RequestStatus.IN_PROGRESS,
|
|
}
|
|
),
|
|
fetchThreadsSuccess: (state, { payload }) => {
|
|
const {
|
|
author, page, ids, threadsById, isFilterChanged, threadsInTopic, avatars, pagination, textSearchRewrite,
|
|
} = payload;
|
|
|
|
const newState = { ...state };
|
|
|
|
if (newState.author !== author) {
|
|
newState.pages = [];
|
|
newState.author = author;
|
|
}
|
|
|
|
const updatedPages = newState.pages.slice();
|
|
if (!updatedPages[page - 1]) {
|
|
updatedPages[page - 1] = ids;
|
|
} else {
|
|
updatedPages[page - 1] = [...new Set([...updatedPages[page - 1], ...ids])];
|
|
}
|
|
newState.pages = updatedPages;
|
|
|
|
newState.status = RequestStatus.SUCCESSFUL;
|
|
newState.threadsById = { ...newState.threadsById, ...threadsById };
|
|
newState.threadsInTopic = (isFilterChanged || page === 1)
|
|
? { ...threadsInTopic }
|
|
: mergeThreadsInTopics(newState.threadsInTopic, threadsInTopic);
|
|
newState.avatars = { ...newState.avatars, ...avatars };
|
|
newState.nextPage = (page < pagination.numPages) ? page + 1 : null;
|
|
newState.totalPages = pagination.numPages;
|
|
newState.totalThreads = pagination.count;
|
|
newState.textSearchRewrite = textSearchRewrite;
|
|
|
|
return newState;
|
|
},
|
|
fetchThreadsFailed: (state) => (
|
|
{
|
|
...state,
|
|
status: RequestStatus.FAILED,
|
|
}
|
|
),
|
|
fetchThreadsDenied: (state) => (
|
|
{
|
|
...state,
|
|
status: RequestStatus.DENIED,
|
|
}
|
|
),
|
|
fetchThreadRequest: (state) => (
|
|
{
|
|
...state,
|
|
status: RequestStatus.IN_PROGRESS,
|
|
}
|
|
),
|
|
fetchThreadSuccess: (state, { payload }) => (
|
|
{
|
|
...state,
|
|
status: RequestStatus.SUCCESSFUL,
|
|
threadsById: { ...state.threadsById, ...payload.threadsById },
|
|
avatars: { ...state.avatars, ...payload.avatars },
|
|
}
|
|
),
|
|
fetchThreadByDirectLinkSuccess: (state, { payload }) => (
|
|
{
|
|
...state,
|
|
status: RequestStatus.SUCCESSFUL,
|
|
pages: [
|
|
...state.pages.slice(0, payload.page - 1),
|
|
payload.ids,
|
|
...state.pages.slice(payload.page),
|
|
],
|
|
threadsInTopic: { ...payload.threadsInTopic, ...state.threadsInTopic },
|
|
threadsById: { ...payload.threadsById, ...state.threadsById },
|
|
avatars: { ...state.avatars, ...payload.avatars },
|
|
}
|
|
),
|
|
fetchThreadFailed: (state) => (
|
|
{
|
|
...state,
|
|
status: RequestStatus.FAILED,
|
|
}
|
|
),
|
|
fetchThreadDenied: (state) => (
|
|
{
|
|
...state,
|
|
status: RequestStatus.DENIED,
|
|
}
|
|
),
|
|
postThreadRequest: (state, { payload }) => (
|
|
{
|
|
...state,
|
|
postStatus: RequestStatus.IN_PROGRESS,
|
|
threadsDraft: payload,
|
|
}
|
|
),
|
|
postThreadSuccess: (state, { payload }) => (
|
|
{
|
|
...state,
|
|
postStatus: RequestStatus.SUCCESSFUL,
|
|
threadsById: {
|
|
...state.threadsById,
|
|
[payload.id]: payload,
|
|
},
|
|
threadsInTopic: {
|
|
...state.threadsInTopic,
|
|
[payload.topicId]: [
|
|
...(state.threadsInTopic[payload.topicId] || []),
|
|
payload.id,
|
|
],
|
|
},
|
|
pages: !payload.anonymousToPeers
|
|
? [
|
|
...(state.pages[0] ? [payload.id].concat(state.pages[0]) : []),
|
|
...state.pages.slice(1),
|
|
]
|
|
: [...state.pages],
|
|
avatars: { ...state.avatars, ...payload.avatars },
|
|
redirectToThread: { topicId: payload.topicId, threadId: payload.id },
|
|
threadDraft: null,
|
|
}
|
|
),
|
|
postThreadFailed: (state) => (
|
|
{
|
|
...state,
|
|
postStatus: RequestStatus.FAILED,
|
|
}
|
|
),
|
|
postThreadDenied: (state) => (
|
|
{
|
|
...state,
|
|
postStatus: RequestStatus.DENIED,
|
|
}
|
|
),
|
|
updateThreadRequest: (state, { payload }) => (
|
|
{
|
|
...state,
|
|
postStatus: RequestStatus.IN_PROGRESS,
|
|
threadsDraft: payload,
|
|
}
|
|
),
|
|
updateThreadAsRead: (state, { payload }) => (
|
|
{
|
|
...state,
|
|
threadsById: {
|
|
...state.threadsById,
|
|
[payload.threadId]: {
|
|
...state.threadsById[payload.threadId],
|
|
read: true,
|
|
},
|
|
},
|
|
}
|
|
),
|
|
updateThreadSuccess: (state, { payload }) => (
|
|
{
|
|
...state,
|
|
postStatus: RequestStatus.SUCCESSFUL,
|
|
threadsById: {
|
|
...state.threadsById,
|
|
[payload.id]: {
|
|
...state.threadsById[payload.id],
|
|
...payload,
|
|
abuseFlaggedCount: state.threadsById[payload.id].abuseFlaggedCount || false,
|
|
},
|
|
},
|
|
avatars: { ...state.avatars, ...payload.avatars },
|
|
threadDraft: null,
|
|
}
|
|
),
|
|
updateThreadFailed: (state) => (
|
|
{
|
|
...state,
|
|
postStatus: RequestStatus.FAILED,
|
|
totalThreads: 0,
|
|
}
|
|
),
|
|
updateThreadDenied: (state) => (
|
|
{
|
|
...state,
|
|
postStatus: RequestStatus.DENIED,
|
|
totalThreads: 0,
|
|
}
|
|
),
|
|
deleteThreadRequest: (state) => (
|
|
{
|
|
...state,
|
|
postStatus: RequestStatus.IN_PROGRESS,
|
|
}
|
|
),
|
|
deleteThreadSuccess: (state, { payload }) => {
|
|
const { threadId } = payload;
|
|
const { topicId } = state.threadsById[threadId];
|
|
return {
|
|
...state,
|
|
postStatus: RequestStatus.SUCCESSFUL,
|
|
threadsInTopic: {
|
|
...state.threadsInTopic,
|
|
[topicId]: state.threadsInTopic[topicId].filter(item => item !== threadId),
|
|
},
|
|
pages: state.pages.map(page => page?.filter(item => item !== threadId)),
|
|
threadsById: omitBy(state.threadsById, (thread) => thread.id === threadId),
|
|
};
|
|
},
|
|
deleteThreadFailed: (state) => (
|
|
{
|
|
...state,
|
|
postStatus: RequestStatus.FAILED,
|
|
}
|
|
),
|
|
deleteThreadDenied: (state) => (
|
|
{
|
|
...state,
|
|
postStatus: RequestStatus.DENIED,
|
|
}
|
|
),
|
|
setSortedBy: (state, { payload }) => (
|
|
{
|
|
...state,
|
|
sortedBy: payload,
|
|
pages: [],
|
|
}
|
|
),
|
|
setStatusFilter: (state, { payload }) => (
|
|
{
|
|
...state,
|
|
filters: {
|
|
...state.filters,
|
|
status: payload,
|
|
},
|
|
pages: [],
|
|
}
|
|
),
|
|
setPostsTypeFilter: (state, { payload }) => (
|
|
{
|
|
...state,
|
|
filters: {
|
|
...state.filters,
|
|
postType: payload,
|
|
},
|
|
pages: [],
|
|
}
|
|
),
|
|
setCohortFilter: (state, { payload }) => (
|
|
{
|
|
...state,
|
|
filters: {
|
|
...state.filters,
|
|
cohort: payload,
|
|
},
|
|
pages: [],
|
|
}
|
|
),
|
|
setSearchQuery: (state, { payload }) => (
|
|
{
|
|
...state,
|
|
filters: {
|
|
...state.filters,
|
|
search: payload,
|
|
status: state.filters.status === PostsStatusFilter.FOLLOWING
|
|
? PostsStatusFilter.ALL
|
|
: state.filters.status,
|
|
},
|
|
pages: [],
|
|
}
|
|
),
|
|
showPostEditor: (state) => (
|
|
{
|
|
...state,
|
|
postEditorVisible: true,
|
|
redirectToThread: null,
|
|
}
|
|
),
|
|
hidePostEditor: (state) => (
|
|
{
|
|
...state,
|
|
postEditorVisible: false,
|
|
}
|
|
),
|
|
clearRedirect: (state) => (
|
|
{
|
|
...state,
|
|
redirectToThread: null,
|
|
}
|
|
),
|
|
clearFilter: (state) => (
|
|
{
|
|
...state,
|
|
filters: {
|
|
...state.filters,
|
|
status: PostsStatusFilter.ALL,
|
|
postType: ThreadType.ALL,
|
|
cohort: '',
|
|
search: '',
|
|
},
|
|
pages: [],
|
|
}
|
|
),
|
|
clearSort: (state) => (
|
|
{
|
|
...state,
|
|
sortedBy: ThreadOrdering.BY_LAST_ACTIVITY,
|
|
pages: [],
|
|
}
|
|
),
|
|
sendAccountActivationEmailRequest: (state) => (
|
|
{
|
|
...state,
|
|
confirmEmailStatus: RequestStatus.IN_PROGRESS,
|
|
}
|
|
),
|
|
sendAccountActivationEmailSuccess: (state) => ({
|
|
...state,
|
|
confirmEmailStatus: RequestStatus.SUCCESSFUL,
|
|
}),
|
|
sendAccountActivationEmailFailed: (state) => (
|
|
{
|
|
...state,
|
|
confirmEmailStatus: RequestStatus.FAILED,
|
|
}
|
|
),
|
|
sendAccountActivationEmailDenied: (state) => (
|
|
{
|
|
...state,
|
|
confirmEmailStatus: RequestStatus.DENIED,
|
|
}
|
|
),
|
|
},
|
|
});
|
|
|
|
export const {
|
|
deleteThreadDenied,
|
|
deleteThreadFailed,
|
|
deleteThreadRequest,
|
|
deleteThreadSuccess,
|
|
fetchLearnerThreadsRequest,
|
|
fetchThreadDenied,
|
|
fetchThreadFailed,
|
|
fetchThreadRequest,
|
|
fetchThreadsDenied,
|
|
fetchThreadsFailed,
|
|
fetchThreadsRequest,
|
|
fetchThreadsSuccess,
|
|
fetchThreadSuccess,
|
|
fetchThreadByDirectLinkSuccess,
|
|
postThreadDenied,
|
|
postThreadFailed,
|
|
postThreadRequest,
|
|
postThreadSuccess,
|
|
updateThreadDenied,
|
|
updateThreadFailed,
|
|
updateThreadRequest,
|
|
updateThreadAsRead,
|
|
updateThreadSuccess,
|
|
setPostsTypeFilter,
|
|
setCohortFilter,
|
|
setSortedBy,
|
|
setStatusFilter,
|
|
setSearchQuery,
|
|
showPostEditor,
|
|
hidePostEditor,
|
|
clearRedirect,
|
|
clearPostsPages,
|
|
clearFilter,
|
|
clearSort,
|
|
sendAccountActivationEmailDenied,
|
|
sendAccountActivationEmailFailed,
|
|
sendAccountActivationEmailRequest,
|
|
sendAccountActivationEmailSuccess,
|
|
} = threadsSlice.actions;
|
|
|
|
export const threadsReducer = threadsSlice.reducer;
|