feat: mentor dashboard
This commit is contained in:
parent
28542f8540
commit
3b0f562a7a
|
|
@ -1,17 +1,38 @@
|
|||
<script setup lang="ts">
|
||||
import log from "loglevel";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
const props = defineProps<{
|
||||
courseSlug: string;
|
||||
}>();
|
||||
|
||||
log.debug("CockpitIndexPage created", props.courseSlug);
|
||||
const route = useRoute();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<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>
|
||||
</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) {
|
||||
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 LoginPage from "@/pages/LoginPage.vue";
|
||||
import {
|
||||
handleCockpit,
|
||||
handleCourseSessionAsQueryParam,
|
||||
handleCurrentCourseSession,
|
||||
redirectToLoginIfRequired,
|
||||
|
|
@ -134,16 +135,71 @@ const router = createRouter({
|
|||
},
|
||||
{
|
||||
path: "/course/:courseSlug/cockpit",
|
||||
name: "cockpit",
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
component: () => import("@/pages/cockpit/cockpitPage/CockpitPage.vue"),
|
||||
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: [
|
||||
{
|
||||
path: "",
|
||||
component: () =>
|
||||
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",
|
||||
component: () => import("@/pages/cockpit/CockpitUserProfilePage.vue"),
|
||||
props: true,
|
||||
name: "cockpitUserProfile",
|
||||
},
|
||||
{
|
||||
path: "profile/:userId/:circleSlug",
|
||||
|
|
@ -259,6 +315,8 @@ router.beforeEach(redirectToLoginIfRequired);
|
|||
router.beforeEach(handleCurrentCourseSession);
|
||||
router.beforeEach(handleCourseSessionAsQueryParam);
|
||||
|
||||
router.beforeEach(handleCockpit);
|
||||
|
||||
router.beforeEach(addToHistory);
|
||||
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -32,5 +32,6 @@ export const useCockpitStore = defineStore("cockpit", () => {
|
|||
hasMentorCockpitType,
|
||||
hasNoCockpitType,
|
||||
isLoading,
|
||||
cockpitType,
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -215,6 +215,13 @@ def create_versicherungsvermittlerin_course(
|
|||
|
||||
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":
|
||||
for user_data in default_users:
|
||||
CourseSessionUser.objects.create(
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ def get_praxis_assignments(
|
|||
|
||||
for course_session_assignment in CourseSessionAssignment.objects.filter(
|
||||
course_session=course_session,
|
||||
learning_content__content_assignment__assignment_type__in=[
|
||||
learning_content__assignment_type__in=[
|
||||
AssignmentType.PRAXIS_ASSIGNMENT.value,
|
||||
],
|
||||
):
|
||||
|
|
|
|||
Loading…
Reference in New Issue