feat: Sidebar refactor and add support for discussions sidebar. (#762)

squash!: remove unnecessary styling and migrate to bootstrap and other review feedback
This commit is contained in:
Kshitij Sobti
2022-03-07 19:26:05 +05:30
committed by GitHub
parent 1bbcc6d052
commit f004d0ab3c
46 changed files with 954 additions and 537 deletions

View File

@@ -0,0 +1,23 @@
/* eslint-disable import/prefer-default-export */
import { Factory } from 'rosie'; // eslint-disable-line import/no-extraneous-dependencies
Factory.define('discussionTopic')
.option('topicPrefix', null, '')
.option('courseId', null, 'course-v1:edX+DemoX+Demo_Course')
.sequence('id', ['topicPrefix'], (idx, topicPrefix) => `${topicPrefix}topic-${idx}`)
.sequence('name', ['topicPrefix'], (idx, topicPrefix) => `${topicPrefix}topic ${idx}`)
.sequence(
'usage_key',
['id', 'courseId'],
(idx, id, courseId) => `block-v1:${courseId.replace('course-v1:', '')}+type@vertical+block@${id}`,
)
.attr('enabled_in_context', null, true)
.attr('thread_counts', [], {
discussion: 0,
question: 0,
});
// Given a pre-build units state, build topics from it.
export function buildTopicsFromUnits(units) {
return Object.values(units).map(unit => Factory.build('discussionTopic', { usage_key: unit.id }));
}

View File

@@ -2,3 +2,4 @@ import './courseMetadata.factory';
import './sequenceMetadata.factory';
import './courseRecommendations.factory';
import './learningSequencesOutline.factory';
import './discussionTopics.factory';

View File

@@ -1,4 +1,4 @@
import { getConfig, camelCaseObject } from '@edx/frontend-platform';
import { camelCaseObject, getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient, getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { getTimeOffsetMillis } from '../../course-home/data/api';
import { appendBrowserTimezoneToUrl } from '../../utils';
@@ -71,7 +71,7 @@ export async function getSequenceForUnitDeprecated(courseId, unitId) {
url.searchParams.append('course_id', courseId);
url.searchParams.append('username', authenticatedUser ? authenticatedUser.username : '');
url.searchParams.append('depth', 3);
url.searchParams.append('requested_fields', 'children');
url.searchParams.append('requested_fields', 'children,discussions_url');
const { data } = await getAuthenticatedHttpClient().get(url.href, {});
const parent = Object.values(data.blocks).find(block => block.type === 'sequential' && block.children.includes(unitId));
@@ -227,8 +227,21 @@ export async function postIntegritySignature(courseId) {
);
return camelCaseObject(data);
}
export async function sendActivationEmail() {
const url = new URL(`${getConfig().LMS_BASE_URL}/api/send_account_activation_email`);
const { data } = await getAuthenticatedHttpClient().post(url.href, {});
return data;
}
export async function getCourseDiscussionConfig(courseId) {
const url = `${getConfig().LMS_BASE_URL}/api/discussion/v1/courses/${courseId}`;
const { data } = await getAuthenticatedHttpClient().get(url);
return data;
}
export async function getCourseTopics(courseId) {
const { data } = await getAuthenticatedHttpClient()
.get(`${getConfig().LMS_BASE_URL}/api/discussion/v2/course_topics/${courseId}`);
return camelCaseObject(data);
}

View File

@@ -1,24 +1,26 @@
import { logError, logInfo } from '@edx/frontend-platform/logging';
import { getCourseHomeCourseMetadata } from '../../course-home/data/api';
import {
addModel, addModelsMap, updateModel, updateModels, updateModelsMap,
} from '../../generic/model-store';
import {
getBlockCompletion,
getCourseDiscussionConfig,
getCourseMetadata,
getCourseTopics,
getLearningSequencesOutline,
getSequenceMetadata,
postIntegritySignature,
postSequencePosition,
} from './api';
import { getCourseHomeCourseMetadata } from '../../course-home/data/api';
import {
updateModel, addModel, updateModelsMap, addModelsMap, updateModels,
} from '../../generic/model-store';
import {
fetchCourseDenied,
fetchCourseFailure,
fetchCourseRequest,
fetchCourseSuccess,
fetchCourseFailure,
fetchCourseDenied,
fetchSequenceFailure,
fetchSequenceRequest,
fetchSequenceSuccess,
fetchSequenceFailure,
} from './slice';
export function fetchCourse(courseId) {
@@ -231,3 +233,23 @@ export function saveIntegritySignature(courseId, isMasquerading) {
}
};
}
export function getCourseDiscussionTopics(courseId) {
return async (dispatch) => {
try {
const config = await getCourseDiscussionConfig(courseId);
// Only load topics for the openedx provider, the legacy provider uses
// the xblock
if (config.provider === 'openedx') {
const topics = await getCourseTopics(courseId);
dispatch(updateModels({
modelType: 'discussionTopics',
models: topics,
idField: 'usageKey',
}));
}
} catch (error) {
logError(error);
}
};
}