Make `useCurrentCourseSession` reactive

This commit is contained in:
Daniel Egger 2023-05-19 09:52:11 +02:00
parent eaf12fbc87
commit bcc42eaf83
16 changed files with 44 additions and 36 deletions

View File

@ -31,7 +31,7 @@ onMounted(() => {
eventBus.on("switchedCourseSession", () => {
// Rerender the component tree, when the course session gets switched.
// Mainly so that the `useCurrentCourseSession` composable gets re-evaluated
// So that the current learning path completion data gets updated.
componentKey.value++;
log.info("Switched course session, re-evaluate component tree");
});

View File

@ -1,27 +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.
* ATTENTION: The value is not reactive! So the components need to be re-rendered
* when the value changes. This is currently done with the "switchedCourseSession"
* event handler in the App.vue component.
*/
const store = useCourseSessionsStore();
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.
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 the current NON-REACTIVE course session
return store.currentCourseSession as CourseSession;
);
}
return store.currentCourseSession;
}
);
return result;
}

View File

@ -22,7 +22,7 @@ onMounted(async () => {
log.debug("CockpitParentPage mounted", props.courseSlug);
try {
await cockpitStore.loadCourseSessionUsers(courseSession.id);
await cockpitStore.loadCourseSessionUsers(courseSession.value.id);
cockpitStore.courseSessionUsers?.forEach((csu) => {
competenceStore.loadCompetenceProfilePage(
props.courseSlug + "-competence",

View File

@ -144,7 +144,7 @@ const feedbackData = reactive<FeedbackData>({ amount: 0, questions: {} });
onMounted(async () => {
log.debug("FeedbackPage mounted");
const data = await itGet(
`/api/core/feedback/${courseSession.course.id}/${props.circleId}`
`/api/core/feedback/${courseSession.value.course.id}/${props.circleId}`
);
Object.assign(feedbackData, data);
});

View File

@ -39,7 +39,7 @@ const router = useRouter();
const queryResult = useQuery({
query: ASSIGNMENT_COMPLETION_QUERY,
variables: {
courseSessionId: courseSession.id.toString(),
courseSessionId: courseSession.value.id.toString(),
assignmentId: props.assignmentId,
assignmentUserId: props.userId,
},
@ -48,7 +48,7 @@ const queryResult = useQuery({
onMounted(async () => {
log.debug("AssignmentView mounted", props.assignmentId, props.userId);
state.assignmentUser = courseSession.users.find(
state.assignmentUser = courseSession.value.users.find(
(user) => user.user_id === Number(props.userId)
);
});

View File

@ -29,7 +29,7 @@ async function startEvaluation() {
// noinspection TypeScriptValidateTypes
upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignment.id.toString(),
courseSessionId: courseSession.id.toString(),
courseSessionId: courseSession.value.id.toString(),
assignmentUserId: props.assignmentUser.user_id.toString(),
completionStatus: "EVALUATION_IN_PROGRESS",
completionDataString: JSON.stringify({}),

View File

@ -44,7 +44,7 @@ async function submitEvaluation() {
// noinspection TypeScriptValidateTypes
upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignment.id.toString(),
courseSessionId: courseSession.id.toString(),
courseSessionId: courseSession.value.id.toString(),
assignmentUserId: props.assignmentUser.user_id.toString(),
completionStatus: "EVALUATION_SUBMITTED",
completionDataString: JSON.stringify({}),
@ -87,7 +87,7 @@ const grade = computed(() => {
const evaluationUser = computed(() => {
if (props.assignmentCompletion.evaluation_user) {
return (courseSession.users ?? []).find(
return (courseSession.value.users ?? []).find(
(user) => user.user_id === Number(props.assignmentCompletion.evaluation_user)
) as CourseSessionUser;
}

View File

@ -68,7 +68,7 @@ async function evaluateAssignmentCompletion(completionData: AssignmentCompletion
// noinspection TypeScriptValidateTypes
upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignment.id.toString(),
courseSessionId: courseSession.id.toString(),
courseSessionId: courseSession.value.id.toString(),
assignmentUserId: props.assignmentUser.user_id.toString(),
completionStatus: "EVALUATION_IN_PROGRESS",
completionDataString: JSON.stringify(completionData),

View File

@ -23,7 +23,7 @@ onMounted(async () => {
const assignments = computed(() => {
return calcAssignmentLearningContents(
learningPathStore.learningPathForUser(courseSession.course.slug, userStore.id)
learningPathStore.learningPathForUser(courseSession.value.course.slug, userStore.id)
);
});
</script>

View File

@ -62,7 +62,7 @@ const onSubmit = async () => {
// noinspection TypeScriptValidateTypes
upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignment.id.toString(),
courseSessionId: courseSession.id.toString(),
courseSessionId: courseSession.value.id.toString(),
completionDataString: JSON.stringify({}),
completionStatus: "SUBMITTED",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

View File

@ -34,7 +34,7 @@ async function upsertAssignmentCompletion(completion_data: AssignmentCompletionD
// noinspection TypeScriptValidateTypes
await upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignmentId.toString(),
courseSessionId: courseSession.id.toString(),
courseSessionId: courseSession.value.id.toString(),
completionDataString: JSON.stringify(completion_data),
completionStatus: "IN_PROGRESS",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

View File

@ -43,7 +43,7 @@ const props = defineProps<{
const queryResult = useQuery({
query: ASSIGNMENT_COMPLETION_QUERY,
variables: {
courseSessionId: courseSession.id.toString(),
courseSessionId: courseSession.value.id.toString(),
assignmentId: props.learningContent.content_assignment_id.toString(),
},
pause: true,
@ -80,7 +80,7 @@ onMounted(async () => {
// noinspection TypeScriptValidateTypes
await upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.learningContent.content_assignment_id.toString(),
courseSessionId: courseSession.id.toString(),
courseSessionId: courseSession.value.id.toString(),
completionDataString: JSON.stringify({}),
completionStatus: "IN_PROGRESS",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
@ -151,7 +151,7 @@ const getTitle = () => {
};
const assignmentUser = computed(() => {
return courseSession.users.find(
return courseSession.value.users.find(
(user) => user.user_id === Number(userStore.id)
) as CourseSessionUser;
});

View File

@ -1,6 +1,7 @@
<script setup lang="ts">
import * as log from "loglevel";
import { useCurrentCourseSession } from "@/composables";
import LearningPathAppointmentsMock from "@/pages/learningPath/learningPathPage/LearningPathAppointmentsMock.vue";
import LearningPathListView from "@/pages/learningPath/learningPathPage/LearningPathListView.vue";
import LearningPathPathView from "@/pages/learningPath/learningPathPage/LearningPathPathView.vue";
@ -20,6 +21,7 @@ const props = defineProps<{
const breakpoints = useBreakpoints(breakpointsTailwind);
const learningPathStore = useLearningPathStore();
const userStore = useUserStore();
const courseSession = useCurrentCourseSession();
// Layout state
const useMobileLayout = breakpoints.smaller("sm");
@ -80,6 +82,7 @@ const changeViewType = (viewType: ViewType) => {
<p class="font-bold">
{{ $t("learningPathPage.welcomeBack", { name: userStore.first_name }) }}
</p>
<pre>{{ courseSession.title }}</pre>
<h2 data-cy="learning-path-title">
{{ learningPath?.title }}
</h2>

View File

@ -1,6 +1,6 @@
import { useCurrentCourseSession } from "@/composables";
import { itGetCached } from "@/fetchHelpers";
import { useCompletionStore } from "@/stores/completion";
import { useCourseSessionsStore } from "@/stores/courseSessions";
import { useUserStore } from "@/stores/user";
import type {
CircleLight,
@ -166,11 +166,10 @@ export const useCompetenceStore = defineStore({
if (competenceProfilePage) {
const completionStore = useCompletionStore();
const courseSessionsStore = useCourseSessionsStore();
const courseSession = courseSessionsStore.currentCourseSession;
const courseSession = useCurrentCourseSession();
if (courseSession) {
const completionData = await completionStore.loadCourseSessionCompletionData(
courseSession.id,
courseSession.value.id,
userId
);

View File

@ -228,7 +228,6 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
return {
uniqueCourseSessionsByCourse,
currentCourseSession,
allCurrentCourseSessions,
courseSessionForCourse,
switchCourseSession,
@ -242,9 +241,12 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
findAttendanceDay,
findAssignmentDetails,
// only used so that `router.afterEach` can switch it
// use `useCurrentCourseSession` whenever possible
currentCourseSession,
loadCourseSessionsData,
loaded,
// only used so that `router.afterEach` can switch it
_currentCourseSlug,
// only used for unit testing

View File

@ -1,7 +1,8 @@
import mitt from "mitt";
export type MittEvents = {
// event needed so that the App components do re-render when the course session changes
// event needed so that the App components do re-render
// and reload the current course session
switchedCourseSession: number;
finishedLearningContent: boolean;