Refactor learningPath loading
This commit is contained in:
parent
00c2217ad1
commit
2c17012686
|
|
@ -12,6 +12,10 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: "horizontal",
|
default: "horizontal",
|
||||||
},
|
},
|
||||||
|
postfix: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
learningPath: {
|
learningPath: {
|
||||||
required: true,
|
required: true,
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|
@ -25,7 +29,7 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
svgId() {
|
svgId() {
|
||||||
return `learningpath-diagram-${this.learningPath.slug}-${this.diagramType}`;
|
return `learningpath-diagram-${this.learningPath.slug}-${this.diagramType}${this.postfix}`;
|
||||||
},
|
},
|
||||||
viewBox() {
|
viewBox() {
|
||||||
return `0 0 ${this.width} ${this.height}`;
|
return `0 0 ${this.width} ${this.height}`;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { ref } from "vue";
|
||||||
log.debug("LearningPathDiagramSmall created");
|
log.debug("LearningPathDiagramSmall created");
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
learningPathUrl: string;
|
courseSlug: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const learningPathData = ref<LearningPath | undefined>(undefined);
|
const learningPathData = ref<LearningPath | undefined>(undefined);
|
||||||
|
|
@ -17,11 +17,7 @@ const learningPathData = ref<LearningPath | undefined>(undefined);
|
||||||
const learningPathStore = useLearningPathStore();
|
const learningPathStore = useLearningPathStore();
|
||||||
|
|
||||||
learningPathStore
|
learningPathStore
|
||||||
.loadLearningPath(
|
.loadLearningPath(props.courseSlug + "-lp", undefined, false, false)
|
||||||
props.learningPathUrl.replace(/\/learn$/, "-lp").replace(/^\/course\//, ""),
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
learningPathData.value = data;
|
learningPathData.value = data;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,29 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
|
|
||||||
import LearningPathDiagram from "@/components/learningPath/LearningPathDiagram.vue";
|
import LearningPathDiagram from "@/components/learningPath/LearningPathDiagram.vue";
|
||||||
import ItFullScreenModal from "@/components/ui/ItFullScreenModal.vue";
|
import ItFullScreenModal from "@/components/ui/ItFullScreenModal.vue";
|
||||||
|
import type { LearningPath } from "@/services/learningPath";
|
||||||
|
|
||||||
log.debug("LearningPathView created");
|
log.debug("LearningPathView created");
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
learningPathSlug: string;
|
learningPath: LearningPath | undefined;
|
||||||
show: boolean;
|
show: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const learningPathStore = useLearningPathStore();
|
|
||||||
|
|
||||||
const emits = defineEmits(["closemodal"]);
|
const emits = defineEmits(["closemodal"]);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<ItFullScreenModal :show="show" @closemodal="$emit('closemodal')">
|
<ItFullScreenModal :show="show" @closemodal="$emit('closemodal')">
|
||||||
<div v-if="learningPathStore.learningPath" class="container-medium">
|
<div v-if="learningPath" class="container-medium">
|
||||||
<h1>{{ learningPathStore.learningPath.title }}</h1>
|
<h1>{{ learningPath.title }}</h1>
|
||||||
<div class="learningpath flex flex-col">
|
<div class="learningpath flex flex-col">
|
||||||
<div class="flex flex-col h-max">
|
<div class="flex flex-col h-max">
|
||||||
<LearningPathDiagram
|
<LearningPathDiagram
|
||||||
v-if="learningPathStore.learningPath"
|
v-if="learningPath"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
:learning-path="learningPathStore.learningPath"
|
:learning-path="learningPath"
|
||||||
diagram-type="vertical"
|
diagram-type="vertical"
|
||||||
></LearningPathDiagram>
|
></LearningPathDiagram>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ onMounted(async () => {
|
||||||
<div>
|
<div>
|
||||||
<LearningPathDiagramSmall
|
<LearningPathDiagramSmall
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
:learning-path-url="courseSession.learning_path_url"
|
:course-slug="courseSession.course.slug"
|
||||||
></LearningPathDiagramSmall>
|
></LearningPathDiagramSmall>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
import { useCockpitStore } from "@/stores/cockpit";
|
||||||
import { useCompetenceStore } from "@/stores/competence";
|
import { useCompetenceStore } from "@/stores/competence";
|
||||||
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import { onMounted } from "vue";
|
import { onMounted } from "vue";
|
||||||
|
|
||||||
|
|
@ -12,6 +13,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
const cockpitStore = useCockpitStore();
|
const cockpitStore = useCockpitStore();
|
||||||
const competenceStore = useCompetenceStore();
|
const competenceStore = useCompetenceStore();
|
||||||
|
const learningPathStore = useLearningPathStore();
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.debug("CockpitParentPage mounted", props.courseSlug);
|
log.debug("CockpitParentPage mounted", props.courseSlug);
|
||||||
|
|
@ -23,6 +25,8 @@ onMounted(async () => {
|
||||||
props.courseSlug + "-competence",
|
props.courseSlug + "-competence",
|
||||||
csu.user_id
|
csu.user_id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
learningPathStore.loadLearningPath(props.courseSlug + "-lp", csu.user_id);
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(error);
|
log.error(error);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
import { useCockpitStore } from "@/stores/cockpit";
|
||||||
import { useCompetenceStore } from "@/stores/competence";
|
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import { onMounted } from "vue";
|
import { computed, onMounted } from "vue";
|
||||||
|
|
||||||
import LearningPathDiagram from "@/components/learningPath/LearningPathDiagram.vue";
|
import LearningPathDiagram from "@/components/learningPath/LearningPathDiagram.vue";
|
||||||
|
|
||||||
|
|
@ -15,23 +14,19 @@ const props = defineProps<{
|
||||||
log.debug("CockpitUserProfilePage created", props.userId);
|
log.debug("CockpitUserProfilePage created", props.userId);
|
||||||
|
|
||||||
const cockpitStore = useCockpitStore();
|
const cockpitStore = useCockpitStore();
|
||||||
const competenceStore = useCompetenceStore();
|
|
||||||
const learningPathStore = useLearningPathStore();
|
const learningPathStore = useLearningPathStore();
|
||||||
|
|
||||||
function userCountStatus(userId: number) {
|
|
||||||
return competenceStore.calcStatusCount(
|
|
||||||
competenceStore.flatPerformanceCriteria(userId)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.debug("CockpitUserProfilePage mounted");
|
log.debug("CockpitUserProfilePage mounted");
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
const learningPath = computed(() => {
|
||||||
await learningPathStore.loadLearningPath(props.courseSlug + "-lp");
|
if (learningPathStore.learningPaths.size > 0) {
|
||||||
} catch (error) {
|
const learningPathKey = `${props.courseSlug}-lp-${props.userId}`;
|
||||||
log.error(error);
|
return learningPathStore.learningPaths.get(learningPathKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
function courseSessionUser() {
|
function courseSessionUser() {
|
||||||
|
|
@ -50,11 +45,12 @@ function courseSessionUser() {
|
||||||
:src="courseSessionUser()?.avatar_url"
|
:src="courseSessionUser()?.avatar_url"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="learningPathStore.learningPath">
|
<div v-if="learningPath">
|
||||||
<LearningPathDiagram
|
<LearningPathDiagram
|
||||||
class="mx-auto max-w-[1920px] max-h-[90px] lg:max-h-[380px] w-full px-4"
|
class="mx-auto max-w-[1920px] max-h-[90px] lg:max-h-[380px] w-full px-4"
|
||||||
diagram-type="horizontal"
|
diagram-type="horizontal"
|
||||||
:learning-path="learningPathStore.learningPath"
|
:learning-path="learningPath"
|
||||||
|
:postfix="userId"
|
||||||
></LearningPathDiagram>
|
></LearningPathDiagram>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import * as log from "loglevel";
|
||||||
|
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import { onMounted } from "vue";
|
import { computed, onMounted } from "vue";
|
||||||
|
|
||||||
import LearningPathDiagram from "@/components/learningPath/LearningPathDiagram.vue";
|
import LearningPathDiagram from "@/components/learningPath/LearningPathDiagram.vue";
|
||||||
import LearningPathViewVertical from "@/components/learningPath/LearningPathViewVertical.vue";
|
import LearningPathViewVertical from "@/components/learningPath/LearningPathViewVertical.vue";
|
||||||
|
|
@ -18,6 +18,15 @@ const props = defineProps<{
|
||||||
const learningPathStore = useLearningPathStore();
|
const learningPathStore = useLearningPathStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
const learningPath = computed(() => {
|
||||||
|
if (userStore.loggedIn && learningPathStore.learningPaths.size > 0) {
|
||||||
|
const learningPathKey = `${props.courseSlug}-lp-${userStore.id}`;
|
||||||
|
return learningPathStore.learningPaths.get(learningPathKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.debug("LearningPathView mounted");
|
log.debug("LearningPathView mounted");
|
||||||
|
|
||||||
|
|
@ -29,7 +38,7 @@ onMounted(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const createContinueUrl = (learningPath: LearningPath): [string, boolean] => {
|
const createContinueUrl = (learningPath: LearningPath): [string, boolean] => {
|
||||||
if (learningPath.nextLearningContent) {
|
if (learningPath?.nextLearningContent) {
|
||||||
const circle = learningPath.nextLearningContent.parentCircle;
|
const circle = learningPath.nextLearningContent.parentCircle;
|
||||||
const url =
|
const url =
|
||||||
learningPath.nextLearningContent.parentLearningSequence?.frontend_url ||
|
learningPath.nextLearningContent.parentLearningSequence?.frontend_url ||
|
||||||
|
|
@ -45,11 +54,11 @@ const createContinueUrl = (learningPath: LearningPath): [string, boolean] => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="learningPathStore.learningPath" class="bg-gray-200">
|
<div v-if="learningPath" class="bg-gray-200">
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<LearningPathViewVertical
|
<LearningPathViewVertical
|
||||||
:show="learningPathStore.page === 'OVERVIEW'"
|
:show="learningPathStore.page === 'OVERVIEW'"
|
||||||
:learning-path-slug="props.courseSlug + '-lp'"
|
:learning-path="learningPath"
|
||||||
@closemodal="learningPathStore.page = 'INDEX'"
|
@closemodal="learningPathStore.page = 'INDEX'"
|
||||||
/>
|
/>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
|
|
@ -70,13 +79,13 @@ const createContinueUrl = (learningPath: LearningPath): [string, boolean] => {
|
||||||
<LearningPathDiagram
|
<LearningPathDiagram
|
||||||
class="mx-auto max-w-[1920px] max-h-[90px] lg:max-h-[380px] w-full px-4"
|
class="mx-auto max-w-[1920px] max-h-[90px] lg:max-h-[380px] w-full px-4"
|
||||||
diagram-type="horizontal"
|
diagram-type="horizontal"
|
||||||
:learning-path="learningPathStore.learningPath"
|
:learning-path="learningPath"
|
||||||
></LearningPathDiagram>
|
></LearningPathDiagram>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container-large pt-0 lg:pt-4">
|
<div class="container-large pt-0 lg:pt-4">
|
||||||
<h1 data-cy="learning-path-title" class="mt-6 lg:mt-12 mb-6">
|
<h1 data-cy="learning-path-title" class="mt-6 lg:mt-12 mb-6">
|
||||||
{{ learningPathStore.learningPath.title }}
|
{{ learningPath.title }}
|
||||||
</h1>
|
</h1>
|
||||||
<div
|
<div
|
||||||
class="bg-white p-4 lg:mb-16 flex flex-col lg:flex-row divide-y lg:divide-y-0 lg:divide-x divide-gray-500 justify-start"
|
class="bg-white p-4 lg:mb-16 flex flex-col lg:flex-row divide-y lg:divide-y-0 lg:divide-x divide-gray-500 justify-start"
|
||||||
|
|
@ -87,27 +96,19 @@ const createContinueUrl = (learningPath: LearningPath): [string, boolean] => {
|
||||||
</h2>
|
</h2>
|
||||||
<p class="mt-4 text-xl"></p>
|
<p class="mt-4 text-xl"></p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="learningPath.nextLearningContent" class="p-4 lg:p-8 flex-2">
|
||||||
v-if="learningPathStore.learningPath.nextLearningContent"
|
|
||||||
class="p-4 lg:p-8 flex-2"
|
|
||||||
>
|
|
||||||
{{ $t("learningPathPage.nextStep") }}
|
{{ $t("learningPathPage.nextStep") }}
|
||||||
<h3>
|
<h3>
|
||||||
{{
|
{{ learningPath.nextLearningContent.parentCircle.title }}:
|
||||||
learningPathStore.learningPath.nextLearningContent.parentCircle.title
|
{{ learningPath.nextLearningContent.parentLearningSequence?.title }}
|
||||||
}}:
|
|
||||||
{{
|
|
||||||
learningPathStore.learningPath.nextLearningContent
|
|
||||||
.parentLearningSequence?.title
|
|
||||||
}}
|
|
||||||
</h3>
|
</h3>
|
||||||
<router-link
|
<router-link
|
||||||
class="mt-4 btn-blue"
|
class="mt-4 btn-blue"
|
||||||
:to="createContinueUrl(learningPathStore.learningPath)[0]"
|
:to="createContinueUrl(learningPath)[0]"
|
||||||
data-cy="lp-continue-button"
|
data-cy="lp-continue-button"
|
||||||
translate
|
translate
|
||||||
>
|
>
|
||||||
<span v-if="createContinueUrl(learningPathStore.learningPath)[1]">
|
<span v-if="createContinueUrl(learningPath)[1]">
|
||||||
{{ $t("general.start") }}
|
{{ $t("general.start") }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else>{{ $t("general.nextStep") }}</span>
|
<span v-else>{{ $t("general.nextStep") }}</span>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import * as log from "loglevel";
|
||||||
import type { Circle } from "@/services/circle";
|
import type { Circle } from "@/services/circle";
|
||||||
import { useCompletionStore } from "@/stores/completion";
|
import { useCompletionStore } from "@/stores/completion";
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
|
import { useUserStore } from "@/stores/user";
|
||||||
import type {
|
import type {
|
||||||
CourseCompletionStatus,
|
CourseCompletionStatus,
|
||||||
LearningContent,
|
LearningContent,
|
||||||
|
|
@ -37,13 +38,25 @@ export const useCircleStore = defineStore({
|
||||||
},
|
},
|
||||||
getters: {},
|
getters: {},
|
||||||
actions: {
|
actions: {
|
||||||
async loadCircle(courseSlug: string, circleSlug: string): Promise<Circle> {
|
async loadCircle(
|
||||||
|
courseSlug: string,
|
||||||
|
circleSlug: string,
|
||||||
|
userId: number | undefined = undefined
|
||||||
|
): Promise<Circle> {
|
||||||
|
if (!userId) {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
userId = userStore.id;
|
||||||
|
}
|
||||||
|
|
||||||
this.circle = undefined;
|
this.circle = undefined;
|
||||||
const learningPathSlug = courseSlug + "-lp";
|
const learningPathSlug = courseSlug + "-lp";
|
||||||
const learningPathStore = useLearningPathStore();
|
const learningPathStore = useLearningPathStore();
|
||||||
await learningPathStore.loadLearningPath(learningPathSlug);
|
const learningPath = await learningPathStore.loadLearningPath(
|
||||||
if (learningPathStore.learningPath) {
|
learningPathSlug,
|
||||||
this.circle = learningPathStore.learningPath.circles.find((circle) => {
|
userId
|
||||||
|
);
|
||||||
|
if (learningPath) {
|
||||||
|
this.circle = learningPath.circles.find((circle) => {
|
||||||
return circle.slug.endsWith(circleSlug);
|
return circle.slug.endsWith(circleSlug);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ export const useCompetenceStore = defineStore({
|
||||||
userId = userStore.id;
|
userId = userStore.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.competenceProfilePages.get(userId) && !reload) {
|
if (this.competenceProfilePages.has(userId) && !reload) {
|
||||||
const competenceProfilePage = this.competenceProfilePages.get(userId);
|
const competenceProfilePage = this.competenceProfilePages.get(userId);
|
||||||
await this.parseCompletionData(userId);
|
await this.parseCompletionData(userId);
|
||||||
return competenceProfilePage;
|
return competenceProfilePage;
|
||||||
|
|
|
||||||
|
|
@ -2,52 +2,60 @@ import { itGetCached } from "@/fetchHelpers";
|
||||||
import { LearningPath } from "@/services/learningPath";
|
import { LearningPath } from "@/services/learningPath";
|
||||||
import { useCompletionStore } from "@/stores/completion";
|
import { useCompletionStore } from "@/stores/completion";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
|
import _ from "lodash";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
export type LearningPathStoreState = {
|
export type LearningPathStoreState = {
|
||||||
learningPath: LearningPath | undefined;
|
learningPaths: Map<string, LearningPath>;
|
||||||
page: "INDEX" | "OVERVIEW";
|
|
||||||
loading: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
let lastSlug = "";
|
page: "INDEX" | "OVERVIEW";
|
||||||
|
};
|
||||||
|
|
||||||
export const useLearningPathStore = defineStore({
|
export const useLearningPathStore = defineStore({
|
||||||
id: "learningPath",
|
id: "learningPath",
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
learningPath: undefined,
|
learningPaths: new Map<string, LearningPath>(),
|
||||||
page: "INDEX",
|
page: "INDEX",
|
||||||
loading: false,
|
loading: false,
|
||||||
} as LearningPathStoreState;
|
} as LearningPathStoreState;
|
||||||
},
|
},
|
||||||
getters: {},
|
getters: {},
|
||||||
actions: {
|
actions: {
|
||||||
async loadLearningPath(slug: string, reload = false, fail = true) {
|
async loadLearningPath(
|
||||||
this.loading = true;
|
slug: string,
|
||||||
const completionStore = useCompletionStore();
|
userId: number | undefined = undefined,
|
||||||
if (this.learningPath && !reload && slug === lastSlug) {
|
reload = false,
|
||||||
return this.learningPath;
|
fail = true
|
||||||
|
) {
|
||||||
|
if (!userId) {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
userId = userStore.id;
|
||||||
}
|
}
|
||||||
this.learningPath = undefined;
|
|
||||||
const learningPathData = await itGetCached(`/api/course/page/${slug}/`);
|
|
||||||
|
|
||||||
|
const key = `${slug}-${userId}`;
|
||||||
|
|
||||||
|
if (this.learningPaths.has(key) && !reload) {
|
||||||
|
return this.learningPaths.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
const learningPathData = await itGetCached(`/api/course/page/${slug}/`);
|
||||||
if (!learningPathData && fail) {
|
if (!learningPathData && fail) {
|
||||||
throw `No learning path found with: ${slug}`;
|
throw `No learning path found with: ${slug}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const completionStore = useCompletionStore();
|
||||||
if (learningPathData && userStore.loggedIn) {
|
const completionData = await completionStore.loadCompletionData(
|
||||||
lastSlug = slug;
|
learningPathData.course.id,
|
||||||
const completionData = await completionStore.loadCompletionData(
|
userId
|
||||||
learningPathData.course.id,
|
);
|
||||||
userStore.id
|
|
||||||
);
|
|
||||||
|
|
||||||
this.learningPath = LearningPath.fromJson(learningPathData, completionData);
|
const learningPath = LearningPath.fromJson(
|
||||||
this.loading = false;
|
_.cloneDeep(learningPathData),
|
||||||
return this.learningPath;
|
completionData
|
||||||
}
|
);
|
||||||
|
this.learningPaths.set(key, learningPath);
|
||||||
|
return learningPath;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,7 @@ export interface Course {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
category_name: string;
|
category_name: string;
|
||||||
|
slug: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CourseCategory {
|
export interface CourseCategory {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue