feat: wraps self evaluation feedback request member side

This commit is contained in:
Livio Bieri 2024-01-23 22:34:04 +01:00
parent 3a519e2220
commit 412172515f
5 changed files with 255 additions and 105 deletions

View File

@ -28,8 +28,8 @@ import type {
import { useQuery } from "@urql/vue";
import orderBy from "lodash/orderBy";
import log from "loglevel";
import type { ComputedRef } from "vue";
import { computed, onMounted, ref, watchEffect } from "vue";
import type { ComputedRef, Ref } from "vue";
import { computed, onMounted, ref, toValue, watchEffect } from "vue";
export function useCurrentCourseSession() {
/**
@ -469,17 +469,52 @@ export function useFileUpload() {
export function useLearningMentors() {
const learningMentors = ref<LearningMentor[]>([]);
const currentCourseSessionId = useCurrentCourseSession().value.id;
const loading = ref(false);
const fetchMentors = async () => {
loading.value = true;
const { data } = await useCSRFFetch(
`/api/mentor/${currentCourseSessionId}/mentors`
).json();
learningMentors.value = data.value;
loading.value = false;
};
onMounted(fetchMentors);
return {
learningMentors,
loading,
};
}
export function useSelfEvaluationFeedback(learningUnitId: Ref<string> | string) {
const feedback = ref({});
const loading = ref(false);
const exists = ref(false);
const url = `/api/self-evaluation-feedback/requester/${toValue(
learningUnitId
)}/feedback`;
const fetchSelfEvaluationFeedback = async () => {
loading.value = true;
const { data, statusCode } = await useCSRFFetch(url).json();
loading.value = false;
if (statusCode.value === 404) {
exists.value = false;
return;
} else {
exists.value = true;
feedback.value = data.value;
}
};
onMounted(fetchSelfEvaluationFeedback);
return {
feedback,
exists,
loading,
};
}

View File

@ -11,7 +11,7 @@ import { useRouteQuery } from "@vueuse/router";
import { computed, onUnmounted } from "vue";
import { getPreviousRoute } from "@/router/history";
import { getCompetenceNaviUrl } from "@/utils/utils";
import SelfEvaluationSubmit from "@/pages/learningPath/selfEvaluationPage/SelfEvaluationSubmit.vue";
import SelfEvaluationSubmit from "@/pages/learningPath/selfEvaluationPage/SelfEvaluationRequestFeedback.vue";
log.debug("LearningContent.vue setup");

View File

@ -0,0 +1,170 @@
<script setup lang="ts">
import type { LearningUnit, LearningUnitPerformanceCriteria } from "@/types";
import { useLearningMentors, useSelfEvaluationFeedback } from "@/composables";
import { computed, ref } from "vue";
import ItButton from "@/components/ui/ItButton.vue";
import NoMentorInformationPanel from "@/components/mentor/NoMentorInformationPanel.vue";
import { useCSRFFetch } from "@/fetchHelpers";
const props = defineProps<{
learningUnit: LearningUnit;
criteria: LearningUnitPerformanceCriteria[];
}>();
const {
feedback: storedFeedback,
exists: isStoredFeedbackAvailable,
loading: isStoredFeedbackLoading,
} = useSelfEvaluationFeedback(props.learningUnit.id);
// if no feedback is stored "current session"
// state management (mentor selection etc.)
const { learningMentors, loading: isLearningMentorsLoading } = useLearningMentors();
const isCurrentSessionFeedbackRequested = ref(false);
const currentSessionRequestedMentor = ref();
const VisualState = {
LOADING: "LOADING",
NO_MENTOR: "NO_MENTOR",
HAS_REQUESTED_FEEDBACK: "HAS_REQUESTED_FEEDBACK",
HAS_NOT_REQUESTED_FEEDBACK: "HAS_NOT_REQUESTED_FEEDBACK",
};
const currentVisualState = computed(() => {
if (isLearningMentorsLoading.value || isStoredFeedbackLoading.value) {
return VisualState.LOADING;
} else if (learningMentors.value.length == 0) {
return VisualState.NO_MENTOR;
} else if (
isStoredFeedbackAvailable.value ||
isCurrentSessionFeedbackRequested.value
) {
return VisualState.HAS_REQUESTED_FEEDBACK;
} else {
return VisualState.HAS_NOT_REQUESTED_FEEDBACK;
}
});
const feedbackMentorName = computed(() => {
const mentor = isStoredFeedbackAvailable.value
? (storedFeedback.value as any).feedback_provider_user
: isCurrentSessionFeedbackRequested.value
? currentSessionRequestedMentor.value
: null;
return mentor ? `${mentor.first_name} ${mentor.last_name}` : "";
});
const onSubmitForMentorFeedback = async () => {
const url = `/api/self-evaluation-feedback/requester/${props.learningUnit.id}/feedback/start`;
const { error } = await useCSRFFetch(url).post({
feedback_provider_user_id: currentSessionRequestedMentor.value.id,
});
if (!error.value) {
isCurrentSessionFeedbackRequested.value = true;
}
};
</script>
<template>
<div v-if="currentVisualState != VisualState.LOADING" class="mb-10 w-full pt-8">
<div class="w-full border border-gray-400">
<div class="m-6 space-y-6">
<h3 class="heading-3">
{{ $t("a.Selbsteinschätzung teilen") }}
</h3>
<div v-if="currentVisualState == VisualState.NO_MENTOR">
<NoMentorInformationPanel />
</div>
<div v-if="currentVisualState == VisualState.HAS_REQUESTED_FEEDBACK">
<div class="flex space-x-2 bg-green-200 p-4">
<it-icon-check class="it-icon h-6 w-6 text-green-700" />
<div>
{{
$t(
"a.Du hast deine Selbsteinschätzung erfolgreich mit FULL_NAME geteilt.",
{
FULL_NAME: feedbackMentorName,
}
)
}}
</div>
</div>
<div class="pt-6">
{{
$t(
"a.FULL_NAME wird eine Fremdeinschätzung für dich vornehmen. Du wirst per Benachrichtigung informiert, sobald die Fremdeinschätzung für dich freigegeben wurde.",
{ FULL_NAME: feedbackMentorName }
)
}}
</div>
</div>
<div v-else-if="currentVisualState == VisualState.HAS_NOT_REQUESTED_FEEDBACK">
<p>
{{
$t(
"a.Du kannst deine Selbsteinschätzung mit deiner Lernbegleitung teilen, damit sie eine Fremdeinschätzung vornimmt."
)
}}
</p>
<select
v-model="currentSessionRequestedMentor"
data-cy="select-learning-mentor"
>
<option
v-for="learningMentor in learningMentors"
:key="learningMentor.id"
:value="learningMentor.mentor"
>
{{ learningMentor.mentor.first_name }}
{{ learningMentor.mentor.last_name }}
</option>
</select>
<ItButton
class="mt-6"
variant="primary"
size="large"
:disabled="!currentSessionRequestedMentor"
data-cy="submit-assignment"
@click="onSubmitForMentorFeedback"
>
<p v-if="!currentSessionRequestedMentor">
{{ $t("a.Selbsteinschätzung teilen") }}
</p>
<p v-else>
{{
$t("a.Selbsteinschätzung mit MENTOR_NAME teilen", {
MENTOR_NAME: feedbackMentorName,
})
}}
</p>
</ItButton>
</div>
</div>
</div>
</div>
<div
v-for="(completion, index) in criteria"
:key="completion.id"
class="flex flex-col space-y-4 border-t border-gray-400 py-8"
>
<div class="flex justify-between">
<b>{{ completion.title }}</b>
<router-link :to="`${learningUnit.evaluate_url}?step=${index}`" class="underline">
{{ $t("a.Bearbeiten") }}
</router-link>
</div>
<div
v-if="completion.completion_status == 'SUCCESS'"
class="flex flex-row items-center space-x-2"
>
<it-icon-smiley-happy class="h-6 w-6" />
<span>{{ $t("selfEvaluation.yes") }}</span>
</div>
<div v-else class="flex flex-row items-center space-x-2">
<it-icon-smiley-thinking class="h-6 w-6" />
<span>{{ $t("selfEvaluation.no") }}</span>
</div>
</div>
</template>
<style scoped></style>

View File

@ -1,101 +0,0 @@
<script setup lang="ts">
import type { LearningUnit, LearningUnitPerformanceCriteria } from "@/types";
import { useLearningMentors } from "@/composables";
import { ref } from "vue";
import ItButton from "@/components/ui/ItButton.vue";
import NoMentorInformationPanel from "@/components/mentor/NoMentorInformationPanel.vue";
defineProps<{
learningUnit: LearningUnit;
criteria: LearningUnitPerformanceCriteria[];
}>();
const selectedLearningMentor = ref();
const learningMentors = useLearningMentors().learningMentors;
const onSubmitForMentorFeedback = async () => {
try {
console.log("submit for mentor feedback");
} catch (error) {
console.log("Could not submit assignment", error);
}
};
</script>
<template>
<div class="mb-10 w-full pt-8">
<div class="w-full border border-gray-400">
<div class="m-6 space-y-6">
<h3 class="heading-3">
{{ $t("a.Selbsteinschätzung teilen") }}
</h3>
<div v-if="learningMentors?.length">
<p>
{{
$t(
"a.Du kannst deine Selbsteinschätzung mit deiner Lernbegleitung teilen, damit sie eine Fremdeinschätzung vornimmt."
)
}}
</p>
<select v-model="selectedLearningMentor" data-cy="select-learning-mentor">
<option
v-for="learningMentor in learningMentors"
:key="learningMentor.id"
:value="learningMentor.mentor"
>
{{ learningMentor.mentor.first_name }}
{{ learningMentor.mentor.last_name }}
</option>
</select>
<ItButton
class="mt-6"
variant="primary"
size="large"
:disabled="!selectedLearningMentor"
data-cy="submit-assignment"
@click="onSubmitForMentorFeedback"
>
<p v-if="!selectedLearningMentor">
{{ $t("a.Selbsteinschätzung teilen") }}
</p>
<p v-else>
{{
$t("a.Selbsteinschätzung mit MENTOR_NAME teilen", {
MENTOR_NAME: selectedLearningMentor.first_name,
})
}}
</p>
</ItButton>
</div>
<div v-else>
<NoMentorInformationPanel />
</div>
</div>
</div>
</div>
<div
v-for="(pc, index) in criteria"
:key="pc.id"
class="flex flex-col space-y-4 border-t border-gray-400 py-8"
>
<div class="flex justify-between">
<b>{{ pc.title }}</b>
<router-link :to="`${learningUnit.evaluate_url}?step=${index}`" class="underline">
{{ $t("a.Bearbeiten") }}
</router-link>
</div>
<div
v-if="pc.completion_status == 'SUCCESS'"
class="flex flex-row items-center space-x-2"
>
<it-icon-smiley-happy class="h-6 w-6" />
<span>{{ $t("selfEvaluation.yes") }}</span>
</div>
<div v-else class="flex flex-row items-center space-x-2">
<it-icon-smiley-thinking class="h-6 w-6" />
<span>{{ $t("selfEvaluation.no") }}</span>
</div>
</div>
</template>
<style scoped></style>

View File

@ -1,3 +1,49 @@
from django.contrib import admin
# Register your models here.
from vbv_lernwelt.self_evaluation_feedback.models import (
CourseCompletionFeedback,
SelfEvaluationFeedback,
)
@admin.register(SelfEvaluationFeedback)
class CourseSessionAdmin(admin.ModelAdmin):
list_display = (
"id",
"feedback_submitted",
"feedback_requester_user",
"feedback_provider_user",
"learning_unit",
)
list_filter = (
"feedback_submitted",
"feedback_requester_user",
"feedback_provider_user",
"learning_unit",
)
search_fields = (
"feedback_submitted",
"feedback_requester_user",
"feedback_provider_user",
"learning_unit",
)
@admin.register(CourseCompletionFeedback)
class CourseSessionAdmin(admin.ModelAdmin):
list_display = (
"id",
"feedback",
"course_completion",
"feedback_assessment",
)
list_filter = (
"feedback",
"course_completion",
"feedback_assessment",
)
search_fields = (
"feedback",
"course_completion",
"feedback_assessment",
)