import { itGetCached } from "@/fetchHelpers"; import type { CourseSession, DueDate } from "@/types"; import eventBus from "@/utils/eventBus"; import { useRouteLookups } from "@/utils/route"; import { useLocalStorage } from "@vueuse/core"; import dayjs from "dayjs"; import uniqBy from "lodash/uniqBy"; import log from "loglevel"; import { defineStore } from "pinia"; import { computed, ref } from "vue"; import { useUserStore } from "./user"; const SELECTED_COURSE_SESSIONS_KEY = "selectedCourseSessionMap"; export const useCourseSessionsStore = defineStore("courseSessions", () => { const loaded = ref(false); const allCourseSessions = ref([]); const { inCompetenceProfile, inLearningPath } = useRouteLookups(); async function loadCourseSessionsData(reload = false) { log.debug("loadCourseSessionsData called"); allCourseSessions.value = await itGetCached(`/api/course/sessions/`, { reload: reload, }); const userStore = useUserStore(); if (userStore.loggedIn) { // TODO: refactor after implementing of Klassenkonzept await Promise.all( allCourseSessions.value.map(async (cs) => { sortDueDates(cs.due_dates); }) ); if (!allCourseSessions.value) { throw `No courseSessionData found for user`; } } loaded.value = true; } const selectedCourseSessionMap = useLocalStorage( SELECTED_COURSE_SESSIONS_KEY, new Map() ); const _currentCourseSlug = ref(""); const uniqueCourseSessionsByCourse = computed(() => // Im Dashboard wird aktuell ein Widget pro Kurs dargestellt // mit dem Fortschritt jeweils einer Durchführung. // Dieser Getter wird nur dort benutzt. // TODO: Das Dashboard verschwindet evtl. in Zukunft, dann kann dieser Getter weg. // @ts-ignore uniqBy(allCourseSessions.value, "course.id") ); function selectedCourseSessionForCourse(courseSlug: string) { // Wir wollen pro Kurs wissen, welche Durchführung der User zuletzt ausgewählt hat. // Die letzte Durchführung wird im localStorage via `selectedCoruseSessionMap` // gespeichert und hier geladen. // Wenn noch keine Durchführung ausgewählt wurde, wird die erste Durchführung // in `courseSessionForCourse` zurückgegeben. try { const courseSessionId = selectedCourseSessionMap.value.get(courseSlug); if (courseSessionId) { return allCourseSessions.value.find((cs) => { return cs.id === courseSessionId; }); } } catch (e) { log.error("Error while parsing courseSessions from localStorage", e); } // Keine Durchführung ausgewählt im localStorage return undefined; } function _switchCourseSession(courseSession: CourseSession) { log.debug("switchCourseSession", courseSession); selectedCourseSessionMap.value.set(courseSession.course.slug, courseSession.id); // Emit event so that the App can re-render with the new courseSession eventBus.emit("switchedCourseSession", courseSession.id); } function getCourseSessionById(courseSessionId: string) { return allCourseSessions.value.find((cs) => { return courseSessionId === cs.id; }); } function switchCourseSessionById(courseSessionId: string) { const courseSession = allCourseSessions.value.find((cs) => { return courseSessionId === cs.id; }); if (courseSession) { _switchCourseSession(courseSession); return true; } else { return false; } } function courseSessionForCourse(courseSlug: string) { if (courseSlug) { const courseSession = selectedCourseSessionForCourse(courseSlug); if (courseSession) { return courseSession; } else { // return first if there is no selected courseSession return allCourseSessions.value.find((cs) => { return cs.course.slug === courseSlug; }); } } return undefined; } function allCourseSessionsForCourse(courseSlug: string) { return allCourseSessions.value.filter((cs) => { return cs.course.slug === courseSlug; }); } const currentCourseSession = computed(() => { return courseSessionForCourse(_currentCourseSlug.value); }); const allCurrentCourseSessions = computed(() => { return allCourseSessionsForCourse(_currentCourseSlug.value); }); const isCourseSessionPreviewActive = computed(() => { const hasPreview = currentCourseSession.value?.actions.includes("preview"); return Boolean(hasPreview && (inLearningPath() || inCompetenceProfile())); }); function allDueDates() { const allDueDatesReturn: DueDate[] = []; allCourseSessions.value?.forEach((cs) => { allDueDatesReturn.push(...cs.due_dates); }); sortDueDates(allDueDatesReturn); return allDueDatesReturn; } function sortDueDates(dueDates: DueDate[]) { dueDates.sort((a, b) => { const dateA = dayjs(a.start); const dateB = dayjs(b.start); if (!dateA.isValid() && !dateB.isValid()) return 0; // If both are invalid, they are equal if (!dateA.isValid()) return 1; // If dateA is invalid, it goes after dateB if (!dateB.isValid()) return -1; // If dateB is invalid, it goes after dateA return dateA.diff(dateB); // sort by `start` }); } return { uniqueCourseSessionsByCourse, allCurrentCourseSessions, getCourseSessionById, switchCourseSessionById, isCourseSessionPreviewActive, allDueDates, // use `useCurrentCourseSession` whenever possible currentCourseSession, loadCourseSessionsData, loaded, // only used so that `router.afterEach` can switch it _currentCourseSlug, // only used for unit testing allCourseSessions, }; });