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