feat: mentor dashboard
This commit is contained in:
parent
28542f8540
commit
3b0f562a7a
|
|
@ -1,17 +1,38 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import log from "loglevel";
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
const props = defineProps<{
|
const route = useRoute();
|
||||||
courseSlug: string;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
log.debug("CockpitIndexPage created", props.courseSlug);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-200">
|
<div class="bg-gray-200">
|
||||||
<h1>Mentor</h1>
|
<nav class="border-b bg-white px-4 lg:px-8">
|
||||||
|
<ul class="flex flex-col lg:flex-row">
|
||||||
|
<li
|
||||||
|
class="border-t-2 border-t-transparent"
|
||||||
|
:class="{
|
||||||
|
'border-b-2 border-b-blue-900':
|
||||||
|
route.name === 'mentorCockpitOverview' || route.name === 'mentorCockpit',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<router-link :to="{ name: 'mentorCockpitOverview' }" class="block py-3">
|
||||||
|
{{ $t("a.Übersicht") }}
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="border-t-2 border-t-transparent lg:ml-12"
|
||||||
|
:class="{
|
||||||
|
'border-b-2 border-b-blue-900': route.name === 'mentorCockpitParticipants',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<router-link :to="{ name: 'mentorCockpitParticipants' }" class="block py-3">
|
||||||
|
{{ $t("a.Teilnehmer") }}
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<main class="container-large lg:mt-4">
|
||||||
|
<router-view></router-view>
|
||||||
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
|
||||||
import { useCurrentCourseSession } from "@/composables";
|
|
||||||
import CockpitExpertPage from "./CockpitExpertPage.vue";
|
|
||||||
import CockpitMentorPage from "./CockpitMentorPage.vue";
|
|
||||||
|
|
||||||
const cockpitStore = useCockpitStore();
|
|
||||||
const courseSession = useCurrentCourseSession();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="bg-gray-200">
|
|
||||||
<template v-if="cockpitStore.hasExpertCockpitType">
|
|
||||||
<CockpitExpertPage :course-slug="courseSession.course.slug" />
|
|
||||||
</template>
|
|
||||||
<template v-else-if="cockpitStore.hasMentorCockpitType">
|
|
||||||
<CockpitMentorPage :course-slug="courseSession.course.slug" />
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<router-link to="{name: ''}">{{ $t("a.Zurück") }}</router-link>
|
||||||
|
|
||||||
|
<div class="bg-white p-8">Hallo</div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useMentorCockpit } from "@/services/mentorCockpit";
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
|
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
||||||
|
import { computed, ref } from "vue";
|
||||||
|
|
||||||
|
const courseSession = useCurrentCourseSession();
|
||||||
|
const { summary } = useMentorCockpit(courseSession.value.id);
|
||||||
|
|
||||||
|
const statusFilterValue = ref({ name: "Alle", id: "_all" });
|
||||||
|
|
||||||
|
const statusFilter = ref([
|
||||||
|
{ name: "Alle", id: "_all" },
|
||||||
|
{ name: "Zu erledigen", id: "todo" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
interface Circle {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const circleFilterValue = ref({ name: "Circle: Alle", id: "_all" });
|
||||||
|
|
||||||
|
const circleFilter = computed(() => {
|
||||||
|
if (!summary.value) return [];
|
||||||
|
|
||||||
|
return [
|
||||||
|
{ name: "Circle: Alle", id: "_all" },
|
||||||
|
...summary.value.circles.map((circle: Circle) => ({
|
||||||
|
name: `Circle: ${circle.title}`,
|
||||||
|
id: circle.id,
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{ summary }}
|
||||||
|
<div class="bg-white" v-if="summary">
|
||||||
|
<div class="flex flex-col space-x-2 lg:flex-row">
|
||||||
|
<ItDropdownSelect
|
||||||
|
v-model="statusFilterValue"
|
||||||
|
class="min-w-[10rem]"
|
||||||
|
:items="statusFilter"
|
||||||
|
borderless
|
||||||
|
></ItDropdownSelect>
|
||||||
|
<ItDropdownSelect
|
||||||
|
v-model="circleFilterValue"
|
||||||
|
class="min-w-[18rem]"
|
||||||
|
:items="circleFilter"
|
||||||
|
borderless
|
||||||
|
></ItDropdownSelect>
|
||||||
|
<!-- <ItDropdownSelect-->
|
||||||
|
<!-- v-model="circleFilterValue"-->
|
||||||
|
<!-- class="min-w-[18rem]"-->
|
||||||
|
<!-- :items="circleFilter"-->
|
||||||
|
<!-- borderless-->
|
||||||
|
<!-- ></ItDropdownSelect>-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useMentorCockpit } from "@/services/mentorCockpit";
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
|
|
||||||
|
const courseSession = useCurrentCourseSession();
|
||||||
|
const { summary } = useMentorCockpit(courseSession.value.id);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div v-if="summary" class="bg-white px-4 py-2">
|
||||||
|
<div
|
||||||
|
v-for="participant in summary.participants"
|
||||||
|
:key="participant.id"
|
||||||
|
class="flex flex-col items-center justify-between gap-4 border-b py-2 last:border-b-0 md:flex-row 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: 'cockpitUserProfile', params: {userId: participant.id}}" class="underline">-->
|
||||||
|
<!-- {{ $t("a.Profil anzeigen") }}-->
|
||||||
|
<!-- </router-link>-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
|
<template>Praxis</template>
|
||||||
|
|
@ -62,10 +62,6 @@ export async function handleCurrentCourseSession(to: RouteLocationNormalized) {
|
||||||
if (!courseSessionsStore.loaded) {
|
if (!courseSessionsStore.loaded) {
|
||||||
await courseSessionsStore.loadCourseSessionsData();
|
await courseSessionsStore.loadCourseSessionsData();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be after loadCourseSessionsData & _currentCourseSlug is set!
|
|
||||||
const courseId = courseSessionsStore.currentCourseSession?.course.id || null;
|
|
||||||
await useCockpitStore().fetchCockpitType(courseId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,3 +98,28 @@ export async function handleCourseSessionAsQueryParam(to: RouteLocationNormalize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function handleCockpit(to: RouteLocationNormalized) {
|
||||||
|
const courseSessionsStore = useCourseSessionsStore();
|
||||||
|
const courseId = courseSessionsStore.currentCourseSession?.course.id || null;
|
||||||
|
const cockpitStore = useCockpitStore();
|
||||||
|
await cockpitStore.fetchCockpitType(courseId);
|
||||||
|
|
||||||
|
if (to.name === "cockpit") {
|
||||||
|
if (cockpitStore.hasExpertCockpitType) {
|
||||||
|
return { name: "expertCockpit", params: to.params };
|
||||||
|
} else if (cockpitStore.hasMentorCockpitType) {
|
||||||
|
return { name: "mentorCockpitOverview", params: to.params };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cockpitType = to.meta?.cockpitType;
|
||||||
|
|
||||||
|
if (!cockpitType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cockpitType !== cockpitStore.cockpitType) {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import DashboardPage from "@/pages/dashboard/DashboardPage.vue";
|
import DashboardPage from "@/pages/dashboard/DashboardPage.vue";
|
||||||
import LoginPage from "@/pages/LoginPage.vue";
|
import LoginPage from "@/pages/LoginPage.vue";
|
||||||
import {
|
import {
|
||||||
|
handleCockpit,
|
||||||
handleCourseSessionAsQueryParam,
|
handleCourseSessionAsQueryParam,
|
||||||
handleCurrentCourseSession,
|
handleCurrentCourseSession,
|
||||||
redirectToLoginIfRequired,
|
redirectToLoginIfRequired,
|
||||||
|
|
@ -134,16 +135,71 @@ const router = createRouter({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/course/:courseSlug/cockpit",
|
path: "/course/:courseSlug/cockpit",
|
||||||
|
name: "cockpit",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "expert",
|
||||||
|
component: () => import("@/pages/cockpit/cockpitPage/CockpitExpertPage.vue"),
|
||||||
|
props: true,
|
||||||
|
name: "expertCockpit",
|
||||||
|
meta: {
|
||||||
|
cockpitType: "expert",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "mentor",
|
||||||
|
component: () => import("@/pages/cockpit/cockpitPage/CockpitMentorPage.vue"),
|
||||||
|
name: "mentorCockpit",
|
||||||
|
meta: {
|
||||||
|
cockpitType: "mentor",
|
||||||
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "",
|
path: "",
|
||||||
component: () => import("@/pages/cockpit/cockpitPage/CockpitPage.vue"),
|
component: () =>
|
||||||
props: true,
|
import("@/pages/cockpit/cockpitPage/mentor/MentorOverview.vue"),
|
||||||
|
name: "mentorCockpitOverview",
|
||||||
|
meta: {
|
||||||
|
cockpitType: "mentor",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "participants",
|
||||||
|
component: () =>
|
||||||
|
import("@/pages/cockpit/cockpitPage/mentor/MentorParticipants.vue"),
|
||||||
|
name: "mentorCockpitParticipants",
|
||||||
|
meta: {
|
||||||
|
cockpitType: "mentor",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "details",
|
||||||
|
component: () =>
|
||||||
|
import("@/pages/cockpit/cockpitPage/mentor/MentorDetailParentPage.vue"),
|
||||||
|
meta: {
|
||||||
|
cockpitType: "mentor",
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "praxis-assignments",
|
||||||
|
component: () =>
|
||||||
|
import(
|
||||||
|
"@/pages/cockpit/cockpitPage/mentor/MentorPraxisAssignment.vue"
|
||||||
|
),
|
||||||
|
name: "mentorCockpitPraxisAssignments",
|
||||||
|
meta: {
|
||||||
|
cockpitType: "mentor",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "profile/:userId",
|
path: "profile/:userId",
|
||||||
component: () => import("@/pages/cockpit/CockpitUserProfilePage.vue"),
|
component: () => import("@/pages/cockpit/CockpitUserProfilePage.vue"),
|
||||||
props: true,
|
props: true,
|
||||||
|
name: "cockpitUserProfile",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "profile/:userId/:circleSlug",
|
path: "profile/:userId/:circleSlug",
|
||||||
|
|
@ -259,6 +315,8 @@ router.beforeEach(redirectToLoginIfRequired);
|
||||||
router.beforeEach(handleCurrentCourseSession);
|
router.beforeEach(handleCurrentCourseSession);
|
||||||
router.beforeEach(handleCourseSessionAsQueryParam);
|
router.beforeEach(handleCourseSessionAsQueryParam);
|
||||||
|
|
||||||
|
router.beforeEach(handleCockpit);
|
||||||
|
|
||||||
router.beforeEach(addToHistory);
|
router.beforeEach(addToHistory);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
|
||||||
|
|
@ -32,5 +32,6 @@ export const useCockpitStore = defineStore("cockpit", () => {
|
||||||
hasMentorCockpitType,
|
hasMentorCockpitType,
|
||||||
hasNoCockpitType,
|
hasNoCockpitType,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
cockpitType,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,13 @@ def create_versicherungsvermittlerin_course(
|
||||||
|
|
||||||
cs = CourseSession.objects.create(course_id=course_id, title=names[language])
|
cs = CourseSession.objects.create(course_id=course_id, title=names[language])
|
||||||
|
|
||||||
|
for assignment in Assignment.objects.all():
|
||||||
|
if assignment.get_course().id == course_id:
|
||||||
|
CourseSessionAssignment.objects.get_or_create(
|
||||||
|
course_session=cs,
|
||||||
|
learning_content=assignment.find_attached_learning_content(),
|
||||||
|
)
|
||||||
|
|
||||||
if language == "de":
|
if language == "de":
|
||||||
for user_data in default_users:
|
for user_data in default_users:
|
||||||
CourseSessionUser.objects.create(
|
CourseSessionUser.objects.create(
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ def get_praxis_assignments(
|
||||||
|
|
||||||
for course_session_assignment in CourseSessionAssignment.objects.filter(
|
for course_session_assignment in CourseSessionAssignment.objects.filter(
|
||||||
course_session=course_session,
|
course_session=course_session,
|
||||||
learning_content__content_assignment__assignment_type__in=[
|
learning_content__assignment_type__in=[
|
||||||
AssignmentType.PRAXIS_ASSIGNMENT.value,
|
AssignmentType.PRAXIS_ASSIGNMENT.value,
|
||||||
],
|
],
|
||||||
):
|
):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue