129 lines
3.5 KiB
TypeScript
129 lines
3.5 KiB
TypeScript
import * as _ from "lodash";
|
|
|
|
import { Circle } from "@/services/circle";
|
|
import type {
|
|
CourseCompletion,
|
|
CourseCompletionStatus,
|
|
CourseWagtailPage,
|
|
LearningContent,
|
|
LearningPathChild,
|
|
Topic,
|
|
} from "@/types";
|
|
|
|
function getLastCompleted(courseId: number, completionData: CourseCompletion[]) {
|
|
return _.orderBy(completionData, ["updated_at"], "desc").find(
|
|
(c: CourseCompletion) => {
|
|
return (
|
|
c.completion_status === "success" &&
|
|
c.course === courseId &&
|
|
c.page_type === "learnpath.LearningContent"
|
|
);
|
|
}
|
|
);
|
|
}
|
|
|
|
export class LearningPath implements CourseWagtailPage {
|
|
readonly type = "learnpath.LearningPath";
|
|
public topics: Topic[];
|
|
public circles: Circle[];
|
|
public nextLearningContent?: LearningContent;
|
|
readonly completion_status: CourseCompletionStatus = "unknown";
|
|
|
|
public static fromJson(json: any, completionData: CourseCompletion[]): LearningPath {
|
|
return new LearningPath(
|
|
json.id,
|
|
json.slug,
|
|
json.course.title,
|
|
json.translation_key,
|
|
json.frontend_url,
|
|
json.course.id,
|
|
json.children,
|
|
completionData
|
|
);
|
|
}
|
|
|
|
constructor(
|
|
public readonly id: number,
|
|
public readonly slug: string,
|
|
public readonly title: string,
|
|
public readonly translation_key: string,
|
|
public readonly frontend_url: string,
|
|
public readonly courseId: number,
|
|
public children: LearningPathChild[],
|
|
completionData?: CourseCompletion[]
|
|
) {
|
|
// parse children
|
|
this.topics = [];
|
|
this.circles = [];
|
|
|
|
let topic: Topic | undefined;
|
|
|
|
this.children.forEach((page) => {
|
|
if (page.type === "learnpath.Topic") {
|
|
if (topic) {
|
|
this.topics.push(topic);
|
|
}
|
|
topic = Object.assign(page, { circles: [] });
|
|
}
|
|
if (page.type === "learnpath.Circle") {
|
|
const circle = Circle.fromJson(page, this);
|
|
if (completionData) {
|
|
circle.parseCompletionData(completionData);
|
|
}
|
|
if (topic) {
|
|
topic.circles.push(circle);
|
|
}
|
|
|
|
circle.previousCircle = this.circles[this.circles.length - 1];
|
|
if (circle.previousCircle) {
|
|
circle.previousCircle.nextCircle = circle;
|
|
}
|
|
this.circles.push(circle);
|
|
}
|
|
});
|
|
|
|
if (topic) {
|
|
this.topics.push(topic);
|
|
}
|
|
|
|
if (completionData) {
|
|
this.calcNextLearningContent(completionData);
|
|
}
|
|
}
|
|
|
|
public calcNextLearningContent(completionData: CourseCompletion[]): void {
|
|
this.nextLearningContent = undefined;
|
|
|
|
const lastCompletedLearningContent = getLastCompleted(
|
|
this.courseId,
|
|
completionData
|
|
);
|
|
|
|
if (lastCompletedLearningContent) {
|
|
const lastCircle = this.circles.find((circle) => {
|
|
return circle.flatLearningContents.find(
|
|
(learningContent) =>
|
|
learningContent.translation_key === lastCompletedLearningContent.page_key
|
|
);
|
|
});
|
|
if (lastCircle) {
|
|
const lastLearningContent = lastCircle.flatLearningContents.find(
|
|
(learningContent) =>
|
|
learningContent.translation_key === lastCompletedLearningContent.page_key
|
|
);
|
|
if (lastLearningContent && lastLearningContent.nextLearningContent) {
|
|
this.nextLearningContent = lastLearningContent.nextLearningContent;
|
|
} else {
|
|
if (lastCircle.nextCircle) {
|
|
this.nextLearningContent = lastCircle.nextCircle.flatLearningContents[0];
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (this.circles[0]) {
|
|
this.nextLearningContent = this.circles[0].flatLearningContents[0];
|
|
}
|
|
}
|
|
}
|
|
}
|