feat: participants
This commit is contained in:
parent
8fd2234011
commit
9b5845d89b
|
|
@ -0,0 +1,44 @@
|
|||
<script setup lang="ts">
|
||||
import { useLearningMentees } from "@/services/learningMentees";
|
||||
import { useCurrentCourseSession } from "@/composables";
|
||||
|
||||
const courseSession = useCurrentCourseSession();
|
||||
const { summary } = useLearningMentees(courseSession.value.id);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="summary">
|
||||
<h2 class="heading-2 mb-6 mt-6">{{ $t("a.Personen, die du begleitest") }}</h2>
|
||||
<div class="bg-white px-4 py-2">
|
||||
<div
|
||||
v-for="participant in summary.participants"
|
||||
:key="participant.id"
|
||||
class="flex flex-col items-start justify-between gap-4 border-b py-2 last:border-b-0 md:flex-row md:items-center md:gap-16"
|
||||
>
|
||||
<div class="flex items-center space-x-2">
|
||||
<img
|
||||
:alt="participant.last_name"
|
||||
class="h-11 w-11 rounded-full"
|
||||
:src="participant.avatar_url || '/static/avatars/myvbv-default-avatar.png'"
|
||||
/>
|
||||
<div>
|
||||
<div class="text-bold">
|
||||
{{ participant.first_name }}
|
||||
{{ participant.last_name }}
|
||||
</div>
|
||||
{{ participant.email }}
|
||||
</div>
|
||||
</div>
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'profileLearningPath',
|
||||
params: { userId: participant.id, courseSlug: courseSession.course.slug },
|
||||
}"
|
||||
class="underline"
|
||||
>
|
||||
{{ $t("cockpit.profileLink") }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
<script setup lang="ts">
|
||||
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 inviteeEmail = ref("");
|
||||
|
||||
const { execute: refreshMentors, data: mentors } = useCSRFFetch(
|
||||
`/api/mentor/${courseSession.value.id}/mentors`
|
||||
).json();
|
||||
|
||||
const { execute: refreshInvitations, data: invitations } = useCSRFFetch(
|
||||
`/api/mentor/${courseSession.value.id}/invitations`
|
||||
).json();
|
||||
|
||||
const hasMentors = computed(() => {
|
||||
return (
|
||||
(mentors.value && mentors.value.length > 0) ||
|
||||
(invitations.value && invitations.value.length > 0)
|
||||
);
|
||||
});
|
||||
|
||||
const validEmail = computed(() => {
|
||||
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
return emailRegex.test(inviteeEmail.value);
|
||||
});
|
||||
|
||||
const removeInvitation = async (invitationId: string) => {
|
||||
await useCSRFFetch(
|
||||
`/api/mentor/${courseSession.value.id}/invitations/${invitationId}/delete`
|
||||
).delete();
|
||||
await refreshInvitations();
|
||||
};
|
||||
|
||||
const removeMentor = async (mentorId: string) => {
|
||||
await useCSRFFetch(
|
||||
`/api/mentor/${courseSession.value.id}/mentors/${mentorId}/leave`
|
||||
).delete();
|
||||
await refreshMentors();
|
||||
};
|
||||
|
||||
const inviteMentor = async () => {
|
||||
await useCSRFFetch(`/api/mentor/${courseSession.value.id}/invitations/create`).post({
|
||||
email: inviteeEmail.value,
|
||||
});
|
||||
await refreshInvitations();
|
||||
showInvitationModal.value = false;
|
||||
inviteeEmail.value = "";
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-gray-200">
|
||||
<div class="container-large">
|
||||
<header class="mb-8 mt-12">
|
||||
<h1 class="mb-8">{{ $t("a.Lernbegleitung") }}</h1>
|
||||
<p>
|
||||
{{
|
||||
$t(
|
||||
"a.Hier kannst du Personen einladen, damit sie deine Lernbegleitung werden. Zudem siehst du jederzeit eine Übersicht aller Personen, die du bereits als Lernbegleitung hinzugefügt hast."
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
</header>
|
||||
<main>
|
||||
<div class="bg-white p-6">
|
||||
<div class="mb-8">
|
||||
<button
|
||||
class="btn-secondary flex items-center"
|
||||
@click="showInvitationModal = true"
|
||||
>
|
||||
<it-icon-add class="it-icon mr-2 h-6 w-6" />
|
||||
{{ $t("a.Neue Lernbegleitung einladen") }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="border-t">
|
||||
<div
|
||||
v-for="invitation in invitations"
|
||||
:key="invitation.id"
|
||||
class="flex flex-col justify-between gap-4 border-b py-4 md:flex-row md:gap-16"
|
||||
>
|
||||
<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" @click="removeInvitation(invitation.id)">
|
||||
{{ $t("a.Entfernen") }}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
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"
|
||||
>
|
||||
<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 class="underline" @click="removeMentor(learningMentor.id)">
|
||||
{{ $t("a.Entfernen") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<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.")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<ItModal v-model="showInvitationModal">
|
||||
<template #title>{{ $t("a.Neue Lernbegleitung einladen") }}</template>
|
||||
<template #body>
|
||||
<div class="flex flex-col">
|
||||
<label for="mentor-email">{{ $t("a.E-Mail Adresse") }}</label>
|
||||
<input id="mentor-email" v-model="inviteeEmail" type="email" />
|
||||
|
||||
<button
|
||||
:disabled="!validEmail"
|
||||
class="btn-primary mt-8"
|
||||
@click="inviteMentor()"
|
||||
>
|
||||
{{ $t("a.Einladung abschicken") }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</ItModal>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,44 +1,22 @@
|
|||
<script setup lang="ts">
|
||||
import { useLearningMentees } from "@/services/learningMentees";
|
||||
import { useCurrentCourseSession } from "@/composables";
|
||||
import MyMentors from "@/components/learningMentor/MyMentors.vue";
|
||||
import MyMentees from "@/components/learningMentor/MyMentees.vue";
|
||||
|
||||
const courseSession = useCurrentCourseSession();
|
||||
const { summary } = useLearningMentees(courseSession.value.id);
|
||||
const isMyMentorsVisible = courseSession.value.actions.includes(
|
||||
"learning-mentor::edit-mentors"
|
||||
);
|
||||
const isMyMenteesVisible = courseSession.value.actions.includes(
|
||||
"learning-mentor::guide-members"
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="summary">
|
||||
<h2 class="heading-2 mb-6 mt-6">{{ $t("a.Personen, die du begleitest") }}</h2>
|
||||
<div class="bg-white px-4 py-2">
|
||||
<div
|
||||
v-for="participant in summary.participants"
|
||||
:key="participant.id"
|
||||
class="flex flex-col items-start justify-between gap-4 border-b py-2 last:border-b-0 md:flex-row md:items-center md:gap-16"
|
||||
>
|
||||
<div class="flex items-center space-x-2">
|
||||
<img
|
||||
:alt="participant.last_name"
|
||||
class="h-11 w-11 rounded-full"
|
||||
:src="participant.avatar_url || '/static/avatars/myvbv-default-avatar.png'"
|
||||
/>
|
||||
<div>
|
||||
<div class="text-bold">
|
||||
{{ participant.first_name }}
|
||||
{{ participant.last_name }}
|
||||
</div>
|
||||
{{ participant.email }}
|
||||
</div>
|
||||
</div>
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'profileLearningPath',
|
||||
params: { userId: participant.id, courseSlug: courseSession.course.slug },
|
||||
}"
|
||||
class="underline"
|
||||
>
|
||||
{{ $t("cockpit.profileLink") }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isMyMentorsVisible">
|
||||
<MyMentors />
|
||||
</div>
|
||||
<div v-if="isMyMenteesVisible">
|
||||
<MyMentees />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -316,8 +316,6 @@ def can_complete_learning_content(user: User, course_session_id: int) -> bool:
|
|||
def course_session_permissions(user: User, course_session_id: int) -> list[str]:
|
||||
return _action_list(
|
||||
{
|
||||
# FIXME: Just here WHILE we move cockpit -> learning-mentor THEN remove this!
|
||||
"deprecated-mentor": is_course_session_member(user, course_session_id),
|
||||
"learning-mentor": has_learning_mentor(user, course_session_id),
|
||||
"learning-mentor::edit-mentors": can_edit_mentors(user, course_session_id),
|
||||
"learning-mentor::guide-members": can_guide_members(
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ class ActionTestCase(TestCase):
|
|||
self.assertEqual(
|
||||
participant_actions,
|
||||
[
|
||||
"deprecated-mentor",
|
||||
"learning-mentor",
|
||||
"learning-mentor::edit-mentors",
|
||||
"media-library",
|
||||
|
|
|
|||
Loading…
Reference in New Issue