vbv/client/src/components/learningPath/SelfEvaluation.vue

204 lines
7.0 KiB
Vue

<script setup lang="ts">
import { useCircleStore } from "@/stores/circle";
import type {
CircleType,
CourseCompletionStatus,
LearningUnit,
LearningUnitPerformanceCriteria,
} from "@/types";
import * as log from "loglevel";
import { useCourseDataWithCompletion, useCurrentCourseSession } from "@/composables";
import LearningContentContainer from "@/pages/learningPath/learningContentPage/LearningContentContainer.vue";
import LearningContentMultiLayout from "@/pages/learningPath/learningContentPage/layouts/LearningContentMultiLayout.vue";
import SelfEvaluationRequestFeedbackPage from "@/pages/learningPath/selfEvaluationPage/SelfEvaluationRequestFeedbackPage.vue";
import { getPreviousRoute } from "@/router/history";
import eventBus from "@/utils/eventBus";
import { getCompetenceNaviUrl } from "@/utils/utils";
import { useRouteQuery } from "@vueuse/router";
import { computed, onUnmounted } from "vue";
log.debug("LearningContent.vue setup");
const props = defineProps<{
learningUnit: LearningUnit;
circle: CircleType;
}>();
const circleStore = useCircleStore();
const courseSession = useCurrentCourseSession();
const courseCompletionData = useCourseDataWithCompletion();
// if we have preview rights, we can only preview the learning content -> read only
const isReadOnly = computed(() => courseSession.value.actions.includes("preview"));
const questions = computed(() => props.learningUnit?.performance_criteria ?? []);
const numPages = computed(() => {
if (learningUnitHasFeedbackPage.value) {
return questions.value.length + 1;
} else {
return questions.value.length;
}
});
const questionIndex = useRouteQuery("step", "0", { transform: Number, mode: "push" });
const previousRoute = getPreviousRoute();
const learningUnitHasFeedbackPage = computed(
() =>
courseSession.value.course.configuration.enable_learning_mentor &&
courseSession.value.course.configuration.is_vv &&
!isReadOnly.value
);
const currentQuestion = computed(() => questions.value[questionIndex.value]);
const showPreviousButton = computed(() => questionIndex.value != 0);
const showNextButton = computed(
() => questionIndex.value + 1 < numPages.value && numPages.value > 1
);
const isLastStep = computed(
() => questions.value?.length === 1 || numPages.value == questionIndex.value + 1
);
function handleContinue() {
log.debug("handleContinue");
// not answering a question is allowed especially,
// nonetheless we want to still know this state in the backend!
if (currentQuestion.value && currentQuestion.value.completion_status === "UNKNOWN") {
markCompletion(currentQuestion.value, "UNKNOWN");
}
if (questionIndex.value + 1 < numPages.value) {
log.debug("increment questionIndex", questionIndex.value);
questionIndex.value += 1;
} else {
log.debug("continue to next learning content");
circleStore.continueFromSelfEvaluation(props.learningUnit, props.circle);
}
}
function markCompletion(
question: LearningUnitPerformanceCriteria,
status: CourseCompletionStatus
) {
if (isReadOnly.value) {
log.debug("We are in read only mode, so we do not mark the completion");
return;
} else {
log.debug("markCompletion", question, status);
courseCompletionData.markCompletion(question, status);
}
}
function handleBack() {
log.debug("handleBack");
if (questionIndex.value > 0 && questionIndex.value < numPages.value) {
questionIndex.value -= 1;
}
}
function handleFinishedLearningContent() {
circleStore.closeSelfEvaluation(props.learningUnit, props.circle, previousRoute);
}
eventBus.on("finishedLearningContent", handleFinishedLearningContent);
onUnmounted(() => {
eventBus.off("finishedLearningContent", handleFinishedLearningContent);
});
</script>
<template>
<div v-if="learningUnit">
<LearningContentContainer
@exit="
circleStore.closeSelfEvaluation(props.learningUnit, props.circle, previousRoute)
"
>
<LearningContentMultiLayout
:current-step="questionIndex"
:sub-title="$t('a.Selbsteinschätzung')"
:title="`${learningUnit.title}`"
icon="it-icon-lc-learning-module"
:steps-count="numPages"
:show-next-button="showNextButton"
:show-exit-button="isLastStep"
:show-start-button="false"
:show-previous-button="showPreviousButton"
:base-url="props.learningUnit.evaluate_url"
:close-button-variant="
learningUnitHasFeedbackPage || isReadOnly ? 'close' : 'mark_as_done'
"
:end-badge-text="
learningUnitHasFeedbackPage ? $t('general.submission') : undefined
"
@previous="handleBack()"
@next="handleContinue()"
>
<div v-if="currentQuestion" class="h-full">
<div class="mt-8">
<h3 class="heading-3">
{{ currentQuestion.title }}
</h3>
<div
class="mt-4 flex flex-col justify-between gap-8 lg:mt-8 lg:flex-row lg:gap-12"
>
<button
:disabled="isReadOnly"
class="inline-flex flex-1 items-center border p-4 text-left"
:class="{
'border-green-500': currentQuestion.completion_status === 'SUCCESS',
'border-2': currentQuestion.completion_status === 'SUCCESS',
}"
data-cy="success"
@click="markCompletion(currentQuestion, 'SUCCESS')"
>
<it-icon-smiley-happy class="mr-4 h-16 w-16"></it-icon-smiley-happy>
<span class="text-large font-bold">
{{ $t("selfEvaluation.yes") }}
</span>
</button>
<button
:disabled="isReadOnly"
class="inline-flex flex-1 items-center border p-4 text-left"
:class="{
'border-orange-500': currentQuestion.completion_status === 'FAIL',
'border-2': currentQuestion.completion_status === 'FAIL',
}"
data-cy="fail"
@click="markCompletion(currentQuestion, 'FAIL')"
>
<it-icon-smiley-thinking
class="mr-4 h-16 w-16"
></it-icon-smiley-thinking>
<span class="text-xl font-bold">{{ $t("selfEvaluation.no") }}</span>
</button>
</div>
<div class="mt-6 lg:mt-12">
{{ $t("selfEvaluation.progressText") }}
<router-link
:to="getCompetenceNaviUrl(courseSession.course.slug)"
class="text-primary-500 underline"
>
{{ $t("selfEvaluation.progressLink") }}
</router-link>
</div>
</div>
</div>
<SelfEvaluationRequestFeedbackPage
v-else-if="isLastStep && learningUnitHasFeedbackPage"
:learning-unit="props.learningUnit"
:criteria="questions"
/>
</LearningContentMultiLayout>
</LearningContentContainer>
</div>
</template>
<style scoped></style>