diff --git a/client/package.json b/client/package.json index 09806947..91a7c6e4 100644 --- a/client/package.json +++ b/client/package.json @@ -15,6 +15,7 @@ "@headlessui/vue": "^1.6.7", "axios": "^0.26.1", "d3": "^7.6.1", + "lodash": "^4.17.21", "loglevel": "^1.8.0", "pinia": "^2.0.21", "vue": "^3.2.38", diff --git a/client/src/services/circle.ts b/client/src/services/circle.ts index 09cd0e69..54e8eb46 100644 --- a/client/src/services/circle.ts +++ b/client/src/services/circle.ts @@ -24,7 +24,7 @@ function _createEmptyLearningUnit(parentLearningSequence: LearningSequence): Lea } } -export function parseLearningSequences (children: CircleChild[]): LearningSequence[] { +export function parseLearningSequences (circle: Circle, children: CircleChild[]): LearningSequence[] { let learningSequence:LearningSequence | undefined; let learningUnit:LearningUnit | undefined; let learningContent:LearningContent | undefined; @@ -69,6 +69,7 @@ export function parseLearningSequences (children: CircleChild[]): LearningSequen previousLearningContent = learningContent; learningContent = Object.assign(child, { + parentCircle: circle, parentLearningSequence: learningSequence, parentLearningUnit: learningUnit, previousLearningContent: previousLearningContent, @@ -111,6 +112,9 @@ export class Circle implements LearningWagtailPage { readonly learningSequences: LearningSequence[]; readonly completed: boolean; + nextCircle?: Circle; + previousCircle?: Circle; + constructor( public readonly id: number, public readonly slug: string, @@ -121,7 +125,7 @@ export class Circle implements LearningWagtailPage { public goals: CircleGoal[], public job_situations: CircleJobSituation[], ) { - this.learningSequences = parseLearningSequences(this.children); + this.learningSequences = parseLearningSequences(this, this.children); this.completed = false; } @@ -154,6 +158,18 @@ export class Circle implements LearningWagtailPage { return result; } + public get flatLearningContents(): LearningContent[] { + const result: LearningContent[] = []; + this.learningSequences.forEach((learningSequence) => { + learningSequence.learningUnits.forEach((learningUnit) => { + learningUnit.learningContents.forEach((learningContent) => { + result.push(learningContent); + }); + }); + }); + return result; + } + public someFinishedInLearningSequence(translationKey: string): boolean { if (translationKey) { return this.flatChildren.filter((lc) => { diff --git a/client/src/services/learningPath.ts b/client/src/services/learningPath.ts index b902c71e..1c7c45ae 100644 --- a/client/src/services/learningPath.ts +++ b/client/src/services/learningPath.ts @@ -1,10 +1,19 @@ -import type { LearningPathChild, LearningWagtailPage, Topic } from '@/types' +import * as _ from 'lodash' + +import type { CircleCompletion, LearningContent, LearningPathChild, LearningWagtailPage, Topic } from '@/types' import { Circle } from '@/services/circle' +function getLastCompleted(learningPathKey: string, completionData: CircleCompletion[]) { + return _.orderBy(completionData, ['updated_at'], 'desc').find((c: CircleCompletion) => { + return c.completed && c.learning_path_key === learningPathKey && c.page_type === 'learnpath.LearningContent' + }) +} + export class LearningPath implements LearningWagtailPage { readonly type = 'learnpath.LearningPath' public topics: Topic[] public circles: Circle[] + public nextLearningContent?: LearningContent public static fromJson(json: any, completionData: any): LearningPath { return new LearningPath(json.id, json.slug, json.title, json.translation_key, json.children, completionData) @@ -37,6 +46,11 @@ export class LearningPath implements LearningWagtailPage { 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) } }) @@ -44,5 +58,26 @@ export class LearningPath implements LearningWagtailPage { if (topic) { this.topics.push(topic) } + + // find next learning content + const lastCompletedLearningContent = getLastCompleted(this.translation_key, completionData); + + if (lastCompletedLearningContent) { + const lastCircle = this.circles.find(circle => circle.translation_key === lastCompletedLearningContent.circle_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 { + this.nextLearningContent = this.circles[0].flatLearningContents[0]; + } + + console.log('################# ', this.nextLearningContent); } } diff --git a/client/src/stores/learningPath.ts b/client/src/stores/learningPath.ts index 7b6ad0d4..9dcfb1a9 100644 --- a/client/src/stores/learningPath.ts +++ b/client/src/stores/learningPath.ts @@ -3,67 +3,16 @@ import * as log from 'loglevel' import { defineStore } from 'pinia' import { itGet } from '@/fetchHelpers' import { LearningPath } from '@/services/learningPath' -import {defineStore} from 'pinia' -import * as _ from 'lodash'; - -import type {LearningPath, Topic} from '@/types' -import {itGet} from '@/fetchHelpers'; -import {Circle} from '@/services/circle'; -import learningPathDiagram from "@/components/circle/LearningPathDiagram.vue"; export type LearningPathStoreState = { learningPath: LearningPath | undefined } - -function getLastCompleted(completionData: any) { - return _.filter(_.orderBy(completionData, ['updated_at'], 'desc'), c =>{return c.completed && c.page_type === "learnpath.LearningContent" })[0] -} - - -function getFirstLearningContent(lastCopleted, learningPathData) { - const circles = _.filter(learningPathData.children, {'type': 'learnpath.Circle'}) - - let currentCircle = Circle.fromJson(circles[0]) - const currentLearningUnit = currentCircle.flatChildren[0] - let currentLearningSequence = currentLearningUnit.parentLearningSequence - return [currentCircle, currentLearningSequence, currentLearningUnit] -} - -function getNextLearningContent(lastCopleted, learningPathData) { - - let currentCircle, currentLearningSequence, currentLearningUnit - - currentLearningUnit = getFirstLearningContent(lastCopleted, learningPathData) - - if (lastCopleted) { - const circles = _.filter(learningPathData.children, {'type': 'learnpath.Circle'}) - _.forEach(circles, circle => { - _.forEach(Circle.fromJson(circle).learningSequences, learningSequence => { - _.forEach(learningSequence.learningUnits, learningUnit => { - _.forEach(learningUnit.learningContents, content => { - if (lastCopleted.page_key === content.translation_key) { - currentCircle = Circle.fromJson(circle) - currentLearningSequence = learningSequence - currentLearningUnit = content - - } - }) - }) - }) - }) - currentLearningUnit = [currentCircle, currentLearningSequence, currentLearningUnit] - } - return currentLearningUnit -} - - export const useLearningPathStore = defineStore({ id: 'learningPath', state: () => { return { learningPath: undefined, - } as LearningPathStoreState; }, getters: {}, @@ -76,19 +25,7 @@ export const useLearningPathStore = defineStore({ const learningPathData = await itGet(`/learnpath/api/page/${slug}/`); const completionData = await itGet(`/api/completion/learning_path/${learningPathData.translation_key}/`); - this.learningPath = learningPathData; - - if (learningPathData) { - this.learningPath.lastCompleted = getLastCompleted(completionData) - const nextLearningContent = getNextLearningContent(this.learningPath.lastCompleted, learningPathData) - - console.log('nextLearningContent', nextLearningContent) - this.learningPath.nextCircle = nextLearningContent[0] - this.learningPath.nextLearningSequence = nextLearningContent[1] - this.learningPath.nextLearningUnit = nextLearningContent[2] - - this.learningPath = LearningPath.fromJson(learningPathData, completionData); } return this.learningPath; diff --git a/client/src/types.ts b/client/src/types.ts index b349af30..420c1984 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -59,6 +59,7 @@ export interface LearningContent extends LearningWagtailPage { type: 'learnpath.LearningContent'; minutes: number; contents: (LearningContentBlock | VideoBlock | PodcastBlock | DocumentBlock)[]; + parentCircle: Circle; parentLearningSequence?: LearningSequence; parentLearningUnit?: LearningUnit; nextLearningContent?: LearningContent; @@ -111,6 +112,7 @@ export interface CircleCompletion { page_key: string; page_type: string; circle_key: string; + learning_path_key: string; completed: boolean; json_data: any; } diff --git a/client/src/views/LearningPathView.vue b/client/src/views/LearningPathView.vue index d77d7470..ee0c80ec 100644 --- a/client/src/views/LearningPathView.vue +++ b/client/src/views/LearningPathView.vue @@ -2,7 +2,7 @@ import * as log from 'loglevel'; -import {computed, onMounted} from 'vue' +import {onMounted} from 'vue' import {useLearningPathStore} from '@/stores/learningPath'; import {useUserStore} from '@/stores/user'; @@ -20,10 +20,6 @@ const learningPathStore = useLearningPathStore(); const userStore = useUserStore(); -const continueRoute = computed(() => { - return "/circle/" + learningPathStore.learningPath.nextCircle.slug + "/"; -}) - onMounted(async () => { log.info('LearningPathView mounted'); await learningPathStore.loadLearningPath(props.learningPathSlug); @@ -72,10 +68,14 @@ onMounted(async () => {
-