feat: Created Course updates page (#581)
This commit is contained in:
84
src/course-updates/data/api.js
Normal file
84
src/course-updates/data/api.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL;
|
||||
export const getCourseUpdatesApiUrl = (courseId) => `${getApiBaseUrl()}/course_info_update/${courseId}/`;
|
||||
export const updateCourseUpdatesApiUrl = (courseId, updateId) => `${getApiBaseUrl()}/course_info_update/${courseId}/${updateId}`;
|
||||
export const getCourseHandoutApiUrl = (courseId) => {
|
||||
const formattedCourseId = courseId.split('course-v1:')[1];
|
||||
return `${getApiBaseUrl()}/xblock/block-v1:${formattedCourseId}+type@course_info+block@handouts`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get course updates.
|
||||
* @param {string} courseId
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function getCourseUpdates(courseId) {
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.get(getCourseUpdatesApiUrl(courseId));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new course update.
|
||||
* @param {string} courseId
|
||||
* @param {object} courseUpdate
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function createUpdate(courseId, courseUpdate) {
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.post(getCourseUpdatesApiUrl(courseId), courseUpdate);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit course update.
|
||||
* @param {string} courseId
|
||||
* @param {object} courseUpdate
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function editUpdate(courseId, courseUpdate) {
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.put(updateCourseUpdatesApiUrl(courseId, courseUpdate.id), courseUpdate);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete course update.
|
||||
* @param {string} courseId
|
||||
* @param {number} updateId
|
||||
1 */
|
||||
export async function deleteUpdate(courseId, updateId) {
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.delete(updateCourseUpdatesApiUrl(courseId, updateId));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get course handouts.
|
||||
* @param {string} courseId
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function getCourseHandouts(courseId) {
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.get(getCourseHandoutApiUrl(courseId));
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit course handouts.
|
||||
* @param {string} courseId
|
||||
* @param {object} courseHandouts
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function editHandouts(courseId, courseHandouts) {
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.put(getCourseHandoutApiUrl(courseId), courseHandouts);
|
||||
|
||||
return data;
|
||||
}
|
||||
4
src/course-updates/data/selectors.js
Normal file
4
src/course-updates/data/selectors.js
Normal file
@@ -0,0 +1,4 @@
|
||||
export const getCourseUpdates = (state) => state.courseUpdates.courseUpdates;
|
||||
export const getCourseHandouts = (state) => state.courseUpdates.courseHandouts;
|
||||
export const getSavingStatuses = (state) => state.courseUpdates.savingStatuses;
|
||||
export const getLoadingStatuses = (state) => state.courseUpdates.loadingStatuses;
|
||||
72
src/course-updates/data/slice.js
Normal file
72
src/course-updates/data/slice.js
Normal file
@@ -0,0 +1,72 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import { sortBy } from 'lodash';
|
||||
|
||||
const initialState = {
|
||||
courseUpdates: [],
|
||||
courseHandouts: {},
|
||||
savingStatuses: {
|
||||
createCourseUpdateQuery: '',
|
||||
editCourseUpdateQuery: '',
|
||||
deleteCourseUpdateQuery: '',
|
||||
editCourseHandoutsQuery: '',
|
||||
},
|
||||
loadingStatuses: {
|
||||
fetchCourseUpdatesQuery: '',
|
||||
fetchCourseHandoutsQuery: '',
|
||||
},
|
||||
};
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'courseUpdates',
|
||||
initialState,
|
||||
reducers: {
|
||||
fetchCourseUpdatesSuccess: (state, { payload }) => {
|
||||
state.courseUpdates = payload;
|
||||
},
|
||||
createCourseUpdate: (state, { payload }) => {
|
||||
state.courseUpdates = [payload, ...state.courseUpdates];
|
||||
},
|
||||
editCourseUpdate: (state, { payload }) => {
|
||||
state.courseUpdates = state.courseUpdates.map((courseUpdate) => {
|
||||
if (courseUpdate.id === payload.id) {
|
||||
return payload;
|
||||
}
|
||||
return courseUpdate;
|
||||
});
|
||||
},
|
||||
deleteCourseUpdate: (state, { payload }) => {
|
||||
state.courseUpdates = sortBy(payload, 'id').reverse();
|
||||
},
|
||||
fetchCourseHandoutsSuccess: (state, { payload }) => {
|
||||
state.courseHandouts = payload;
|
||||
},
|
||||
editCourseHandouts: (state, { payload }) => {
|
||||
state.courseHandouts = {
|
||||
...state.courseHandouts,
|
||||
...payload,
|
||||
};
|
||||
},
|
||||
updateSavingStatuses: (state, { payload }) => {
|
||||
state.savingStatuses = { ...state.savingStatuses, ...payload };
|
||||
},
|
||||
updateLoadingStatuses: (state, { payload }) => {
|
||||
state.loadingStatuses = { ...state.loadingStatuses, ...payload };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
fetchCourseUpdatesSuccess,
|
||||
createCourseUpdate,
|
||||
editCourseUpdate,
|
||||
deleteCourseUpdate,
|
||||
fetchCourseHandoutsSuccess,
|
||||
editCourseHandouts,
|
||||
updateSavingStatuses,
|
||||
updateLoadingStatuses,
|
||||
} = slice.actions;
|
||||
|
||||
export const {
|
||||
reducer,
|
||||
} = slice;
|
||||
111
src/course-updates/data/thunk.js
Normal file
111
src/course-updates/data/thunk.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import { NOTIFICATION_MESSAGES } from '../../constants';
|
||||
import { RequestStatus } from '../../data/constants';
|
||||
import { hideProcessingNotification, showProcessingNotification } from '../../generic/processing-notification/data/slice';
|
||||
import {
|
||||
getCourseUpdates,
|
||||
getCourseHandouts,
|
||||
createUpdate,
|
||||
editUpdate,
|
||||
deleteUpdate,
|
||||
editHandouts,
|
||||
} from './api';
|
||||
import {
|
||||
fetchCourseUpdatesSuccess,
|
||||
createCourseUpdate,
|
||||
editCourseUpdate,
|
||||
deleteCourseUpdate,
|
||||
fetchCourseHandoutsSuccess,
|
||||
editCourseHandouts,
|
||||
updateLoadingStatuses,
|
||||
updateSavingStatuses,
|
||||
} from './slice';
|
||||
|
||||
export function fetchCourseUpdatesQuery(courseId) {
|
||||
return async (dispatch) => {
|
||||
try {
|
||||
dispatch(updateLoadingStatuses({ fetchCourseHandoutsQuery: RequestStatus.IN_PROGRESS }));
|
||||
const courseUpdates = await getCourseUpdates(courseId);
|
||||
dispatch(fetchCourseUpdatesSuccess(courseUpdates));
|
||||
dispatch(updateLoadingStatuses({ fetchCourseHandoutsQuery: RequestStatus.SUCCESSFUL }));
|
||||
} catch (error) {
|
||||
dispatch(updateLoadingStatuses({ fetchCourseHandoutsQuery: RequestStatus.FAILED }));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createCourseUpdateQuery(courseId, data) {
|
||||
return async (dispatch) => {
|
||||
try {
|
||||
dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.PENDING }));
|
||||
dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.saving));
|
||||
const courseUpdate = await createUpdate(courseId, data);
|
||||
dispatch(createCourseUpdate(courseUpdate));
|
||||
dispatch(hideProcessingNotification());
|
||||
dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.SUCCESSFUL }));
|
||||
} catch (error) {
|
||||
dispatch(hideProcessingNotification());
|
||||
dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.FAILED }));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function editCourseUpdateQuery(courseId, data) {
|
||||
return async (dispatch) => {
|
||||
try {
|
||||
dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.PENDING }));
|
||||
dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.saving));
|
||||
const courseUpdate = await editUpdate(courseId, data);
|
||||
dispatch(editCourseUpdate(courseUpdate));
|
||||
dispatch(hideProcessingNotification());
|
||||
dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.SUCCESSFUL }));
|
||||
} catch (error) {
|
||||
dispatch(hideProcessingNotification());
|
||||
dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.FAILED }));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteCourseUpdateQuery(courseId, updateId) {
|
||||
return async (dispatch) => {
|
||||
try {
|
||||
dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.PENDING }));
|
||||
dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.deleting));
|
||||
const courseUpdates = await deleteUpdate(courseId, updateId);
|
||||
dispatch(deleteCourseUpdate(courseUpdates));
|
||||
dispatch(hideProcessingNotification());
|
||||
dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.SUCCESSFUL }));
|
||||
} catch (error) {
|
||||
dispatch(hideProcessingNotification());
|
||||
dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.FAILED }));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchCourseHandoutsQuery(courseId) {
|
||||
return async (dispatch) => {
|
||||
try {
|
||||
dispatch(updateLoadingStatuses({ fetchCourseHandoutsQuery: RequestStatus.IN_PROGRESS }));
|
||||
const courseHandouts = await getCourseHandouts(courseId);
|
||||
dispatch(fetchCourseHandoutsSuccess(courseHandouts));
|
||||
dispatch(updateLoadingStatuses({ fetchCourseHandoutsQuery: RequestStatus.SUCCESSFUL }));
|
||||
} catch (error) {
|
||||
dispatch(updateLoadingStatuses({ fetchCourseHandoutsQuery: RequestStatus.FAILED }));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function editCourseHandoutsQuery(courseId, data) {
|
||||
return async (dispatch) => {
|
||||
try {
|
||||
dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.PENDING }));
|
||||
dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.saving));
|
||||
const courseHandouts = await editHandouts(courseId, data);
|
||||
dispatch(editCourseHandouts(courseHandouts));
|
||||
dispatch(hideProcessingNotification());
|
||||
dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.SUCCESSFUL }));
|
||||
} catch (error) {
|
||||
dispatch(hideProcessingNotification());
|
||||
dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.FAILED }));
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user