Files
frontend-app-discussions/src/discussions/posts/data/slices.js
sundasnoreen12 76da74ae20 feat: Modified discussions FE so that ONLY users with verified emails (#789)
* 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
2025-07-23 17:24:57 +05:00

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;