feat: learning mentor mgmt UI

This commit is contained in:
Reto Aebersold 2023-12-12 11:02:07 +01:00
parent 9eb2bbceba
commit 2a8b3198b2
5 changed files with 73 additions and 19 deletions

View File

@ -1,4 +1,5 @@
import { getCookieValue } from "@/router/guards";
import { createFetch } from "@vueuse/core";
class FetchError extends Error {
response: Response;
@ -88,3 +89,13 @@ export const itGetCached = (
return itGetPromiseCache.get(url.toString()) as Promise<any>;
};
export const useCSRFFetch = createFetch({
options: {
async beforeFetch({ options }) {
const headers = options.headers as Record<string, string>;
headers["X-CSRFToken"] = getCookieValue("csrftoken");
return { options };
},
},
});

View File

@ -1,18 +1,18 @@
<script setup lang="ts">
import { useFetch } from "@vueuse/core";
import { useCurrentCourseSession } from "@/composables";
import ItModal from "@/components/ui/ItModal.vue";
import { computed, ref } from "vue";
import { useCSRFFetch } from "@/fetchHelpers";
const courseSession = useCurrentCourseSession();
const showInvitationModal = ref(false);
const { data: mentors } = useFetch(
const { execute: refreshMentors, data: mentors } = useCSRFFetch(
`/api/mentor/${courseSession.value.course.id}/mentors`
).json();
const { data: invitations } = useFetch(
const { execute: refreshInvitations, data: invitations } = useCSRFFetch(
`/api/mentor/${courseSession.value.course.id}/invitations`
).json();
@ -22,6 +22,20 @@ const hasMentors = computed(() => {
(invitations.value && invitations.value.length > 0)
);
});
const removeInvitation = async (invitationId: string) => {
await useCSRFFetch(
`/api/mentor/${courseSession.value.course.id}/invitations/${invitationId}/delete`
).delete();
await refreshInvitations();
};
const removeMentor = async (mentorId: string) => {
await useCSRFFetch(
`/api/mentor/${courseSession.value.course.id}/mentors/${mentorId}/leave`
).delete();
await refreshMentors();
};
</script>
<template>
@ -52,26 +66,44 @@ const hasMentors = computed(() => {
<div
v-for="invitation in invitations"
:key="invitation.id"
class="flex flex-row justify-between gap-4 border-b py-4"
class="flex flex-col justify-between gap-4 border-b py-4 md:flex-row md:gap-16"
>
{{ invitation.email }}
<div class="flex items-center">
<it-icon-info class="it-icon mr-2 h-6 w-6" />
{{ $t("a.Die Einladung wurde noch nicht angenommen.") }}
<div class="flex flex-col justify-between md:flex-grow md:flex-row">
{{ invitation.email }}
<div class="flex items-center">
<it-icon-info class="it-icon mr-2 h-6 w-6" />
{{ $t("a.Die Einladung wurde noch nicht angenommen.") }}
</div>
</div>
<button class="underline">
<button @click="removeInvitation(invitation.id)" class="underline">
{{ $t("a.Entfernen") }}
</button>
</div>
<div
v-for="mentor in mentors"
:key="mentor.id"
class="flex flex-col justify-between gap-4 border-b py-4"
v-for="learningMentor in mentors"
:key="learningMentor.id"
class="flex flex-col justify-between gap-4 border-b py-4 md:flex-row md:gap-16"
>
{{ mentor.name }}
<div class="flex items-center space-x-2">
<img
:alt="learningMentor.mentor.last_name"
class="h-11 w-11 rounded-full"
:src="learningMentor.mentor.avatar_url"
/>
<div>
<div class="text-bold">
{{ learningMentor.mentor.first_name }}
{{ learningMentor.mentor.last_name }}
</div>
{{ learningMentor.mentor.email }}
</div>
</div>
<button @click="removeMentor(learningMentor.id)" class="underline">
{{ $t("a.Entfernen") }}
</button>
</div>
</div>
<div v-if="!hasMentors" class="flex items-center">
<div v-if="!hasMentors" class="mt-8 flex items-center">
<it-icon-info class="it-icon mr-2 h-6 w-6" />
{{
$t("a.Aktuell hast du noch keine Person als Lernbegleitung eingeladen.")

View File

@ -1,6 +1,7 @@
from rest_framework import serializers
from vbv_lernwelt.learning_mentor.models import MentorInvitation
from vbv_lernwelt.core.serializers import UserSerializer
from vbv_lernwelt.learning_mentor.models import LearningMentor, MentorInvitation
class PraxisAssignmentCompletionSerializer(serializers.Serializer):
@ -33,3 +34,12 @@ class InvitationSerializer(serializers.ModelSerializer):
email=validated_data["email"], defaults={"participant": participant}
)
return invitation
class MentorSerializer(serializers.ModelSerializer):
mentor = UserSerializer(read_only=True)
class Meta:
model = LearningMentor
fields = ["id", "mentor"]
read_only_fields = ["id"]

View File

@ -187,8 +187,10 @@ class LearningMentorAPITest(APITestCase):
# THEN
self.assertEqual(response.status_code, status.HTTP_200_OK)
mentor_user = response.data[0]
mentor = response.data[0]
self.assertEqual(mentor["id"], learning_mentor.id)
mentor_user = mentor["mentor"]
self.assertEqual(mentor_user["email"], self.mentor.email)
self.assertEqual(mentor_user["id"], str(self.mentor.id))

View File

@ -15,6 +15,7 @@ from vbv_lernwelt.learning_mentor.content.praxis_assignment import (
from vbv_lernwelt.learning_mentor.models import LearningMentor, MentorInvitation
from vbv_lernwelt.learning_mentor.serializers import (
InvitationSerializer,
MentorSerializer,
PraxisAssignmentStatusSerializer,
)
from vbv_lernwelt.learnpath.models import Circle
@ -130,9 +131,7 @@ def list_user_mentors(request, course_session_id: int):
course=course_session.course, participants=course_session_user
)
mentor_users = [mentor.mentor for mentor in mentors]
return Response(UserSerializer(mentor_users, many=True).data)
return Response(MentorSerializer(mentors, many=True).data)
@api_view(["DELETE"])