269 lines
8.9 KiB
Vue
269 lines
8.9 KiB
Vue
<script setup lang="ts">
|
|
import { useCurrentCourseSession } from "@/composables";
|
|
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
|
import { ASSIGNMENT_COMPLETION_QUERY } from "@/graphql/queries";
|
|
import EvaluationSummary from "@/pages/cockpit/assignmentEvaluationPage/EvaluationSummary.vue";
|
|
import AssignmentIntroductionView from "@/pages/learningPath/learningContentPage/assignment/AssignmentIntroductionView.vue";
|
|
import AssignmentSubmissionView from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionView.vue";
|
|
import AssignmentTaskView from "@/pages/learningPath/learningContentPage/assignment/AssignmentTaskView.vue";
|
|
import LearningContentMultiLayout from "@/pages/learningPath/learningContentPage/layouts/LearningContentMultiLayout.vue";
|
|
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
import { useUserStore } from "@/stores/user";
|
|
import type {
|
|
Assignment,
|
|
AssignmentCompletion,
|
|
AssignmentTask,
|
|
CourseSessionAssignment,
|
|
CourseSessionUser,
|
|
LearningContentAssignment,
|
|
} from "@/types";
|
|
import { useMutation, useQuery } from "@urql/vue";
|
|
import { useRouteQuery } from "@vueuse/router";
|
|
import dayjs from "dayjs";
|
|
import * as log from "loglevel";
|
|
import { computed, onMounted, reactive } from "vue";
|
|
import { useTranslation } from "i18next-vue";
|
|
import { learningContentTypeData } from "@/utils/typeMaps";
|
|
|
|
const { t } = useTranslation();
|
|
const courseSession = useCurrentCourseSession();
|
|
const userStore = useUserStore();
|
|
|
|
interface State {
|
|
courseSessionAssignment: CourseSessionAssignment | undefined;
|
|
}
|
|
|
|
const state: State = reactive({
|
|
courseSessionAssignment: undefined,
|
|
});
|
|
|
|
const props = defineProps<{
|
|
learningContent: LearningContentAssignment;
|
|
}>();
|
|
|
|
const queryResult = useQuery({
|
|
query: ASSIGNMENT_COMPLETION_QUERY,
|
|
variables: {
|
|
courseSessionId: courseSession.value.id.toString(),
|
|
assignmentId: props.learningContent.content_assignment_id.toString(),
|
|
learningContentId: props.learningContent.id.toString(),
|
|
},
|
|
pause: true,
|
|
});
|
|
|
|
const upsertAssignmentCompletionMutation = useMutation(
|
|
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
|
|
);
|
|
|
|
// FIXME daniel: `useRouteQuery` from usevue is currently the reason that we have to
|
|
// fix the version of @vueuse/router and @vueuse/core to 10.1.0
|
|
// it fails with version 10.2.0. I have a reminder to check out the situation
|
|
// at the end of July 2023
|
|
// 0 = introduction, 1 - n = tasks, n+1 = submission
|
|
const stepIndex = useRouteQuery("step", "0", { transform: Number, mode: "push" });
|
|
|
|
const assignment = computed(
|
|
() => queryResult.data.value?.assignment as Assignment | undefined
|
|
);
|
|
const assignmentCompletion = computed(
|
|
() =>
|
|
queryResult.data.value?.assignment_completion as AssignmentCompletion | undefined
|
|
);
|
|
|
|
const completionStatus = computed(() => {
|
|
return assignmentCompletion.value?.completion_status ?? "IN_PROGRESS";
|
|
});
|
|
|
|
onMounted(async () => {
|
|
log.debug(
|
|
"AssignmentView mounted",
|
|
props.learningContent.content_assignment_id,
|
|
props.learningContent
|
|
);
|
|
|
|
state.courseSessionAssignment = useCourseSessionsStore().findCourseSessionAssignment(
|
|
props.learningContent.id
|
|
);
|
|
|
|
// create initial `AssignmentCompletion` first, so that it exists and we don't
|
|
// have reactivity problem accessing it.
|
|
await upsertAssignmentCompletionMutation.executeMutation({
|
|
assignmentId: props.learningContent.content_assignment_id.toString(),
|
|
courseSessionId: courseSession.value.id.toString(),
|
|
learningContentId: props.learningContent.id.toString(),
|
|
completionDataString: JSON.stringify({}),
|
|
completionStatus: "IN_PROGRESS",
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore
|
|
id: assignmentCompletion.value?.id,
|
|
});
|
|
queryResult.resume();
|
|
|
|
try {
|
|
if (
|
|
stepIndex.value === 0 &&
|
|
(completionStatus.value ?? "IN_PROGRESS") !== "IN_PROGRESS"
|
|
) {
|
|
stepIndex.value = numPages.value - 1;
|
|
}
|
|
} catch (error) {
|
|
log.error(error);
|
|
}
|
|
});
|
|
|
|
const numTasks = computed(() => assignment.value?.tasks?.length ?? 0);
|
|
const numPages = computed(() => {
|
|
if (assignmentType.value === "CASEWORK") {
|
|
// casework has extra submission page
|
|
return numTasks.value + 2;
|
|
}
|
|
|
|
return numTasks.value + 1;
|
|
});
|
|
const showPreviousButton = computed(() => stepIndex.value != 0);
|
|
const showNextButton = computed(() => stepIndex.value + 1 < numPages.value);
|
|
const showExitButton = computed(() => numPages.value === stepIndex.value + 1);
|
|
const dueDate = computed(() =>
|
|
dayjs(state.courseSessionAssignment?.submission_deadline_start)
|
|
);
|
|
const currentTask = computed(() => {
|
|
if (stepIndex.value > 0 && stepIndex.value <= numTasks.value) {
|
|
return assignment.value?.tasks[stepIndex.value - 1];
|
|
}
|
|
return undefined;
|
|
});
|
|
|
|
const handleBack = () => {
|
|
log.debug("handleBack");
|
|
if (stepIndex.value > 0) {
|
|
stepIndex.value -= 1;
|
|
}
|
|
log.debug(`pageIndex: ${stepIndex.value}`);
|
|
};
|
|
|
|
const handleContinue = () => {
|
|
log.debug("handleContinue");
|
|
if (stepIndex.value + 1 < numPages.value) {
|
|
stepIndex.value += 1;
|
|
}
|
|
log.debug(`pageIndex: ${stepIndex.value}`);
|
|
};
|
|
|
|
const jumpToTask = (task: AssignmentTask) => {
|
|
log.debug("jumpToTask", task);
|
|
const index = assignment.value?.tasks.findIndex((t) => t.id === task.id);
|
|
if (index && index >= 0) {
|
|
stepIndex.value = index + 1;
|
|
}
|
|
log.debug(`pageIndex: ${stepIndex.value}`);
|
|
};
|
|
|
|
const getTitle = () => {
|
|
if (0 === stepIndex.value) {
|
|
return t("general.introduction");
|
|
} else if (
|
|
assignmentType.value === "CASEWORK" &&
|
|
stepIndex.value === numPages.value - 1
|
|
) {
|
|
return t("general.submission");
|
|
}
|
|
return currentTask?.value?.value.title ?? "Unknown";
|
|
};
|
|
|
|
const assignmentType = computed(() => {
|
|
return assignment.value?.assignment_type ?? "CASEWORK";
|
|
});
|
|
|
|
const subTitle = computed(() => {
|
|
if (assignment.value) {
|
|
const prefix = learningContentTypeData(props.learningContent).title;
|
|
return `${prefix}: ${assignment.value?.title ?? ""}`;
|
|
}
|
|
return "";
|
|
});
|
|
|
|
const assignmentUser = computed(() => {
|
|
return courseSession.value.users.find(
|
|
(user) => user.user_id === userStore.id
|
|
) as CourseSessionUser;
|
|
});
|
|
|
|
const endBadgeText = computed(() => {
|
|
if (assignmentType.value === "PREP_ASSIGNMENT") {
|
|
return "Aufgaben";
|
|
} else if (assignmentType.value === "CASEWORK") {
|
|
return "Abgabe";
|
|
}
|
|
|
|
// just return the number of tasks as default
|
|
return (assignment.value?.tasks.length ?? 0).toString();
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div v-if="queryResult.fetching.value"></div>
|
|
<div v-else-if="queryResult.error.value">{{ queryResult.error.value }}</div>
|
|
<div v-else>
|
|
<div v-if="assignment && assignmentCompletion">
|
|
<div class="flex">
|
|
<LearningContentMultiLayout
|
|
:current-step="stepIndex"
|
|
:sub-title="subTitle"
|
|
:title="getTitle()"
|
|
:learning-content="props.learningContent"
|
|
:steps-count="numPages"
|
|
:show-next-button="showNextButton && stepIndex !== 0"
|
|
:show-exit-button="showExitButton"
|
|
:show-start-button="showNextButton && stepIndex === 0"
|
|
:show-previous-button="showPreviousButton"
|
|
:base-url="props.learningContent.frontend_url"
|
|
step-query-param="step"
|
|
start-badge-text="Einleitung"
|
|
:end-badge-text="endBadgeText"
|
|
close-button-variant="close"
|
|
@previous="handleBack()"
|
|
@next="handleContinue()"
|
|
>
|
|
<div class="flex">
|
|
<div>
|
|
<AssignmentIntroductionView
|
|
v-if="stepIndex === 0"
|
|
:due-date="dueDate"
|
|
:assignment="assignment"
|
|
></AssignmentIntroductionView>
|
|
<AssignmentTaskView
|
|
v-else-if="currentTask"
|
|
:task="currentTask"
|
|
:assignment-id="props.learningContent.content_assignment_id"
|
|
:assignment-completion="assignmentCompletion"
|
|
:learning-content-id="props.learningContent.id"
|
|
></AssignmentTaskView>
|
|
<AssignmentSubmissionView
|
|
v-else-if="assignmentType === 'CASEWORK' && stepIndex + 1 === numPages"
|
|
:due-date="dueDate"
|
|
:assignment="assignment"
|
|
:assignment-completion="assignmentCompletion"
|
|
:learning-content-id="props.learningContent.id"
|
|
:course-session-id="courseSession.id"
|
|
@edit-task="jumpToTask($event)"
|
|
></AssignmentSubmissionView>
|
|
</div>
|
|
</div>
|
|
</LearningContentMultiLayout>
|
|
<div
|
|
v-if="assignmentCompletion?.completion_status === 'EVALUATION_SUBMITTED'"
|
|
class="min-w-2/5 mr-4 bg-gray-200 px-6 py-6"
|
|
>
|
|
<EvaluationSummary
|
|
:assignment-user="assignmentUser"
|
|
:assignment="assignment"
|
|
:assignment-completion="assignmentCompletion"
|
|
:show-evaluation-user="true"
|
|
></EvaluationSummary>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else>Could not load all data</div>
|
|
</div>
|
|
</template>
|