vbv/client/src/stores/courseSessions.ts

152 lines
4.3 KiB
TypeScript

import { itGetCached, itPost } from "@/fetchHelpers";
import { deleteCircleDocument } from "@/services/files";
import type { CircleDocument, CircleExpert, CourseSession } from "@/types";
import _ from "lodash";
import log from "loglevel";
import { defineStore } from "pinia";
import { computed, ref } from "vue";
import { useRoute } from "vue-router";
import { useCircleStore } from "./circle";
import { useUserStore } from "./user";
export type CourseSessionsStoreState = {
courseSessions: CourseSession[] | undefined;
};
export type LearningSequenceCircleDocument = {
id: number;
title: string;
documents: CircleDocument[];
};
function loadCourseSessionsData(reload = false) {
log.debug("loadCourseSessionsData called");
const courseSessions = ref<CourseSession[]>([]);
async function loadAndUpdate() {
courseSessions.value = await itGetCached(`/api/course/sessions/`, {
reload: reload,
});
if (!courseSessions.value) {
throw `No courseSessionData found for user`;
}
}
loadAndUpdate(); // this will be called asynchronously, but does not block
// returns the empty sessions array at first, then after loading populates the ref
return { courseSessions };
}
function userExpertCircles(
userId: number,
courseSessionForRoute: CourseSession | undefined
): CircleExpert[] {
if (!courseSessionForRoute) {
return [];
}
return courseSessionForRoute.experts.filter((expert) => expert.user_id === userId);
}
export const useCourseSessionsStore = defineStore("courseSessions", () => {
// using setup function seems cleaner, see https://pinia.vuejs.org/core-concepts/#setup-stores
// this will become a state variable (like each other `ref()`
// store should do own setup, we don't want to have each component initialize it
// that's why we call the load function in here
const { courseSessions } = loadCourseSessionsData();
// these will become getters
const coursesFromCourseSessions = computed(() =>
_.uniqBy(courseSessions.value, "course.id")
);
const courseSessionForRoute = computed(() => {
const route = useRoute();
const routePath = decodeURI(route.path);
return courseSessions.value.find((cs) => {
return routePath.startsWith(cs.course_url);
});
});
const hasCockpit = computed(() => {
if (courseSessionForRoute.value) {
const userStore = useUserStore();
return (
courseSessionForRoute.value.experts.filter(
(expert) => expert.user_id === userStore.id
).length > 0
);
}
return false;
});
const canUploadCircleDocuments = computed(() => {
const userStore = useUserStore();
const circleStore = useCircleStore();
const expertCircles = userExpertCircles(userStore.id, courseSessionForRoute.value);
return (
expertCircles.filter(
(c) => c.circle_translation_key === circleStore.circle?.translation_key
).length > 0
);
});
const circleDocuments = computed(() => {
const circleStore = useCircleStore();
return circleStore.circle?.learningSequences
.map((ls) => ({ id: ls.id, title: ls.title, documents: [] }))
.map((ls: { id: number; title: string; documents: CircleDocument[] }) => {
if (courseSessionForRoute.value === undefined) {
return ls;
}
for (let document of courseSessionForRoute.value.documents) {
if (document.learning_sequence === ls.id) {
ls.documents.push(document);
}
}
return ls;
})
.filter((ls) => ls.documents.length > 0);
});
function addDocument(document: CircleDocument) {
courseSessionForRoute.value?.documents.push(document);
}
async function startUpload() {
log.debug("loadCourseSessionsData called");
courseSessions.value = await itPost(`/api/core/file/start`, {
file_type: "image/png",
file_name: "test.png",
});
}
async function removeDocument(documentId: number) {
await deleteCircleDocument(documentId);
if (courseSessionForRoute.value === undefined) {
return;
}
courseSessionForRoute.value.documents =
courseSessionForRoute.value?.documents.filter((d) => d.id !== documentId);
}
return {
courseSessions,
coursesFromCourseSessions,
courseSessionForRoute,
hasCockpit,
canUploadCircleDocuments,
circleDocuments,
addDocument,
startUpload,
removeDocument,
};
});