Basic discussions forum framework

Adds the basic structure for the Discussions MFE around which future development
will happen.
This commit is contained in:
Kshitij Sobti
2020-08-18 16:58:48 +05:30
parent 56d68e76ad
commit 491f7b7acd
58 changed files with 9313 additions and 4194 deletions

View File

@@ -0,0 +1,35 @@
/* eslint-disable import/prefer-default-export */
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { API_BASE_URL } from '../../../data/constants';
export async function getCourseThreads(
courseId, topicIds, {
page, pageSize, textSearch, orderBy, following, view, requestedFields,
} = {},
) {
const url = new URL(`${API_BASE_URL}/api/discussion/v1/threads/`);
const paramsMap = {
page,
page_size: pageSize,
topic_id: topicIds && topicIds.join(','),
text_search: textSearch,
order_by: orderBy,
following,
view,
requested_fields: requestedFields,
};
url.searchParams.append('course_id', courseId);
Object.keys(paramsMap)
.forEach(
(param) => {
const paramValue = paramsMap[param];
if (paramValue) {
url.searchParams.append(param, paramValue);
}
},
);
const { data } = await getAuthenticatedHttpClient()
.get(url);
return data;
}

View File

@@ -0,0 +1 @@
export * from './slices';

View File

@@ -0,0 +1,4 @@
/* eslint-disable import/prefer-default-export */
export const selectCourseThreads = topicId => state => state.threads.threads[topicId] || [];
export const courseTopicsStatus = state => state.topics.status;

View File

@@ -0,0 +1,55 @@
/* eslint-disable no-param-reassign,import/prefer-default-export */
import { createSlice } from '@reduxjs/toolkit';
import { LoadingStatus } from '../../../data/constants';
function normaliseThreads(rawThreadsData) {
const topicThreadMap = {};
rawThreadsData.forEach(
thread => {
if (!topicThreadMap[thread.topic_id]) {
topicThreadMap[thread.topic_id] = [];
}
topicThreadMap[thread.topic_id].push(thread);
},
);
return topicThreadMap;
}
const courseThreadsSlice = createSlice({
name: 'courseThreads',
initialState: {
status: LoadingStatus.LOADING,
page: null,
threads: {
// Mapping of topic ids to threads in them
},
totalPages: null,
totalThreads: null,
},
reducers: {
fetchCourseThreadsRequest: (state) => {
state.status = LoadingStatus.LOADING;
},
fetchCourseThreadsSuccess: (state, { payload }) => {
state.status = LoadingStatus.LOADED;
state.threads = normaliseThreads(payload.results);
state.page = payload.pagination.page;
state.totalPages = payload.pagination.num_pages;
state.totalThreads = payload.pagination.count;
},
fetchCourseThreadsFailed: (state) => {
state.status = LoadingStatus.FAILED;
},
fetchCourseThreadsDenied: (state) => {
state.status = LoadingStatus.DENIED;
},
},
});
export const {
fetchCourseThreadsRequest,
fetchCourseThreadsSuccess,
fetchCourseThreadsFailed,
} = courseThreadsSlice.actions;
export const courseThreadsReducer = courseThreadsSlice.reducer;

View File

@@ -0,0 +1,17 @@
/* eslint-disable import/prefer-default-export */
import { logError } from '@edx/frontend-platform/logging';
import { getCourseThreads } from './api';
import { fetchCourseThreadsFailed, fetchCourseThreadsRequest, fetchCourseThreadsSuccess } from './slices';
export function fetchCourseThreads(courseId, topicIds) {
return async (dispatch) => {
try {
dispatch(fetchCourseThreadsRequest({ courseId }));
const data = await getCourseThreads(courseId, topicIds);
dispatch(fetchCourseThreadsSuccess(data));
} catch (error) {
dispatch(fetchCourseThreadsFailed());
logError(error);
}
};
}