vbv/client/src/pages/cockpit/CockpitIndexPage.vue

228 lines
8.2 KiB
Vue

<script setup lang="ts">
import FeedbackSummary from "@/components/feedback/feedbackSummary.vue";
import LearningPathDiagram from "@/components/learningPath/LearningPathDiagram.vue";
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
import ItProgress from "@/components/ui/ItProgress.vue";
import type { LearningPath } from "@/services/learningPath";
import { useCockpitStore } from "@/stores/cockpit";
import { useCompetenceStore } from "@/stores/competence";
import { useCourseSessionsStore } from "@/stores/courseSessions";
import { useLearningPathStore } from "@/stores/learningPath";
import { useUserStore } from "@/stores/user";
import groupBy from "lodash/groupBy";
import log from "loglevel";
import { computed } from "vue";
const props = defineProps<{
courseSlug: string;
}>();
log.debug("CockpitIndexPage created", props.courseSlug);
const userStore = useUserStore();
const cockpitStore = useCockpitStore();
const competenceStore = useCompetenceStore();
const learningPathStore = useLearningPathStore();
const courseSessionStore = useCourseSessionsStore();
function userCountStatusForCircle(userId: number, translationKey: string) {
const criteria = competenceStore.flatPerformanceCriteria(
userId,
cockpitStore.selectedCircles
);
const grouped = groupBy(criteria, "circle.translation_key");
return competenceStore.calcStatusCount(grouped[translationKey]);
}
const circles = computed(() => {
const learningPathCircles = learningPathStore
.learningPathForUser(props.courseSlug, userStore.id)
?.circles.map((c) => {
return {
id: c.id,
title: c.title,
slug: c.slug,
translation_key: c.translation_key,
};
});
if (cockpitStore.cockpitSessionUser?.circles?.length) {
return cockpitStore.cockpitSessionUser.circles;
} else if (learningPathCircles) {
return learningPathCircles;
} else {
return [];
}
});
const selectedCirclesTitles = computed(() => {
return circles.value
.filter((c) => cockpitStore.selectedCircles.includes(c.translation_key))
.map((c) => c.title);
});
const data = {
transferProgress: {
fail: 0,
success: 3,
unknown: 8,
},
};
function setActiveClasses(translationKey: string) {
return cockpitStore.selectedCircles.indexOf(translationKey) > -1
? ["bg-blue-900", "text-white"]
: ["text-bg-900"];
}
</script>
<template>
<div class="bg-gray-200">
<div class="container-large">
<div class="mb-9 flex items-center lg:flex-row">
<h1 class="heading-3">{{ $t("general.circles") }}:</h1>
<ul class="ml-4 flex flex-row text-base font-bold leading-7">
<li
v-for="circle in circles"
:key="circle.translation_key"
class="mr-4 last:mr-0"
>
<button
class="mr-4 rounded-full border-2 border-blue-900 px-4 last:mr-0"
:class="setActiveClasses(circle.translation_key)"
@click="cockpitStore.toggleCourseSelection(circle.translation_key)"
>
{{ circle.title }}
</button>
</li>
</ul>
</div>
<!-- Status -->
<div class="mb-4 grid grid-rows-2 gap-4 lg:grid-cols-2 lg:grid-rows-none">
<div class="bg-white px-6 py-5">
<h1
class="heading-3 mb-4 bg-assignment bg-60 bg-no-repeat pl-[68px] leading-[60px]"
>
{{ $t("general.transferTask", 2) }}
</h1>
<div class="mb-4">
<ItProgress :status-count="data.transferProgress"></ItProgress>
</div>
<p>{{ $t("cockpit.tasksDone") }}</p>
</div>
<div class="bg-white px-6 py-5">
<h1
class="heading-3 mb-4 bg-test bg-60 bg-no-repeat pl-[68px] leading-[60px]"
>
{{ $t("general.examResult", 2) }}
</h1>
<div class="mb-4">
<ItProgress :status-count="data.transferProgress"></ItProgress>
</div>
<p>{{ $t("cockpit.examsDone") }}</p>
</div>
</div>
<!-- Feedback -->
<FeedbackSummary
:selcted-circles="cockpitStore.selectedCircles || []"
:circles="
learningPathStore.learningPathForUser(props.courseSlug, userStore.id)
?.circles || []
"
:course-id="courseSessionStore.courseSessionForRoute?.course.id || 0"
:url="courseSessionStore.courseSessionForRoute?.course_url || ''"
></FeedbackSummary>
<div>
<!-- progress -->
<div v-if="cockpitStore.courseSessionUsers?.length" class="bg-white p-6">
<h1 class="heading-3 mb-5">{{ $t("cockpit.progress") }}</h1>
<ul>
<ItPersonRow
v-for="csu in cockpitStore.courseSessionUsers"
:key="csu.user_id + csu.session_title"
:name="`${csu.first_name} ${csu.last_name}`"
:avatar-url="csu.avatar_url"
>
<template #center>
<div
class="mt-2 flex w-full flex-row items-center justify-between lg:mt-0"
>
<ul class="w-full">
<li
class="flex h-12 items-center justify-between"
v-for="(circle, i) of cockpitStore.selectedCircles"
:key="i"
>
<LearningPathDiagram
v-if="
learningPathStore.learningPathForUser(
props.courseSlug,
csu.user_id
)
"
:learning-path="
learningPathStore.learningPathForUser(
props.courseSlug,
csu.user_id
) as LearningPath
"
:postfix="`cockpit-${csu.user_id}-${i}`"
:profile-user-id="`${csu.user_id}`"
:show-circle-translation-keys="[circle]"
:pull-up="false"
diagram-type="singleSmall"
class="mr-4"
></LearningPathDiagram>
<p class="lg:min-w-[150px]">
{{ selectedCirclesTitles[i] }}
</p>
<div class="ml-4 flex flex-row items-center">
<div class="mr-6 flex flex-row items-center">
<it-icon-smiley-thinking
class="mr-2 inline-block h-8 w-8"
></it-icon-smiley-thinking>
<p class="text-bold inline-block">
{{ userCountStatusForCircle(csu.user_id, circle).fail }}
</p>
</div>
<li class="mr-6 flex flex-row items-center">
<it-icon-smiley-happy
class="mr-2 inline-block h-8 w-8"
></it-icon-smiley-happy>
<p class="text-bold inline-block">
{{ userCountStatusForCircle(csu.user_id, circle).success }}
</p>
</li>
<li class="flex flex-row items-center">
<it-icon-smiley-neutral
class="mr-2 inline-block h-8 w-8"
></it-icon-smiley-neutral>
<p class="text-bold inline-block">
{{ userCountStatusForCircle(csu.user_id, circle).unknown }}
</p>
</li>
</div>
</li>
</ul>
</div>
</template>
<template #link>
<router-link
:to="`/course/${props.courseSlug}/cockpit/profile/${csu.user_id}`"
class="w-full text-right underline"
>
{{ $t("general.profileLink") }}
</router-link>
</template>
</ItPersonRow>
</ul>
</div>
</div>
</div>
</div>
</template>
<style scoped></style>