Merged in feature/composable-course-session (pull request #85)
Feature/composable course session Approved-by: Elia Bieri
This commit is contained in:
commit
3acae49217
|
|
@ -30,8 +30,10 @@ onMounted(() => {
|
||||||
log.debug("App mounted");
|
log.debug("App mounted");
|
||||||
|
|
||||||
eventBus.on("switchedCourseSession", () => {
|
eventBus.on("switchedCourseSession", () => {
|
||||||
// FIXME: clean up with VBV-305
|
// Rerender the component tree, when the course session gets switched.
|
||||||
|
// So that the current learning path completion data gets updated.
|
||||||
componentKey.value++;
|
componentKey.value++;
|
||||||
|
log.info("Switched course session, re-evaluate component tree");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||||
|
import type { CourseSession } from "@/types";
|
||||||
|
import log from "loglevel";
|
||||||
|
import type { ComputedRef } from "vue";
|
||||||
|
import { computed } from "vue";
|
||||||
|
|
||||||
|
export function useCurrentCourseSession() {
|
||||||
|
/**
|
||||||
|
* We often need the current course session in our components.
|
||||||
|
* With this composable we can get it easily.
|
||||||
|
*/
|
||||||
|
const store = useCourseSessionsStore();
|
||||||
|
|
||||||
|
const result: ComputedRef<CourseSession> = computed(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
() => {
|
||||||
|
if (!store.currentCourseSession) {
|
||||||
|
log.error(
|
||||||
|
"currentCourseSession is only defined in pages with :courseSlug in the route"
|
||||||
|
);
|
||||||
|
throw new Error(
|
||||||
|
`currentCourseSession is not defined in the store.
|
||||||
|
It is only defined in pages with :courseSlug in the route`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return store.currentCourseSession;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
import { useCockpitStore } from "@/stores/cockpit";
|
||||||
import { useCompetenceStore } from "@/stores/competence";
|
import { useCompetenceStore } from "@/stores/competence";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
|
|
@ -16,25 +16,22 @@ const props = defineProps<{
|
||||||
const cockpitStore = useCockpitStore();
|
const cockpitStore = useCockpitStore();
|
||||||
const competenceStore = useCompetenceStore();
|
const competenceStore = useCompetenceStore();
|
||||||
const learningPathStore = useLearningPathStore();
|
const learningPathStore = useLearningPathStore();
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
const courseSession = useCurrentCourseSession();
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.debug("CockpitParentPage mounted", props.courseSlug);
|
log.debug("CockpitParentPage mounted", props.courseSlug);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const currentCourseSession = courseSessionsStore.currentCourseSession;
|
await cockpitStore.loadCourseSessionUsers(courseSession.value.id);
|
||||||
if (currentCourseSession?.id) {
|
cockpitStore.courseSessionUsers?.forEach((csu) => {
|
||||||
await cockpitStore.loadCourseSessionUsers(currentCourseSession.id);
|
competenceStore.loadCompetenceProfilePage(
|
||||||
cockpitStore.courseSessionUsers?.forEach((csu) => {
|
props.courseSlug + "-competence",
|
||||||
competenceStore.loadCompetenceProfilePage(
|
csu.user_id
|
||||||
props.courseSlug + "-competence",
|
);
|
||||||
csu.user_id
|
|
||||||
);
|
|
||||||
|
|
||||||
learningPathStore.loadLearningPath(props.courseSlug + "-lp", csu.user_id);
|
learningPathStore.loadLearningPath(props.courseSlug + "-lp", csu.user_id);
|
||||||
});
|
});
|
||||||
learningPathStore.loadLearningPath(props.courseSlug + "-lp", useUserStore().id);
|
learningPathStore.loadLearningPath(props.courseSlug + "-lp", useUserStore().id);
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(error);
|
log.error(error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,8 @@ import HorizontalBarChart from "@/components/ui/HorizontalBarChart.vue";
|
||||||
import OpenFeedback from "@/components/ui/OpenFeedback.vue";
|
import OpenFeedback from "@/components/ui/OpenFeedback.vue";
|
||||||
import RatingScale from "@/components/ui/RatingScale.vue";
|
import RatingScale from "@/components/ui/RatingScale.vue";
|
||||||
import VerticalBarChart from "@/components/ui/VerticalBarChart.vue";
|
import VerticalBarChart from "@/components/ui/VerticalBarChart.vue";
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import { itGet } from "@/fetchHelpers";
|
import { itGet } from "@/fetchHelpers";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import { onMounted, reactive } from "vue";
|
import { onMounted, reactive } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
@ -79,7 +79,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
log.debug("FeedbackPage created", props.circleId);
|
log.debug("FeedbackPage created", props.circleId);
|
||||||
|
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
const courseSession = useCurrentCourseSession();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const orderedQuestions = [
|
const orderedQuestions = [
|
||||||
|
|
@ -144,7 +144,7 @@ const feedbackData = reactive<FeedbackData>({ amount: 0, questions: {} });
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.debug("FeedbackPage mounted");
|
log.debug("FeedbackPage mounted");
|
||||||
const data = await itGet(
|
const data = await itGet(
|
||||||
`/api/core/feedback/${courseSessionsStore.currentCourseSession?.course.id}/${props.circleId}`
|
`/api/core/feedback/${courseSession.value.course.id}/${props.circleId}`
|
||||||
);
|
);
|
||||||
Object.assign(feedbackData, data);
|
Object.assign(feedbackData, data);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import { ASSIGNMENT_COMPLETION_QUERY } from "@/graphql/queries";
|
import { ASSIGNMENT_COMPLETION_QUERY } from "@/graphql/queries";
|
||||||
import EvaluationContainer from "@/pages/cockpit/assignmentEvaluationPage/EvaluationContainer.vue";
|
import EvaluationContainer from "@/pages/cockpit/assignmentEvaluationPage/EvaluationContainer.vue";
|
||||||
import AssignmentSubmissionResponses from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionResponses.vue";
|
import AssignmentSubmissionResponses from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionResponses.vue";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
||||||
import type {
|
import type {
|
||||||
Assignment,
|
Assignment,
|
||||||
AssignmentCompletion,
|
AssignmentCompletion,
|
||||||
|
|
@ -32,14 +32,14 @@ const state: StateInterface = reactive({
|
||||||
assignmentUser: undefined,
|
assignmentUser: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
const courseSession = useCurrentCourseSession();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
// noinspection TypeScriptValidateTypes TODO: because of IntelliJ
|
// noinspection TypeScriptValidateTypes TODO: because of IntelliJ
|
||||||
const queryResult = useQuery({
|
const queryResult = useQuery({
|
||||||
query: ASSIGNMENT_COMPLETION_QUERY,
|
query: ASSIGNMENT_COMPLETION_QUERY,
|
||||||
variables: {
|
variables: {
|
||||||
courseSessionId: courseSessionsStore.currentCourseSession!.id.toString(),
|
courseSessionId: courseSession.value.id.toString(),
|
||||||
assignmentId: props.assignmentId,
|
assignmentId: props.assignmentId,
|
||||||
assignmentUserId: props.userId,
|
assignmentUserId: props.userId,
|
||||||
},
|
},
|
||||||
|
|
@ -48,11 +48,9 @@ const queryResult = useQuery({
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.debug("AssignmentView mounted", props.assignmentId, props.userId);
|
log.debug("AssignmentView mounted", props.assignmentId, props.userId);
|
||||||
|
|
||||||
if (courseSessionsStore.currentCourseSession) {
|
state.assignmentUser = courseSession.value.users.find(
|
||||||
state.assignmentUser = courseSessionsStore.currentCourseSession.users.find(
|
(user) => user.user_id === Number(props.userId)
|
||||||
(user) => user.user_id === Number(props.userId)
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
||||||
import type { Assignment, AssignmentCompletion, CourseSessionUser } from "@/types";
|
import type { Assignment, AssignmentCompletion, CourseSessionUser } from "@/types";
|
||||||
import { useMutation } from "@urql/vue";
|
import { useMutation } from "@urql/vue";
|
||||||
import dayjs, { Dayjs } from "dayjs";
|
import dayjs, { Dayjs } from "dayjs";
|
||||||
|
|
@ -17,7 +17,7 @@ const emit = defineEmits(["startEvaluation"]);
|
||||||
|
|
||||||
log.debug("EvaluationIntro setup");
|
log.debug("EvaluationIntro setup");
|
||||||
|
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
const courseSession = useCurrentCourseSession();
|
||||||
|
|
||||||
const upsertAssignmentCompletionMutation = useMutation(
|
const upsertAssignmentCompletionMutation = useMutation(
|
||||||
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
|
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
|
||||||
|
|
@ -29,7 +29,7 @@ async function startEvaluation() {
|
||||||
// noinspection TypeScriptValidateTypes
|
// noinspection TypeScriptValidateTypes
|
||||||
upsertAssignmentCompletionMutation.executeMutation({
|
upsertAssignmentCompletionMutation.executeMutation({
|
||||||
assignmentId: props.assignment.id.toString(),
|
assignmentId: props.assignment.id.toString(),
|
||||||
courseSessionId: (courseSessionsStore?.currentCourseSession?.id ?? 0).toString(),
|
courseSessionId: courseSession.value.id.toString(),
|
||||||
assignmentUserId: props.assignmentUser.user_id.toString(),
|
assignmentUserId: props.assignmentUser.user_id.toString(),
|
||||||
completionStatus: "EVALUATION_IN_PROGRESS",
|
completionStatus: "EVALUATION_IN_PROGRESS",
|
||||||
completionDataString: JSON.stringify({}),
|
completionDataString: JSON.stringify({}),
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ItSuccessAlert from "@/components/ui/ItSuccessAlert.vue";
|
import ItSuccessAlert from "@/components/ui/ItSuccessAlert.vue";
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
||||||
import {
|
import {
|
||||||
maxAssignmentPoints,
|
maxAssignmentPoints,
|
||||||
pointsToGrade,
|
pointsToGrade,
|
||||||
userAssignmentPoints,
|
userAssignmentPoints,
|
||||||
} from "@/services/assignmentService";
|
} from "@/services/assignmentService";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
||||||
import type {
|
import type {
|
||||||
Assignment,
|
Assignment,
|
||||||
AssignmentCompletion,
|
AssignmentCompletion,
|
||||||
|
|
@ -34,7 +34,7 @@ const state = reactive({
|
||||||
|
|
||||||
log.debug("EvaluationSummary setup");
|
log.debug("EvaluationSummary setup");
|
||||||
|
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
const courseSession = useCurrentCourseSession();
|
||||||
|
|
||||||
const upsertAssignmentCompletionMutation = useMutation(
|
const upsertAssignmentCompletionMutation = useMutation(
|
||||||
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
|
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
|
||||||
|
|
@ -44,7 +44,7 @@ async function submitEvaluation() {
|
||||||
// noinspection TypeScriptValidateTypes
|
// noinspection TypeScriptValidateTypes
|
||||||
upsertAssignmentCompletionMutation.executeMutation({
|
upsertAssignmentCompletionMutation.executeMutation({
|
||||||
assignmentId: props.assignment.id.toString(),
|
assignmentId: props.assignment.id.toString(),
|
||||||
courseSessionId: (courseSessionsStore?.currentCourseSession?.id ?? 0).toString(),
|
courseSessionId: courseSession.value.id.toString(),
|
||||||
assignmentUserId: props.assignmentUser.user_id.toString(),
|
assignmentUserId: props.assignmentUser.user_id.toString(),
|
||||||
completionStatus: "EVALUATION_SUBMITTED",
|
completionStatus: "EVALUATION_SUBMITTED",
|
||||||
completionDataString: JSON.stringify({}),
|
completionDataString: JSON.stringify({}),
|
||||||
|
|
@ -87,7 +87,7 @@ const grade = computed(() => {
|
||||||
|
|
||||||
const evaluationUser = computed(() => {
|
const evaluationUser = computed(() => {
|
||||||
if (props.assignmentCompletion.evaluation_user) {
|
if (props.assignmentCompletion.evaluation_user) {
|
||||||
return (courseSessionsStore.currentCourseSession?.users ?? []).find(
|
return (courseSession.value.users ?? []).find(
|
||||||
(user) => user.user_id === Number(props.assignmentCompletion.evaluation_user)
|
(user) => user.user_id === Number(props.assignmentCompletion.evaluation_user)
|
||||||
) as CourseSessionUser;
|
) as CourseSessionUser;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ItTextarea from "@/components/ui/ItTextarea.vue";
|
import ItTextarea from "@/components/ui/ItTextarea.vue";
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
||||||
import type {
|
import type {
|
||||||
Assignment,
|
Assignment,
|
||||||
AssignmentCompletion,
|
AssignmentCompletion,
|
||||||
|
|
@ -24,7 +24,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
log.debug("EvaluationTask setup", props.taskIndex);
|
log.debug("EvaluationTask setup", props.taskIndex);
|
||||||
|
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
const courseSession = useCurrentCourseSession();
|
||||||
|
|
||||||
const task = computed(() => props.assignment.evaluation_tasks[props.taskIndex]);
|
const task = computed(() => props.assignment.evaluation_tasks[props.taskIndex]);
|
||||||
|
|
||||||
|
|
@ -68,7 +68,7 @@ async function evaluateAssignmentCompletion(completionData: AssignmentCompletion
|
||||||
// noinspection TypeScriptValidateTypes
|
// noinspection TypeScriptValidateTypes
|
||||||
upsertAssignmentCompletionMutation.executeMutation({
|
upsertAssignmentCompletionMutation.executeMutation({
|
||||||
assignmentId: props.assignment.id.toString(),
|
assignmentId: props.assignment.id.toString(),
|
||||||
courseSessionId: (courseSessionsStore?.currentCourseSession?.id ?? 0).toString(),
|
courseSessionId: courseSession.value.id.toString(),
|
||||||
assignmentUserId: props.assignmentUser.user_id.toString(),
|
assignmentUserId: props.assignmentUser.user_id.toString(),
|
||||||
completionStatus: "EVALUATION_IN_PROGRESS",
|
completionStatus: "EVALUATION_IN_PROGRESS",
|
||||||
completionDataString: JSON.stringify(completionData),
|
completionDataString: JSON.stringify(completionData),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import AssignmentDetails from "@/pages/cockpit/assignmentsPage/AssignmentDetails.vue";
|
import AssignmentDetails from "@/pages/cockpit/assignmentsPage/AssignmentDetails.vue";
|
||||||
import { calcAssignmentLearningContents } from "@/services/assignmentService";
|
import { calcAssignmentLearningContents } from "@/services/assignmentService";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
|
|
@ -14,31 +14,23 @@ const props = defineProps<{
|
||||||
log.debug("AssignmentsPage created", props.courseSlug);
|
log.debug("AssignmentsPage created", props.courseSlug);
|
||||||
|
|
||||||
const learningPathStore = useLearningPathStore();
|
const learningPathStore = useLearningPathStore();
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
const courseSession = useCurrentCourseSession();
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.debug("AssignmentsPage mounted");
|
log.debug("AssignmentsPage mounted");
|
||||||
});
|
});
|
||||||
|
|
||||||
const assignments = computed(() => {
|
const assignments = computed(() => {
|
||||||
// TODO: filter by selected circle
|
|
||||||
if (!courseSessionsStore.currentCourseSession) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return calcAssignmentLearningContents(
|
return calcAssignmentLearningContents(
|
||||||
learningPathStore.learningPathForUser(
|
learningPathStore.learningPathForUser(courseSession.value.course.slug, userStore.id)
|
||||||
courseSessionsStore.currentCourseSession.course.slug,
|
|
||||||
userStore.id
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-200">
|
<div class="bg-gray-200">
|
||||||
<div v-if="courseSessionsStore.currentCourseSession" class="container-large">
|
<div class="container-large">
|
||||||
<nav class="py-4 pb-4">
|
<nav class="py-4 pb-4">
|
||||||
<router-link
|
<router-link
|
||||||
class="btn-text inline-flex items-center pl-0"
|
class="btn-text inline-flex items-center pl-0"
|
||||||
|
|
@ -58,7 +50,7 @@ const assignments = computed(() => {
|
||||||
<div v-for="assignment in assignments" :key="assignment.id">
|
<div v-for="assignment in assignments" :key="assignment.id">
|
||||||
<div class="bg-white p-6">
|
<div class="bg-white p-6">
|
||||||
<AssignmentDetails
|
<AssignmentDetails
|
||||||
:course-session="courseSessionsStore.currentCourseSession"
|
:course-session="courseSession"
|
||||||
:assignment="assignment"
|
:assignment="assignment"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
||||||
import ItProgress from "@/components/ui/ItProgress.vue";
|
import ItProgress from "@/components/ui/ItProgress.vue";
|
||||||
import type { LearningPath } from "@/services/learningPath";
|
import type { LearningPath } from "@/services/learningPath";
|
||||||
|
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import AssignmentsTile from "@/pages/cockpit/cockpitPage/AssignmentsTile.vue";
|
import AssignmentsTile from "@/pages/cockpit/cockpitPage/AssignmentsTile.vue";
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
import { useCockpitStore } from "@/stores/cockpit";
|
||||||
import { useCompetenceStore } from "@/stores/competence";
|
import { useCompetenceStore } from "@/stores/competence";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import groupBy from "lodash/groupBy";
|
import groupBy from "lodash/groupBy";
|
||||||
|
|
@ -25,7 +25,7 @@ const userStore = useUserStore();
|
||||||
const cockpitStore = useCockpitStore();
|
const cockpitStore = useCockpitStore();
|
||||||
const competenceStore = useCompetenceStore();
|
const competenceStore = useCompetenceStore();
|
||||||
const learningPathStore = useLearningPathStore();
|
const learningPathStore = useLearningPathStore();
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
const courseSession = useCurrentCourseSession();
|
||||||
|
|
||||||
function userCountStatusForCircle(userId: number, translationKey: string) {
|
function userCountStatusForCircle(userId: number, translationKey: string) {
|
||||||
const criteria = competenceStore.flatPerformanceCriteria(
|
const criteria = competenceStore.flatPerformanceCriteria(
|
||||||
|
|
@ -102,10 +102,7 @@ function setActiveClasses(translationKey: string) {
|
||||||
</div>
|
</div>
|
||||||
<!-- Status -->
|
<!-- Status -->
|
||||||
<div class="mb-4 grid grid-rows-2 gap-4 lg:grid-cols-2 lg:grid-rows-none">
|
<div class="mb-4 grid grid-rows-2 gap-4 lg:grid-cols-2 lg:grid-rows-none">
|
||||||
<AssignmentsTile
|
<AssignmentsTile :course-session="courseSession" />
|
||||||
v-if="courseSessionsStore.currentCourseSession"
|
|
||||||
:course-session="courseSessionsStore.currentCourseSession"
|
|
||||||
/>
|
|
||||||
<div class="bg-white px-6 py-5">
|
<div class="bg-white px-6 py-5">
|
||||||
<h3 class="heading-3 mb-4 flex items-center gap-2">
|
<h3 class="heading-3 mb-4 flex items-center gap-2">
|
||||||
<it-icon-test-large class="h-16 w-16"></it-icon-test-large>
|
<it-icon-test-large class="h-16 w-16"></it-icon-test-large>
|
||||||
|
|
@ -124,8 +121,8 @@ function setActiveClasses(translationKey: string) {
|
||||||
learningPathStore.learningPathForUser(props.courseSlug, userStore.id)
|
learningPathStore.learningPathForUser(props.courseSlug, userStore.id)
|
||||||
?.circles || []
|
?.circles || []
|
||||||
"
|
"
|
||||||
:course-id="courseSessionsStore.currentCourseSession?.course.id || 0"
|
:course-id="courseSession.course.id"
|
||||||
:url="courseSessionsStore.currentCourseSession?.course_url || ''"
|
:url="courseSession.course_url || ''"
|
||||||
></FeedbackSummary>
|
></FeedbackSummary>
|
||||||
<div>
|
<div>
|
||||||
<!-- progress -->
|
<!-- progress -->
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import ItButton from "@/components/ui/ItButton.vue";
|
import ItButton from "@/components/ui/ItButton.vue";
|
||||||
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
|
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
|
||||||
import ItSuccessAlert from "@/components/ui/ItSuccessAlert.vue";
|
import ItSuccessAlert from "@/components/ui/ItSuccessAlert.vue";
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
||||||
import AssignmentSubmissionResponses from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionResponses.vue";
|
import AssignmentSubmissionResponses from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionResponses.vue";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||||
|
|
@ -24,6 +25,7 @@ const emit = defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
const courseSessionsStore = useCourseSessionsStore();
|
||||||
|
const courseSession = useCurrentCourseSession();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
|
|
@ -57,16 +59,10 @@ const onEditTask = (task: AssignmentTask) => {
|
||||||
|
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
const courseSessionId = courseSessionsStore.currentCourseSession?.id;
|
|
||||||
if (!courseSessionId) {
|
|
||||||
log.error("Invalid courseSessionId");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// noinspection TypeScriptValidateTypes
|
// noinspection TypeScriptValidateTypes
|
||||||
upsertAssignmentCompletionMutation.executeMutation({
|
upsertAssignmentCompletionMutation.executeMutation({
|
||||||
assignmentId: props.assignment.id.toString(),
|
assignmentId: props.assignment.id.toString(),
|
||||||
courseSessionId: courseSessionId.toString(),
|
courseSessionId: courseSession.value.id.toString(),
|
||||||
completionDataString: JSON.stringify({}),
|
completionDataString: JSON.stringify({}),
|
||||||
completionStatus: "SUBMITTED",
|
completionStatus: "SUBMITTED",
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
|
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
|
||||||
import ItTextarea from "@/components/ui/ItTextarea.vue";
|
import ItTextarea from "@/components/ui/ItTextarea.vue";
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
||||||
import type {
|
import type {
|
||||||
AssignmentCompletion,
|
AssignmentCompletion,
|
||||||
AssignmentCompletionData,
|
AssignmentCompletionData,
|
||||||
|
|
@ -23,7 +23,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
const checkboxState = reactive({} as Record<string, boolean>);
|
const checkboxState = reactive({} as Record<string, boolean>);
|
||||||
|
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
const courseSession = useCurrentCourseSession();
|
||||||
|
|
||||||
const upsertAssignmentCompletionMutation = useMutation(
|
const upsertAssignmentCompletionMutation = useMutation(
|
||||||
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
|
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
|
||||||
|
|
@ -31,16 +31,10 @@ const upsertAssignmentCompletionMutation = useMutation(
|
||||||
|
|
||||||
async function upsertAssignmentCompletion(completion_data: AssignmentCompletionData) {
|
async function upsertAssignmentCompletion(completion_data: AssignmentCompletionData) {
|
||||||
try {
|
try {
|
||||||
const courseSessionId = courseSessionsStore.currentCourseSession?.id;
|
|
||||||
if (!courseSessionId) {
|
|
||||||
console.error("Invalid courseSessionId");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// noinspection TypeScriptValidateTypes
|
// noinspection TypeScriptValidateTypes
|
||||||
await upsertAssignmentCompletionMutation.executeMutation({
|
await upsertAssignmentCompletionMutation.executeMutation({
|
||||||
assignmentId: props.assignmentId.toString(),
|
assignmentId: props.assignmentId.toString(),
|
||||||
courseSessionId: courseSessionId.toString(),
|
courseSessionId: courseSession.value.id.toString(),
|
||||||
completionDataString: JSON.stringify(completion_data),
|
completionDataString: JSON.stringify(completion_data),
|
||||||
completionStatus: "IN_PROGRESS",
|
completionStatus: "IN_PROGRESS",
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
||||||
import { ASSIGNMENT_COMPLETION_QUERY } from "@/graphql/queries";
|
import { ASSIGNMENT_COMPLETION_QUERY } from "@/graphql/queries";
|
||||||
import EvaluationSummary from "@/pages/cockpit/assignmentEvaluationPage/EvaluationSummary.vue";
|
import EvaluationSummary from "@/pages/cockpit/assignmentEvaluationPage/EvaluationSummary.vue";
|
||||||
|
|
@ -6,7 +7,6 @@ import AssignmentIntroductionView from "@/pages/learningPath/learningContentPage
|
||||||
import AssignmentSubmissionView from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionView.vue";
|
import AssignmentSubmissionView from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionView.vue";
|
||||||
import AssignmentTaskView from "@/pages/learningPath/learningContentPage/assignment/AssignmentTaskView.vue";
|
import AssignmentTaskView from "@/pages/learningPath/learningContentPage/assignment/AssignmentTaskView.vue";
|
||||||
import LearningContentMultiLayout from "@/pages/learningPath/learningContentPage/layouts/LearningContentMultiLayout.vue";
|
import LearningContentMultiLayout from "@/pages/learningPath/learningContentPage/layouts/LearningContentMultiLayout.vue";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import type {
|
import type {
|
||||||
Assignment,
|
Assignment,
|
||||||
|
|
@ -24,7 +24,7 @@ import { computed, onMounted, reactive } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
const courseSession = useCurrentCourseSession();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
|
|
@ -43,7 +43,7 @@ const props = defineProps<{
|
||||||
const queryResult = useQuery({
|
const queryResult = useQuery({
|
||||||
query: ASSIGNMENT_COMPLETION_QUERY,
|
query: ASSIGNMENT_COMPLETION_QUERY,
|
||||||
variables: {
|
variables: {
|
||||||
courseSessionId: courseSessionsStore.currentCourseSession!.id.toString(),
|
courseSessionId: courseSession.value.id.toString(),
|
||||||
assignmentId: props.learningContent.content_assignment_id.toString(),
|
assignmentId: props.learningContent.content_assignment_id.toString(),
|
||||||
},
|
},
|
||||||
pause: true,
|
pause: true,
|
||||||
|
|
@ -80,7 +80,7 @@ onMounted(async () => {
|
||||||
// noinspection TypeScriptValidateTypes
|
// noinspection TypeScriptValidateTypes
|
||||||
await upsertAssignmentCompletionMutation.executeMutation({
|
await upsertAssignmentCompletionMutation.executeMutation({
|
||||||
assignmentId: props.learningContent.content_assignment_id.toString(),
|
assignmentId: props.learningContent.content_assignment_id.toString(),
|
||||||
courseSessionId: courseSessionsStore.currentCourseSession!.id.toString(),
|
courseSessionId: courseSession.value.id.toString(),
|
||||||
completionDataString: JSON.stringify({}),
|
completionDataString: JSON.stringify({}),
|
||||||
completionStatus: "IN_PROGRESS",
|
completionStatus: "IN_PROGRESS",
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
|
@ -109,9 +109,6 @@ const showExitButton = computed(() => numPages.value === stepIndex.value + 1);
|
||||||
const dueDate = computed(() =>
|
const dueDate = computed(() =>
|
||||||
dayjs(state.courseSessionAssignmentDetails?.submissionDeadlineDateTimeUtc)
|
dayjs(state.courseSessionAssignmentDetails?.submissionDeadlineDateTimeUtc)
|
||||||
);
|
);
|
||||||
const courseSessionId = computed(
|
|
||||||
() => courseSessionsStore.currentCourseSession?.id ?? 0
|
|
||||||
);
|
|
||||||
const currentTask = computed(() => {
|
const currentTask = computed(() => {
|
||||||
if (stepIndex.value > 0 && stepIndex.value <= numTasks.value) {
|
if (stepIndex.value > 0 && stepIndex.value <= numTasks.value) {
|
||||||
return assignment.value?.tasks[stepIndex.value - 1];
|
return assignment.value?.tasks[stepIndex.value - 1];
|
||||||
|
|
@ -154,7 +151,7 @@ const getTitle = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const assignmentUser = computed(() => {
|
const assignmentUser = computed(() => {
|
||||||
return (courseSessionsStore.currentCourseSession?.users ?? []).find(
|
return courseSession.value.users.find(
|
||||||
(user) => user.user_id === Number(userStore.id)
|
(user) => user.user_id === Number(userStore.id)
|
||||||
) as CourseSessionUser;
|
) as CourseSessionUser;
|
||||||
});
|
});
|
||||||
|
|
@ -199,7 +196,7 @@ const assignmentUser = computed(() => {
|
||||||
:due-date="dueDate"
|
:due-date="dueDate"
|
||||||
:assignment="assignment"
|
:assignment="assignment"
|
||||||
:assignment-completion="assignmentCompletion"
|
:assignment-completion="assignmentCompletion"
|
||||||
:course-session-id="courseSessionId!"
|
:course-session-id="courseSession.id"
|
||||||
@edit-task="jumpToTask($event)"
|
@edit-task="jumpToTask($event)"
|
||||||
></AssignmentSubmissionView>
|
></AssignmentSubmissionView>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import * as log from "loglevel";
|
|
||||||
|
|
||||||
import LearningPathAppointmentsMock from "@/pages/learningPath/learningPathPage/LearningPathAppointmentsMock.vue";
|
import LearningPathAppointmentsMock from "@/pages/learningPath/learningPathPage/LearningPathAppointmentsMock.vue";
|
||||||
import LearningPathListView from "@/pages/learningPath/learningPathPage/LearningPathListView.vue";
|
import LearningPathListView from "@/pages/learningPath/learningPathPage/LearningPathListView.vue";
|
||||||
import LearningPathPathView from "@/pages/learningPath/learningPathPage/LearningPathPathView.vue";
|
import LearningPathPathView from "@/pages/learningPath/learningPathPage/LearningPathPathView.vue";
|
||||||
|
|
@ -11,6 +9,7 @@ import LearningPathViewSwitch from "@/pages/learningPath/learningPathPage/Learni
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import { breakpointsTailwind, useBreakpoints } from "@vueuse/core";
|
import { breakpointsTailwind, useBreakpoints } from "@vueuse/core";
|
||||||
|
import * as log from "loglevel";
|
||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ import { useCircleStore } from "@/stores/circle";
|
||||||
import type { LearningUnit } from "@/types";
|
import type { LearningUnit } from "@/types";
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
|
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import { COMPLETION_FAILURE, COMPLETION_SUCCESS } from "@/constants";
|
import { COMPLETION_FAILURE, COMPLETION_SUCCESS } from "@/constants";
|
||||||
import LearningContentContainer from "@/pages/learningPath/learningContentPage/LearningContentContainer.vue";
|
import LearningContentContainer from "@/pages/learningPath/learningContentPage/LearningContentContainer.vue";
|
||||||
import LearningContentMultiLayout from "@/pages/learningPath/learningContentPage/layouts/LearningContentMultiLayout.vue";
|
import LearningContentMultiLayout from "@/pages/learningPath/learningContentPage/layouts/LearningContentMultiLayout.vue";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
||||||
import eventBus from "@/utils/eventBus";
|
import eventBus from "@/utils/eventBus";
|
||||||
import { useRouteQuery } from "@vueuse/router";
|
import { useRouteQuery } from "@vueuse/router";
|
||||||
import { computed, onUnmounted } from "vue";
|
import { computed, onUnmounted } from "vue";
|
||||||
|
|
@ -14,7 +14,7 @@ import { computed, onUnmounted } from "vue";
|
||||||
log.debug("LearningContent.vue setup");
|
log.debug("LearningContent.vue setup");
|
||||||
|
|
||||||
const circleStore = useCircleStore();
|
const circleStore = useCircleStore();
|
||||||
const courseSession = useCourseSessionsStore();
|
const courseSession = useCurrentCourseSession();
|
||||||
|
|
||||||
const questionIndex = useRouteQuery("step", "0", { transform: Number, mode: "push" });
|
const questionIndex = useRouteQuery("step", "0", { transform: Number, mode: "push" });
|
||||||
|
|
||||||
|
|
@ -124,7 +124,7 @@ onUnmounted(() => {
|
||||||
<div class="mt-6 lg:mt-12">
|
<div class="mt-6 lg:mt-12">
|
||||||
{{ $t("selfEvaluation.progressText") }}
|
{{ $t("selfEvaluation.progressText") }}
|
||||||
<router-link
|
<router-link
|
||||||
:to="courseSession.currentCourseSession?.competence_url || '/'"
|
:to="courseSession.competence_url"
|
||||||
class="text-primary-500 underline"
|
class="text-primary-500 underline"
|
||||||
>
|
>
|
||||||
{{ $t("selfEvaluation.progressLink") }}
|
{{ $t("selfEvaluation.progressLink") }}
|
||||||
|
|
|
||||||
|
|
@ -43,3 +43,16 @@ export const expertRequired: NavigationGuard = (to: RouteLocationNormalized) =>
|
||||||
return `/course/${courseSlug}/learn`;
|
return `/course/${courseSlug}/learn`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export async function handleCourseSessions(to: RouteLocationNormalized) {
|
||||||
|
// register after login hooks
|
||||||
|
const courseSessionsStore = useCourseSessionsStore();
|
||||||
|
if (to.params.courseSlug) {
|
||||||
|
courseSessionsStore._currentCourseSlug = to.params.courseSlug as string;
|
||||||
|
} else {
|
||||||
|
courseSessionsStore._currentCourseSlug = "";
|
||||||
|
}
|
||||||
|
if (!courseSessionsStore.loaded) {
|
||||||
|
await courseSessionsStore.loadCourseSessionsData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import DashboardPage from "@/pages/DashboardPage.vue";
|
import DashboardPage from "@/pages/DashboardPage.vue";
|
||||||
import LoginPage from "@/pages/LoginPage.vue";
|
import LoginPage from "@/pages/LoginPage.vue";
|
||||||
import { redirectToLoginIfRequired, updateLoggedIn } from "@/router/guards";
|
import {
|
||||||
import { useAppStore } from "@/stores/app";
|
handleCourseSessions,
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
redirectToLoginIfRequired,
|
||||||
|
updateLoggedIn,
|
||||||
|
} from "@/router/guards";
|
||||||
import { createRouter, createWebHistory } from "vue-router";
|
import { createRouter, createWebHistory } from "vue-router";
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
|
|
@ -182,18 +184,7 @@ const router = createRouter({
|
||||||
router.beforeEach(updateLoggedIn);
|
router.beforeEach(updateLoggedIn);
|
||||||
router.beforeEach(redirectToLoginIfRequired);
|
router.beforeEach(redirectToLoginIfRequired);
|
||||||
|
|
||||||
router.beforeEach((to) => {
|
// register after login hooks
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
router.beforeEach(handleCourseSessions);
|
||||||
if (to.params.courseSlug) {
|
|
||||||
courseSessionsStore._currentCourseSlug = to.params.courseSlug as string;
|
|
||||||
} else {
|
|
||||||
courseSessionsStore._currentCourseSlug = "";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
router.afterEach(() => {
|
|
||||||
const appStore = useAppStore();
|
|
||||||
appStore.routingFinished = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
import { defineStore } from "pinia";
|
|
||||||
|
|
||||||
export type AppState = {
|
|
||||||
userLoaded: boolean;
|
|
||||||
routingFinished: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useAppStore = defineStore({
|
|
||||||
id: "app",
|
|
||||||
state: () =>
|
|
||||||
({
|
|
||||||
userLoaded: false,
|
|
||||||
routingFinished: false,
|
|
||||||
} as AppState),
|
|
||||||
getters: {},
|
|
||||||
actions: {},
|
|
||||||
});
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import { itGetCached } from "@/fetchHelpers";
|
import { itGetCached } from "@/fetchHelpers";
|
||||||
import { useCompletionStore } from "@/stores/completion";
|
import { useCompletionStore } from "@/stores/completion";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import type {
|
import type {
|
||||||
CircleLight,
|
CircleLight,
|
||||||
|
|
@ -166,11 +166,10 @@ export const useCompetenceStore = defineStore({
|
||||||
if (competenceProfilePage) {
|
if (competenceProfilePage) {
|
||||||
const completionStore = useCompletionStore();
|
const completionStore = useCompletionStore();
|
||||||
|
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
const courseSession = useCurrentCourseSession();
|
||||||
const courseSession = courseSessionsStore.currentCourseSession;
|
|
||||||
if (courseSession) {
|
if (courseSession) {
|
||||||
const completionData = await completionStore.loadCourseSessionCompletionData(
|
const completionData = await completionStore.loadCourseSessionCompletionData(
|
||||||
courseSession.id,
|
courseSession.value.id,
|
||||||
userId
|
userId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,20 +17,16 @@ import { computed, ref } from "vue";
|
||||||
import { useCircleStore } from "./circle";
|
import { useCircleStore } from "./circle";
|
||||||
import { useUserStore } from "./user";
|
import { useUserStore } from "./user";
|
||||||
|
|
||||||
export type LearningSequenceCircleDocument = {
|
|
||||||
id: number;
|
|
||||||
title: string;
|
|
||||||
documents: CircleDocument[];
|
|
||||||
};
|
|
||||||
|
|
||||||
const SELECTED_COURSE_SESSIONS_KEY = "selectedCourseSessionMap";
|
const SELECTED_COURSE_SESSIONS_KEY = "selectedCourseSessionMap";
|
||||||
|
|
||||||
function loadCourseSessionsData(reload = false) {
|
export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
||||||
log.debug("loadCourseSessionsData called");
|
const loaded = ref(false);
|
||||||
const courseSessions = ref<CourseSession[]>([]);
|
const allCourseSessions = ref<CourseSession[]>([]);
|
||||||
|
|
||||||
async function loadAndUpdate() {
|
async function loadCourseSessionsData(reload = false) {
|
||||||
courseSessions.value = await itGetCached(`/api/course/sessions/`, {
|
log.debug("loadCourseSessionsData called");
|
||||||
|
|
||||||
|
allCourseSessions.value = await itGetCached(`/api/course/sessions/`, {
|
||||||
reload: reload,
|
reload: reload,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -38,7 +34,7 @@ function loadCourseSessionsData(reload = false) {
|
||||||
if (userStore.loggedIn) {
|
if (userStore.loggedIn) {
|
||||||
// TODO: refactor after implementing of Klassenkonzept
|
// TODO: refactor after implementing of Klassenkonzept
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
courseSessions.value.map(async (cs) => {
|
allCourseSessions.value.map(async (cs) => {
|
||||||
const users = (await itGetCached(`/api/course/sessions/${cs.id}/users/`, {
|
const users = (await itGetCached(`/api/course/sessions/${cs.id}/users/`, {
|
||||||
reload: reload,
|
reload: reload,
|
||||||
})) as CourseSessionUser[];
|
})) as CourseSessionUser[];
|
||||||
|
|
@ -46,26 +42,14 @@ function loadCourseSessionsData(reload = false) {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!courseSessions.value) {
|
if (!allCourseSessions.value) {
|
||||||
throw `No courseSessionData found for user`;
|
throw `No courseSessionData found for user`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loaded.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadAndUpdate(); // this will be called asynchronously, but does not block
|
|
||||||
|
|
||||||
// returns the empty sessions array at first, then after loading populates the ref
|
|
||||||
return { allCourseSessions: courseSessions };
|
|
||||||
}
|
|
||||||
|
|
||||||
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 { allCourseSessions } = loadCourseSessionsData();
|
|
||||||
const selectedCourseSessionMap = useLocalStorage(
|
const selectedCourseSessionMap = useLocalStorage(
|
||||||
SELECTED_COURSE_SESSIONS_KEY,
|
SELECTED_COURSE_SESSIONS_KEY,
|
||||||
new Map<string, number>()
|
new Map<string, number>()
|
||||||
|
|
@ -106,7 +90,7 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
||||||
function switchCourseSession(courseSession: CourseSession) {
|
function switchCourseSession(courseSession: CourseSession) {
|
||||||
log.debug("switchCourseSession", courseSession);
|
log.debug("switchCourseSession", courseSession);
|
||||||
selectedCourseSessionMap.value.set(courseSession.course.slug, courseSession.id);
|
selectedCourseSessionMap.value.set(courseSession.course.slug, courseSession.id);
|
||||||
// FIXME: clean up with VBV-305
|
// Emit event so that the App can re-render with the new courseSession
|
||||||
eventBus.emit("switchedCourseSession", courseSession.id);
|
eventBus.emit("switchedCourseSession", courseSession.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -244,7 +228,6 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uniqueCourseSessionsByCourse,
|
uniqueCourseSessionsByCourse,
|
||||||
currentCourseSession,
|
|
||||||
allCurrentCourseSessions,
|
allCurrentCourseSessions,
|
||||||
courseSessionForCourse,
|
courseSessionForCourse,
|
||||||
switchCourseSession,
|
switchCourseSession,
|
||||||
|
|
@ -258,6 +241,11 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
||||||
findAttendanceDay,
|
findAttendanceDay,
|
||||||
findAssignmentDetails,
|
findAssignmentDetails,
|
||||||
|
|
||||||
|
// use `useCurrentCourseSession` whenever possible
|
||||||
|
currentCourseSession,
|
||||||
|
|
||||||
|
loadCourseSessionsData,
|
||||||
|
loaded,
|
||||||
// only used so that `router.afterEach` can switch it
|
// only used so that `router.afterEach` can switch it
|
||||||
_currentCourseSlug,
|
_currentCourseSlug,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import log from "loglevel";
|
||||||
|
|
||||||
import { bustItGetCache, itGetCached, itPost } from "@/fetchHelpers";
|
import { bustItGetCache, itGetCached, itPost } from "@/fetchHelpers";
|
||||||
import { loadLocaleMessages, setI18nLanguage } from "@/i18n";
|
import { loadLocaleMessages, setI18nLanguage } from "@/i18n";
|
||||||
import { useAppStore } from "@/stores/app";
|
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
const logoutRedirectUrl = import.meta.env.VITE_LOGOUT_REDIRECT || "/";
|
const logoutRedirectUrl = import.meta.env.VITE_LOGOUT_REDIRECT || "/";
|
||||||
|
|
@ -85,11 +84,9 @@ export const useUserStore = defineStore({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async fetchUser() {
|
async fetchUser() {
|
||||||
const appStore = useAppStore();
|
|
||||||
const data = await itGetCached("/api/core/me/");
|
const data = await itGetCached("/api/core/me/");
|
||||||
this.$state = data;
|
this.$state = data;
|
||||||
this.loggedIn = true;
|
this.loggedIn = true;
|
||||||
appStore.userLoaded = true;
|
|
||||||
await setLocale(data.language);
|
await setLocale(data.language);
|
||||||
},
|
},
|
||||||
async setUserLanguages(language: AvailableLanguages) {
|
async setUserLanguages(language: AvailableLanguages) {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import mitt from "mitt";
|
import mitt from "mitt";
|
||||||
|
|
||||||
export type MittEvents = {
|
export type MittEvents = {
|
||||||
// FIXME: clean up with VBV-305
|
// event needed so that the App components do re-render
|
||||||
|
// and reload the current course session
|
||||||
switchedCourseSession: number;
|
switchedCourseSession: number;
|
||||||
|
|
||||||
finishedLearningContent: boolean;
|
finishedLearningContent: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue