feat: learning mentor mgmt UI
This commit is contained in:
parent
9eb2bbceba
commit
2a8b3198b2
|
|
@ -1,4 +1,5 @@
|
||||||
import { getCookieValue } from "@/router/guards";
|
import { getCookieValue } from "@/router/guards";
|
||||||
|
import { createFetch } from "@vueuse/core";
|
||||||
|
|
||||||
class FetchError extends Error {
|
class FetchError extends Error {
|
||||||
response: Response;
|
response: Response;
|
||||||
|
|
@ -88,3 +89,13 @@ export const itGetCached = (
|
||||||
|
|
||||||
return itGetPromiseCache.get(url.toString()) as Promise<any>;
|
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 };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useFetch } from "@vueuse/core";
|
|
||||||
import { useCurrentCourseSession } from "@/composables";
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import ItModal from "@/components/ui/ItModal.vue";
|
import ItModal from "@/components/ui/ItModal.vue";
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
|
import { useCSRFFetch } from "@/fetchHelpers";
|
||||||
|
|
||||||
const courseSession = useCurrentCourseSession();
|
const courseSession = useCurrentCourseSession();
|
||||||
|
|
||||||
const showInvitationModal = ref(false);
|
const showInvitationModal = ref(false);
|
||||||
|
|
||||||
const { data: mentors } = useFetch(
|
const { execute: refreshMentors, data: mentors } = useCSRFFetch(
|
||||||
`/api/mentor/${courseSession.value.course.id}/mentors`
|
`/api/mentor/${courseSession.value.course.id}/mentors`
|
||||||
).json();
|
).json();
|
||||||
|
|
||||||
const { data: invitations } = useFetch(
|
const { execute: refreshInvitations, data: invitations } = useCSRFFetch(
|
||||||
`/api/mentor/${courseSession.value.course.id}/invitations`
|
`/api/mentor/${courseSession.value.course.id}/invitations`
|
||||||
).json();
|
).json();
|
||||||
|
|
||||||
|
|
@ -22,6 +22,20 @@ const hasMentors = computed(() => {
|
||||||
(invitations.value && invitations.value.length > 0)
|
(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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -52,26 +66,44 @@ const hasMentors = computed(() => {
|
||||||
<div
|
<div
|
||||||
v-for="invitation in invitations"
|
v-for="invitation in invitations"
|
||||||
:key="invitation.id"
|
: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 flex-col justify-between md:flex-grow md:flex-row">
|
||||||
<div class="flex items-center">
|
{{ invitation.email }}
|
||||||
<it-icon-info class="it-icon mr-2 h-6 w-6" />
|
<div class="flex items-center">
|
||||||
{{ $t("a.Die Einladung wurde noch nicht angenommen.") }}
|
<it-icon-info class="it-icon mr-2 h-6 w-6" />
|
||||||
|
{{ $t("a.Die Einladung wurde noch nicht angenommen.") }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="underline">
|
<button @click="removeInvitation(invitation.id)" class="underline">
|
||||||
{{ $t("a.Entfernen") }}
|
{{ $t("a.Entfernen") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-for="mentor in mentors"
|
v-for="learningMentor in mentors"
|
||||||
:key="mentor.id"
|
:key="learningMentor.id"
|
||||||
class="flex flex-col 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"
|
||||||
>
|
>
|
||||||
{{ 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>
|
</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" />
|
<it-icon-info class="it-icon mr-2 h-6 w-6" />
|
||||||
{{
|
{{
|
||||||
$t("a.Aktuell hast du noch keine Person als Lernbegleitung eingeladen.")
|
$t("a.Aktuell hast du noch keine Person als Lernbegleitung eingeladen.")
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from rest_framework import serializers
|
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):
|
class PraxisAssignmentCompletionSerializer(serializers.Serializer):
|
||||||
|
|
@ -33,3 +34,12 @@ class InvitationSerializer(serializers.ModelSerializer):
|
||||||
email=validated_data["email"], defaults={"participant": participant}
|
email=validated_data["email"], defaults={"participant": participant}
|
||||||
)
|
)
|
||||||
return invitation
|
return invitation
|
||||||
|
|
||||||
|
|
||||||
|
class MentorSerializer(serializers.ModelSerializer):
|
||||||
|
mentor = UserSerializer(read_only=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = LearningMentor
|
||||||
|
fields = ["id", "mentor"]
|
||||||
|
read_only_fields = ["id"]
|
||||||
|
|
|
||||||
|
|
@ -187,8 +187,10 @@ class LearningMentorAPITest(APITestCase):
|
||||||
# THEN
|
# THEN
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
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["email"], self.mentor.email)
|
||||||
self.assertEqual(mentor_user["id"], str(self.mentor.id))
|
self.assertEqual(mentor_user["id"], str(self.mentor.id))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.models import LearningMentor, MentorInvitation
|
||||||
from vbv_lernwelt.learning_mentor.serializers import (
|
from vbv_lernwelt.learning_mentor.serializers import (
|
||||||
InvitationSerializer,
|
InvitationSerializer,
|
||||||
|
MentorSerializer,
|
||||||
PraxisAssignmentStatusSerializer,
|
PraxisAssignmentStatusSerializer,
|
||||||
)
|
)
|
||||||
from vbv_lernwelt.learnpath.models import Circle
|
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
|
course=course_session.course, participants=course_session_user
|
||||||
)
|
)
|
||||||
|
|
||||||
mentor_users = [mentor.mentor for mentor in mentors]
|
return Response(MentorSerializer(mentors, many=True).data)
|
||||||
|
|
||||||
return Response(UserSerializer(mentor_users, many=True).data)
|
|
||||||
|
|
||||||
|
|
||||||
@api_view(["DELETE"])
|
@api_view(["DELETE"])
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue