Improving file organization.
This commit is contained in:
16
src/learning-sequence/data/api.js
Normal file
16
src/learning-sequence/data/api.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
export async function getCourseBlocks(courseId, username) {
|
||||
const url = new URL(`${getConfig().LMS_BASE_URL}/api/courses/v2/blocks/`);
|
||||
url.searchParams.append('course_id', decodeURIComponent(courseId));
|
||||
url.searchParams.append('username', username);
|
||||
url.searchParams.append('depth', 3);
|
||||
url.searchParams.append('requested_fields', 'children');
|
||||
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.get(url.href, {});
|
||||
|
||||
return data;
|
||||
}
|
||||
114
src/learning-sequence/data/hooks.js
Normal file
114
src/learning-sequence/data/hooks.js
Normal file
@@ -0,0 +1,114 @@
|
||||
import { useContext, useMemo, useState, useEffect } from 'react';
|
||||
import { AppContext } from '@edx/frontend-platform/react';
|
||||
|
||||
import CourseStructureContext from '../CourseStructureContext';
|
||||
import { getCourseBlocks } from './api';
|
||||
import { findBlockAncestry, createBlocksMap, createSubSectionIdList, createUnitIdList } from './utils';
|
||||
|
||||
export function useBlockAncestry(blockId) {
|
||||
const { blocks, loaded } = useContext(CourseStructureContext);
|
||||
return useMemo(() => {
|
||||
if (!loaded) {
|
||||
return [];
|
||||
}
|
||||
return findBlockAncestry(
|
||||
blocks,
|
||||
blockId,
|
||||
);
|
||||
}, [blocks, blockId, loaded]);
|
||||
}
|
||||
|
||||
export function useCourseStructure(courseId) {
|
||||
const { authenticatedUser } = useContext(AppContext);
|
||||
|
||||
const [blocks, setBlocks] = useState(null);
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [courseBlockId, setCourseBlockId] = useState();
|
||||
|
||||
useEffect(() => {
|
||||
setLoaded(false);
|
||||
getCourseBlocks(courseId, authenticatedUser.username).then((blocksData) => {
|
||||
setBlocks(createBlocksMap(blocksData.blocks));
|
||||
setCourseBlockId(blocksData.root);
|
||||
setLoaded(true);
|
||||
});
|
||||
}, [courseId]);
|
||||
|
||||
return {
|
||||
blocks, loaded, courseBlockId,
|
||||
};
|
||||
}
|
||||
|
||||
export function useCurrentCourse() {
|
||||
const { loaded, courseBlockId, blocks } = useContext(CourseStructureContext);
|
||||
|
||||
return loaded ? blocks[courseBlockId] : null;
|
||||
}
|
||||
|
||||
export function useCurrentSubSection() {
|
||||
const { loaded, blocks, subSectionId } = useContext(CourseStructureContext);
|
||||
|
||||
return loaded ? blocks[subSectionId] : null;
|
||||
}
|
||||
|
||||
export function useCurrentSection() {
|
||||
const { loaded, blocks } = useContext(CourseStructureContext);
|
||||
const subSection = useCurrentSubSection();
|
||||
return loaded ? blocks[subSection.parentId] : null;
|
||||
}
|
||||
|
||||
export function useCurrentUnit() {
|
||||
const { loaded, blocks, unitId } = useContext(CourseStructureContext);
|
||||
|
||||
return loaded ? blocks[unitId] : null;
|
||||
}
|
||||
|
||||
|
||||
export function useUnitIds() {
|
||||
const { loaded, blocks, courseBlockId } = useContext(CourseStructureContext);
|
||||
|
||||
return useMemo(
|
||||
() => (loaded ? createUnitIdList(blocks, courseBlockId) : []),
|
||||
[loaded, blocks, courseBlockId],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export function usePreviousUnit() {
|
||||
const { loaded, blocks, unitId } = useContext(CourseStructureContext);
|
||||
const unitIds = useUnitIds();
|
||||
|
||||
const currentUnitIndex = unitIds.indexOf(unitId);
|
||||
if (currentUnitIndex === 0) {
|
||||
return null;
|
||||
}
|
||||
return loaded ? blocks[unitIds[currentUnitIndex - 1]] : null;
|
||||
}
|
||||
|
||||
export function useNextUnit() {
|
||||
const { loaded, blocks, unitId } = useContext(CourseStructureContext);
|
||||
const unitIds = useUnitIds();
|
||||
|
||||
const currentUnitIndex = unitIds.indexOf(unitId);
|
||||
if (currentUnitIndex === unitIds.length - 1) {
|
||||
return null;
|
||||
}
|
||||
return loaded ? blocks[unitIds[currentUnitIndex + 1]] : null;
|
||||
}
|
||||
|
||||
export function useCurrentSubSectionUnits() {
|
||||
const { blocks } = useContext(CourseStructureContext);
|
||||
const subSection = useCurrentSubSection();
|
||||
return subSection.children.map(id => blocks[id]);
|
||||
}
|
||||
|
||||
export function useSubSectionIdList() {
|
||||
const { loaded, blocks, courseBlockId } = useContext(CourseStructureContext);
|
||||
|
||||
const subSectionIdList = useMemo(
|
||||
() => (loaded ? createSubSectionIdList(blocks, courseBlockId) : []),
|
||||
[blocks, courseBlockId],
|
||||
);
|
||||
|
||||
return subSectionIdList;
|
||||
}
|
||||
67
src/learning-sequence/data/utils.js
Normal file
67
src/learning-sequence/data/utils.js
Normal file
@@ -0,0 +1,67 @@
|
||||
/* eslint-disable no-plusplus */
|
||||
import { camelCaseObject } from '@edx/frontend-platform';
|
||||
|
||||
export function createBlocksMap(blocksData) {
|
||||
const blocks = {};
|
||||
const blocksList = Object.values(blocksData);
|
||||
|
||||
// First go through the list and flesh out our blocks map, camelCasing the objects as we go.
|
||||
for (let i = 0; i < blocksList.length; i++) {
|
||||
const block = blocksList[i];
|
||||
blocks[block.id] = camelCaseObject(block);
|
||||
}
|
||||
|
||||
// Next go through the blocksList again - now that we've added them all to the blocks map - and
|
||||
// append a parent ID to every child found in every `children` list, using the blocks map to find
|
||||
// them.
|
||||
for (let i = 0; i < blocksList.length; i++) {
|
||||
const block = blocksList[i];
|
||||
|
||||
if (Array.isArray(block.children)) {
|
||||
for (let j = 0; j < block.children.length; j++) {
|
||||
const childId = block.children[j];
|
||||
const child = blocks[childId];
|
||||
child.parentId = block.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
export function createSubSectionIdList(blocks, entryPointId, subSections = []) {
|
||||
const block = blocks[entryPointId];
|
||||
if (block.type === 'sequential') {
|
||||
subSections.push(block.id);
|
||||
}
|
||||
if (Array.isArray(block.children)) {
|
||||
for (let i = 0; i < block.children.length; i++) {
|
||||
const childId = block.children[i];
|
||||
createSubSectionIdList(blocks, childId, subSections);
|
||||
}
|
||||
}
|
||||
return subSections;
|
||||
}
|
||||
|
||||
export function createUnitIdList(blocks, entryPointId, units = []) {
|
||||
const block = blocks[entryPointId];
|
||||
if (block.type === 'vertical') {
|
||||
units.push(block.id);
|
||||
}
|
||||
if (Array.isArray(block.children)) {
|
||||
for (let i = 0; i < block.children.length; i++) {
|
||||
const childId = block.children[i];
|
||||
createUnitIdList(blocks, childId, units);
|
||||
}
|
||||
}
|
||||
return units;
|
||||
}
|
||||
|
||||
export function findBlockAncestry(blocks, blockId, descendents = []) {
|
||||
const block = blocks[blockId];
|
||||
descendents.unshift(block);
|
||||
if (block.parentId === undefined) {
|
||||
return descendents;
|
||||
}
|
||||
return findBlockAncestry(blocks, block.parentId, descendents);
|
||||
}
|
||||
Reference in New Issue
Block a user