181 lines
5.3 KiB
TypeScript
181 lines
5.3 KiB
TypeScript
import type {
|
|
CircleChild,
|
|
CircleCompletion,
|
|
CircleGoal,
|
|
CircleInterface,
|
|
CircleJobSituation,
|
|
LearningContent,
|
|
LearningSequence,
|
|
LearningUnit
|
|
} from '@/types';
|
|
|
|
|
|
function _createEmptyLearningUnit(parentLearningSequence: LearningSequence): LearningUnit {
|
|
return {
|
|
id: 0,
|
|
title: '',
|
|
slug: '',
|
|
translation_key: '',
|
|
type: 'learnpath.LearningUnit',
|
|
learningContents: [],
|
|
minutes: 0,
|
|
parentLearningSequence: parentLearningSequence,
|
|
children: [],
|
|
last: true,
|
|
};
|
|
}
|
|
|
|
export function parseLearningSequences (children: CircleChild[]): LearningSequence[] {
|
|
let learningSequence:LearningSequence | undefined;
|
|
let learningUnit:LearningUnit | undefined;
|
|
let learningContent:LearningContent | undefined;
|
|
let previousLearningContent: LearningContent | undefined;
|
|
const result:LearningSequence[] = [];
|
|
|
|
children.forEach((child) => {
|
|
if (child.type === 'learnpath.LearningSequence') {
|
|
if (learningSequence) {
|
|
if (learningUnit) {
|
|
learningUnit.last = true;
|
|
learningSequence.learningUnits.push(learningUnit);
|
|
}
|
|
result.push(learningSequence);
|
|
}
|
|
learningSequence = Object.assign(child, {learningUnits: []});
|
|
|
|
// initialize empty learning unit if there will not come a learning unit next
|
|
learningUnit = _createEmptyLearningUnit(learningSequence);
|
|
} else if (child.type === 'learnpath.LearningUnit') {
|
|
if (!learningSequence) {
|
|
throw new Error('LearningUnit found before LearningSequence');
|
|
}
|
|
|
|
if (learningUnit && learningUnit.learningContents.length) {
|
|
learningSequence.learningUnits.push(learningUnit);
|
|
}
|
|
|
|
learningUnit = Object.assign(child, {
|
|
learningContents: [],
|
|
parentLearningSequence: learningSequence,
|
|
children: child.children.map((c) => {
|
|
c.parentLearningUnit = learningUnit;
|
|
c.parentLearningSequence = learningSequence;
|
|
return c;
|
|
})
|
|
});
|
|
} else if (child.type === 'learnpath.LearningContent') {
|
|
if (!learningUnit) {
|
|
throw new Error('LearningContent found before LearningUnit');
|
|
}
|
|
previousLearningContent = learningContent;
|
|
|
|
learningContent = Object.assign(child, {
|
|
parentLearningSequence: learningSequence,
|
|
parentLearningUnit: learningUnit,
|
|
previousLearningContent: previousLearningContent,
|
|
});
|
|
|
|
if (previousLearningContent) {
|
|
previousLearningContent.nextLearningContent = learningContent;
|
|
}
|
|
|
|
learningUnit.learningContents.push(child);
|
|
}
|
|
});
|
|
|
|
if (learningUnit && learningSequence) {
|
|
// TypeScript does not get it here...
|
|
learningUnit.last = true;
|
|
(learningSequence as LearningSequence).learningUnits.push(learningUnit);
|
|
result.push(learningSequence);
|
|
} else {
|
|
throw new Error('Finished with LearningContent but there is no LearningSequence and LearningUnit');
|
|
}
|
|
|
|
// sum minutes
|
|
result.forEach((learningSequence) => {
|
|
learningSequence.minutes = 0;
|
|
learningSequence.learningUnits.forEach((learningUnit) => {
|
|
learningUnit.minutes = 0;
|
|
learningUnit.learningContents.forEach((learningContent) => {
|
|
learningUnit.minutes += learningContent.minutes;
|
|
});
|
|
learningSequence.minutes += learningUnit.minutes;
|
|
});
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
export class Circle implements CircleInterface {
|
|
readonly type = 'learnpath.Circle';
|
|
readonly learningSequences: LearningSequence[];
|
|
readonly completed: boolean;
|
|
|
|
constructor(
|
|
public readonly id: number,
|
|
public readonly slug: string,
|
|
public readonly title: string,
|
|
public readonly translation_key: string,
|
|
public description: string,
|
|
public children: CircleChild[],
|
|
public goals: CircleGoal[],
|
|
public job_situations: CircleJobSituation[],
|
|
) {
|
|
this.learningSequences = parseLearningSequences(this.children);
|
|
this.completed = false;
|
|
}
|
|
|
|
public static fromJson(json: any): Circle {
|
|
// TODO add error checking when the data does not conform to the schema
|
|
return new Circle(
|
|
json.id,
|
|
json.slug,
|
|
json.title,
|
|
json.translation_key,
|
|
json.description,
|
|
json.children,
|
|
json.goals,
|
|
json.job_situations,
|
|
)
|
|
}
|
|
|
|
public get flatChildren(): CircleChild[] {
|
|
const result: CircleChild[] = [];
|
|
this.learningSequences.forEach((learningSequence) => {
|
|
learningSequence.learningUnits.forEach((learningUnit) => {
|
|
learningUnit.children.forEach((learningUnitQuestion) => {
|
|
result.push(learningUnitQuestion);
|
|
})
|
|
learningUnit.learningContents.forEach((learningContent) => {
|
|
result.push(learningContent);
|
|
});
|
|
});
|
|
});
|
|
return result;
|
|
}
|
|
|
|
public someFinishedInLearningSequence(translationKey: string): boolean {
|
|
if (translationKey) {
|
|
return this.flatChildren.filter((lc) => {
|
|
return lc.completed && lc.parentLearningSequence?.translation_key === translationKey;
|
|
}).length > 0;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public parseCompletionData(completionData: CircleCompletion[]) {
|
|
this.flatChildren.forEach((page) => {
|
|
const pageIndex = completionData.findIndex((e) => {
|
|
return e.page_key === page.translation_key;
|
|
});
|
|
if (pageIndex >= 0) {
|
|
page.completed = completionData[pageIndex].completed;
|
|
} else {
|
|
page.completed = undefined;
|
|
}
|
|
});
|
|
}
|
|
}
|