vbv/client/src/pages/dashboard/agentAssignment/AgentCompetenceGradePage.vue

179 lines
5.8 KiB
Vue

<script setup lang="ts">
import log from "loglevel";
import { computed, onMounted, ref } from "vue";
import {
courseIdForCourseSlug,
fetchMentorCompetenceSummary,
} from "@/services/dashboard";
import type { AssignmentStatisticsRecordType, BaseStatisticsType } from "@/gql/graphql";
import { useDashboardStore } from "@/stores/dashboard";
import LoadingSpinner from "@/components/ui/LoadingSpinner.vue";
import _ from "lodash";
import { percentToRoundedGrade } from "@/services/assignmentService";
const dashboardStore = useDashboardStore();
const props = defineProps<{
agentRole: string;
courseSlug: string;
}>();
log.debug("AgentCompetenceGradePage created", props);
const loading = ref(true);
const courseId = ref<string | undefined>(undefined);
const agentAssignmentData = ref<BaseStatisticsType | null>(null);
const courseSessionName = (courseSessionId: string) => {
return (
agentAssignmentData.value?.course_session_properties?.sessions.find(
(session) => session.id === courseSessionId
)?.name ?? ""
);
};
onMounted(async () => {
await dashboardStore.loadDashboardDetails();
courseId.value = courseIdForCourseSlug(
dashboardStore.dashboardConfigsv2,
props.courseSlug
);
if (!courseId.value) {
log.error("CourseId not found for courseSlug", props.courseSlug);
return;
}
log.debug("courseId", courseId.value);
agentAssignmentData.value = await fetchMentorCompetenceSummary(
courseId.value,
props.agentRole
);
loading.value = false;
});
type GroupedAssignments = {
competenceCertificateId: string;
competenceCertificateTitle: string;
generation: string;
courseSessionId: string;
assignments: AssignmentStatisticsRecordType[];
sumAverageEvaluationPercent: number;
averageEvaluationPercent: number | null;
averageGrade: number | null;
};
const courseSessionCompetenceAssignments = computed(() => {
let resultArray = [] as GroupedAssignments[];
// group assignments by competence and course session
for (const assignment of agentAssignmentData.value?.assignments.records ?? []) {
const entry = resultArray.find(
(r) =>
r.competenceCertificateId === assignment.competence_certificate_id &&
r.courseSessionId === assignment.course_session_id
);
if (entry) {
if (assignment.metrics.ranking_completed) {
entry.assignments.push(assignment);
}
} else {
const newEntry = {
competenceCertificateId: assignment.competence_certificate_id ?? "",
competenceCertificateTitle: assignment.competence_certificate_title ?? "",
generation: assignment.generation ?? "",
courseSessionId: assignment.course_session_id ?? "",
assignments: [] as AssignmentStatisticsRecordType[],
sumAverageEvaluationPercent: 0,
averageEvaluationPercent: null,
averageGrade: null,
};
if (assignment && assignment.metrics.ranking_completed) {
newEntry.assignments.push(assignment);
}
resultArray.push(newEntry);
}
}
// filter out entries without assignments
resultArray = resultArray.filter((entry) => entry.assignments.length > 0);
// calculate average grade
for (const entry of resultArray) {
entry.sumAverageEvaluationPercent = _.sumBy(entry.assignments, (a) => {
return (
(a.metrics.average_evaluation_percent ?? 0) *
(a.metrics.competence_certificate_weight ?? 1)
);
});
entry.averageEvaluationPercent =
entry.sumAverageEvaluationPercent /
_.sumBy(entry.assignments, (a) => {
return a.metrics.competence_certificate_weight ?? 1;
});
entry.averageGrade = percentToRoundedGrade(entry.averageEvaluationPercent, false);
}
return resultArray;
});
</script>
<template>
<div class="bg-gray-200">
<div v-if="loading" class="m-8 flex justify-center">
<LoadingSpinner />
</div>
<div v-else class="container-large flex flex-col space-y-8">
<router-link class="btn-text inline-flex items-center pl-0" to="/">
<it-icon-arrow-left />
<span>{{ $t("general.back") }}</span>
</router-link>
<div>
<h2 class="text-2xl font-bold">{{ $t("a.Statistik") }}</h2>
<p class="text-gray-800">
{{ $t("a.Statistik für alle Lernenden") }}
</p>
<div class="bg-white px-4 py-2">
<section
class="flex flex-col space-x-0 border-b bg-white lg:flex-row lg:space-x-3"
></section>
<div
v-for="entry in courseSessionCompetenceAssignments"
:key="entry.courseSessionId"
:data-cy="`entry-${entry.courseSessionId}`"
class="flex flex-col justify-between gap-4 border-b p-2 last:border-b-0 md:flex-row md:items-center md:justify-between md:gap-16"
>
<div class="w-full flex-auto md:w-1/3">
{{ entry.competenceCertificateTitle }}
<br />
{{ $t("a.Durchführung") }} «{{
courseSessionName(entry.courseSessionId)
}}»
</div>
<div class="flex w-full flex-auto items-start md:w-1/3">
<div class="flex">
<div>{{ $t("a.Durchschnittsnote") }}:</div>
<div class="w-16 text-center">
{{ entry.averageGrade }}
</div>
</div>
</div>
<div class="w-full flex-auto items-end md:w-1/3 md:text-end">
<router-link
class="underline"
:to="`/statistic/${props.agentRole}/${props.courseSlug}/competence-grade/${entry.courseSessionId}/${entry.competenceCertificateId}`"
data-cy="basebox.detailsLink"
>
{{ $t("a.Details anschauen") }}
</router-link>
</div>
</div>
</div>
</div>
</div>
</div>
</template>