Load stuff

This commit is contained in:
Daniel Egger 2023-10-12 18:38:14 +02:00
parent 8621d4af07
commit 8544898bbf
9 changed files with 88 additions and 96 deletions

View File

@ -1,15 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
import LearningPathCircle from "@/pages/learningPath/learningPathPage/LearningPathCircle.vue"; import LearningPathCircle from "@/pages/learningPath/learningPathPage/LearningPathCircle.vue";
import { calculateCircleSectorData } from "@/pages/learningPath/learningPathPage/utils"; import { calculateCircleSectorData } from "@/pages/learningPath/learningPathPage/utils";
import type { LearningPath } from "@/services/learningPath";
import { computed } from "vue"; import { computed } from "vue";
import type { LearningPathType } from "@/types";
import { flatCircles } from "@/composables";
export type DiagramType = "horizontal" | "horizontalSmall" | "singleSmall"; export type DiagramType = "horizontal" | "horizontalSmall" | "singleSmall";
export interface Props { export interface Props {
diagramType?: DiagramType; diagramType?: DiagramType;
learningPath: LearningPath; learningPath: LearningPathType;
// set to undefined (default) to show all circles
showCircleSlugs?: string[]; showCircleSlugs?: string[];
} }
@ -20,11 +20,11 @@ const props = withDefaults(defineProps<Props>(), {
const circles = computed(() => { const circles = computed(() => {
if (props.showCircleSlugs?.length) { if (props.showCircleSlugs?.length) {
return props.learningPath.circles.filter( return flatCircles(props.learningPath).filter(
(c) => props.showCircleSlugs?.includes(c.slug) ?? true (c) => props.showCircleSlugs?.includes(c.slug) ?? true
); );
} }
return props.learningPath.circles; return flatCircles(props.learningPath);
}); });
const wrapperClasses = computed(() => { const wrapperClasses = computed(() => {

View File

@ -1,31 +1,25 @@
<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 type { LearningPath } from "@/services/learningPath"; import { useLearningPathWithCompletion } from "@/composables";
import { ref } from "vue";
log.debug("LearningPathDiagramSmall created"); log.debug("LearningPathDiagramSmall created");
const props = defineProps<{ const props = defineProps<{
courseSlug: string; courseSlug: string;
courseSessionId: string;
}>(); }>();
const learningPathData = ref<LearningPath | undefined>(undefined); const lpQueryResult = useLearningPathWithCompletion(
props.courseSlug,
const learningPathStore = useLearningPathStore(); props.courseSessionId
);
learningPathStore
.loadLearningPath(props.courseSlug + "-lp", undefined, false, false)
.then((data) => {
learningPathData.value = data;
});
</script> </script>
<template> <template>
<LearningPathDiagram <LearningPathDiagram
v-if="learningPathData" v-if="lpQueryResult.learningPath.value"
:learning-path="learningPathData" :learning-path="lpQueryResult.learningPath.value"
diagram-type="horizontalSmall" diagram-type="horizontalSmall"
></LearningPathDiagram> ></LearningPathDiagram>
</template> </template>

View File

@ -1,5 +1,5 @@
import { COURSE_SESSION_DETAIL_QUERY, LEARNING_PATH_QUERY } from "@/graphql/queries"; import { COURSE_SESSION_DETAIL_QUERY, LEARNING_PATH_QUERY } from "@/graphql/queries";
import { circleFlatChildren } from "@/services/circle"; import { circleFlatChildren, circleFlatLearningContents } from "@/services/circle";
import { useCompletionStore } from "@/stores/completion"; import { useCompletionStore } from "@/stores/completion";
import { useCourseSessionsStore } from "@/stores/courseSessions"; import { useCourseSessionsStore } from "@/stores/courseSessions";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
@ -133,6 +133,10 @@ export function useCourseSessionDetailQuery(courSessionId?: string) {
}; };
} }
export function flatCircles(learningPath: LearningPathType) {
return learningPath.topics.flatMap((t) => t.circles);
}
export function useLearningPathQuery(courseSlug: string) { export function useLearningPathQuery(courseSlug: string) {
const queryResult = useQuery({ const queryResult = useQuery({
query: LEARNING_PATH_QUERY, query: LEARNING_PATH_QUERY,
@ -147,7 +151,7 @@ export function useLearningPathQuery(courseSlug: string) {
const circles = computed(() => { const circles = computed(() => {
if (learningPath.value) { if (learningPath.value) {
return learningPath.value.topics.flatMap((t) => t.circles); return flatCircles(learningPath.value);
} }
return undefined; return undefined;
}); });
@ -158,7 +162,20 @@ export function useLearningPathQuery(courseSlug: string) {
}); });
} }
return { ...queryResult, learningPath, circles, findCircle }; const dataLoaded = ref(false);
function waitForData() {
return new Promise((resolve) => {
watchEffect(() => {
if (queryResult.data.value) {
dataLoaded.value = true;
resolve(queryResult.data.value);
}
});
});
}
return { ...queryResult, waitForData, learningPath, circles, findCircle };
} }
export function useLearningPathWithCompletion( export function useLearningPathWithCompletion(
@ -178,6 +195,7 @@ export function useLearningPathWithCompletion(
const lpQueryResult = useLearningPathQuery(courseSlug); const lpQueryResult = useLearningPathQuery(courseSlug);
const completionStore = useCompletionStore(); const completionStore = useCompletionStore();
const nextLearningContent = ref<LearningContentWithCompletion | null>(null);
function updateCompletionData() { function updateCompletionData() {
if (userId && courseSessionId) { if (userId && courseSessionId) {
@ -209,6 +227,13 @@ export function useLearningPathWithCompletion(
}); });
}); });
} }
// FIXME calculate nextLearningContent
if (lpQueryResult.circles.value?.length) {
nextLearningContent.value = circleFlatLearningContents(
lpQueryResult.circles.value[0]
)[0];
}
} }
async function markCompletion( async function markCompletion(
@ -226,5 +251,10 @@ export function useLearningPathWithCompletion(
} }
} }
return { ...lpQueryResult, updateCompletionData, markCompletion }; return {
...lpQueryResult,
updateCompletionData,
markCompletion,
nextLearningContent,
};
} }

View File

@ -50,6 +50,7 @@ const getNextStepLink = (courseSession: CourseSession) => {
<LearningPathDiagramSmall <LearningPathDiagramSmall
class="mb-4" class="mb-4"
:course-slug="courseSession.course.slug" :course-slug="courseSession.course.slug"
:course-session-id="courseSession.id"
></LearningPathDiagramSmall> ></LearningPathDiagramSmall>
</div> </div>
<div> <div>

View File

@ -1,11 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import LearningPathCircleListTile from "@/pages/learningPath/learningPathPage/LearningPathCircleListTile.vue"; import LearningPathCircleListTile from "@/pages/learningPath/learningPathPage/LearningPathCircleListTile.vue";
import type { OldCircle } from "@/services/oldCircle"; import type { OldCircle } from "@/services/oldCircle";
import type { LearningPath } from "@/services/learningPath";
import { computed } from "vue"; import { computed } from "vue";
import type { LearningPathType } from "@/types";
const props = defineProps<{ const props = defineProps<{
learningPath: LearningPath | undefined; learningPath: LearningPathType | undefined;
}>(); }>();
const topics = computed(() => props.learningPath?.topics ?? []); const topics = computed(() => props.learningPath?.topics ?? []);

View File

@ -6,19 +6,16 @@ import CircleProgress from "@/pages/learningPath/learningPathPage/LearningPathPr
import LearningPathTopics from "@/pages/learningPath/learningPathPage/LearningPathTopics.vue"; import LearningPathTopics from "@/pages/learningPath/learningPathPage/LearningPathTopics.vue";
import type { ViewType } from "@/pages/learningPath/learningPathPage/LearningPathViewSwitch.vue"; import type { ViewType } from "@/pages/learningPath/learningPathPage/LearningPathViewSwitch.vue";
import LearningPathViewSwitch from "@/pages/learningPath/learningPathPage/LearningPathViewSwitch.vue"; import LearningPathViewSwitch from "@/pages/learningPath/learningPathPage/LearningPathViewSwitch.vue";
import { useLearningPathStore } from "@/stores/learningPath";
import { useUserStore } from "@/stores/user";
import { breakpointsTailwind, useBreakpoints } from "@vueuse/core"; import { breakpointsTailwind, useBreakpoints } from "@vueuse/core";
import * as log from "loglevel"; import { computed, ref } from "vue";
import { computed, onMounted, ref } from "vue"; import { useLearningPathWithCompletion } from "@/composables";
import { someFinishedInLearningSequence } from "@/services/circle";
const props = defineProps<{ const props = defineProps<{
courseSlug: string; courseSlug: string;
}>(); }>();
const breakpoints = useBreakpoints(breakpointsTailwind); const breakpoints = useBreakpoints(breakpointsTailwind);
const learningPathStore = useLearningPathStore();
const userStore = useUserStore();
// Layout state // Layout state
const useMobileLayout = breakpoints.smaller("sm"); const useMobileLayout = breakpoints.smaller("sm");
@ -26,38 +23,20 @@ const selectedView = ref<ViewType>(
(window.localStorage.getItem("learningPathView") as ViewType) || "path" (window.localStorage.getItem("learningPathView") as ViewType) || "path"
); );
onMounted(async () => { const lpQueryResult = useLearningPathWithCompletion(props.courseSlug);
log.debug("LearningPathPage mounted");
try { const learningPath = computed(() => lpQueryResult.learningPath.value);
await learningPathStore.loadLearningPath(props.courseSlug + "-lp");
} catch (error) {
log.error(error);
}
});
const learningPath = computed(() => {
if (userStore.loggedIn && learningPathStore.state.learningPaths.size > 0) {
const learningPathKey = `${props.courseSlug}-lp-${userStore.id}`;
return learningPathStore.state.learningPaths.get(learningPathKey);
}
return undefined;
});
const circlesCount = computed(() => { const circlesCount = computed(() => {
if (learningPath.value) { return lpQueryResult.circles.value?.length ?? 0;
return learningPath.value.circles.length;
}
return 0;
}); });
const inProgressCirclesCount = computed(() => { const inProgressCirclesCount = computed(() => {
if (learningPath.value) { if (lpQueryResult.circles.value?.length) {
return learningPath.value.circles.filter( return lpQueryResult.circles.value.filter(
(circle) => (circle) =>
circle.learningSequences.filter((ls) => circle.learning_sequences.filter((ls) => someFinishedInLearningSequence(ls))
circle.someFinishedInLearningSequence(ls.translation_key) .length
).length
).length; ).length;
} }
return 0; return 0;

View File

@ -2,12 +2,12 @@
import LearningPathCircleColumn from "@/pages/learningPath/learningPathPage/LearningPathCircleColumn.vue"; import LearningPathCircleColumn from "@/pages/learningPath/learningPathPage/LearningPathCircleColumn.vue";
import LearningPathScrollButton from "@/pages/learningPath/learningPathPage/LearningPathScrollButton.vue"; import LearningPathScrollButton from "@/pages/learningPath/learningPathPage/LearningPathScrollButton.vue";
import type { OldCircle } from "@/services/oldCircle"; import type { OldCircle } from "@/services/oldCircle";
import type { LearningPath } from "@/services/learningPath";
import { useScroll } from "@vueuse/core"; import { useScroll } from "@vueuse/core";
import { ref } from "vue"; import { ref } from "vue";
import type { LearningPathType } from "@/types";
const props = defineProps<{ const props = defineProps<{
learningPath: LearningPath | undefined; learningPath: LearningPathType | undefined;
useMobileLayout: boolean; useMobileLayout: boolean;
hideButtons?: boolean; hideButtons?: boolean;
overrideCircleUrlBase?: string; overrideCircleUrlBase?: string;

View File

@ -2,14 +2,18 @@ import type {
CircleSectorData, CircleSectorData,
CircleSectorProgress, CircleSectorProgress,
} from "@/pages/learningPath/learningPathPage/LearningPathCircle.vue"; } from "@/pages/learningPath/learningPathPage/LearningPathCircle.vue";
import type { OldCircle } from "@/services/oldCircle"; import {
allFinishedInLearningSequence,
someFinishedInLearningSequence,
} from "@/services/circle";
import type { CircleType } from "@/types";
export function calculateCircleSectorData(circle: OldCircle): CircleSectorData[] { export function calculateCircleSectorData(circle: CircleType): CircleSectorData[] {
return circle.learningSequences.map((ls) => { return circle.learning_sequences.map((ls) => {
let progress: CircleSectorProgress = "none"; let progress: CircleSectorProgress = "none";
if (circle.allFinishedInLearningSequence(ls.translation_key)) { if (allFinishedInLearningSequence(ls)) {
progress = "finished"; progress = "finished";
} else if (circle.someFinishedInLearningSequence(ls.translation_key)) { } else if (someFinishedInLearningSequence(ls)) {
progress = "in_progress"; progress = "in_progress";
} }
return { return {

View File

@ -1,4 +1,4 @@
import { useLearningPathStore } from "@/stores/learningPath"; import { useLearningPathQuery } from "@/composables";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
import type { CircleLight, CourseSessionUser, ExpertSessionUser } from "@/types"; import type { CircleLight, CourseSessionUser, ExpertSessionUser } from "@/types";
import log from "loglevel"; import log from "loglevel";
@ -12,7 +12,6 @@ export type CockpitStoreState = {
courseSessionMembers: CourseSessionUser[] | undefined; courseSessionMembers: CourseSessionUser[] | undefined;
circles: CircleCockpit[] | undefined; circles: CircleCockpit[] | undefined;
currentCircle: CircleCockpit | undefined; currentCircle: CircleCockpit | undefined;
currentCourseSlug: string | undefined;
}; };
export const useCockpitStore = defineStore({ export const useCockpitStore = defineStore({
@ -22,7 +21,6 @@ export const useCockpitStore = defineStore({
courseSessionMembers: undefined, courseSessionMembers: undefined,
circles: [], circles: [],
currentCircle: undefined, currentCircle: undefined,
currentCourseSlug: undefined,
} as CockpitStoreState; } as CockpitStoreState;
}, },
actions: { actions: {
@ -31,21 +29,8 @@ export const useCockpitStore = defineStore({
currentCourseSessionUser: CourseSessionUser | undefined currentCourseSessionUser: CourseSessionUser | undefined
) { ) {
log.debug("loadCircles called", courseSlug); log.debug("loadCircles called", courseSlug);
this.currentCourseSlug = courseSlug;
const circles = await courseCircles( this.circles = await courseCircles(courseSlug, currentCourseSessionUser);
this.currentCourseSlug,
currentCourseSessionUser
);
this.circles = circles.map((c) => {
return {
id: c.id,
slug: c.slug,
title: c.title,
name: c.title,
} as const;
});
if (this.circles?.length) { if (this.circles?.length) {
await this.setCurrentCourseCircle(this.circles[0].slug); await this.setCurrentCourseCircle(this.circles[0].slug);
@ -64,28 +49,27 @@ async function courseCircles(
courseSlug: string, courseSlug: string,
currentCourseSessionUser: CourseSessionUser | undefined currentCourseSessionUser: CourseSessionUser | undefined
) { ) {
const userStore = useUserStore();
const userId = userStore.id;
if (currentCourseSessionUser && currentCourseSessionUser.role === "EXPERT") { if (currentCourseSessionUser && currentCourseSessionUser.role === "EXPERT") {
const expert = currentCourseSessionUser as ExpertSessionUser; const expert = currentCourseSessionUser as ExpertSessionUser;
return expert.circles; return expert.circles.map((c) => {
return { ...c, name: c.title };
});
} }
const userStore = useUserStore();
// Return all circles from learning path for admin users // Return all circles from learning path for admin users
if (userStore.is_superuser) { if (userStore.is_superuser) {
const learningPathStore = useLearningPathStore(); const lpQueryResult = useLearningPathQuery(courseSlug);
const learningPathCircles = learningPathStore await lpQueryResult.waitForData();
.learningPathForUser(courseSlug, userId)
?.circles.map((c) => { return (lpQueryResult.circles.value ?? []).map((c) => {
return { return {
id: c.id, id: c.id,
title: c.title,
slug: c.slug, slug: c.slug,
translation_key: c.translation_key, title: c.title,
}; name: c.title,
} as const;
}); });
return learningPathCircles || [];
} }
return []; return [];