vbv/client/src/pages/dashboard/agentAssignment/AgentCompetenceGradeDetailP...

187 lines
6.0 KiB
Vue

<script setup lang="ts">
import log from "loglevel";
import { computed, onMounted, ref } from "vue";
import { type DashboardPersonType, fetchDashboardPersons } from "@/services/dashboard";
import LoadingSpinner from "@/components/ui/LoadingSpinner.vue";
import { COMPETENCE_NAVI_CERTIFICATE_QUERY } from "@/graphql/queries";
import { graphqlClient } from "@/graphql/client";
import type { CompetenceCertificateObjectType } from "@/gql/graphql";
import { calcCompetenceCertificateGrade } from "@/pages/competence/utils";
import _ from "lodash";
import type { CompetenceCertificateAssignment } from "@/types";
import { percentToRoundedGrade } from "@/services/assignmentService";
const props = defineProps<{
agentRole: string;
courseSlug: string;
competenceCertificateId: string;
courseSessionId: string;
}>();
log.debug("AgentCompetenceGradeDetailPage created", props);
const loading = ref(true);
const participants = ref<DashboardPersonType[]>([]);
const participantUserIds = computed(() => {
return (participants.value ?? []).map((p) => p.user_id);
});
const certificateData = ref<CompetenceCertificateObjectType | undefined>(undefined);
function userGrade(userId: string) {
if (certificateData.value) {
const assignmentsWithUserCompletions = _.cloneDeep(
certificateData.value.assignments
);
for (const assignment of assignmentsWithUserCompletions) {
assignment.completions = assignment.completions?.filter(
(c) => c?.assignment_user.id === userId
);
}
return calcCompetenceCertificateGrade(
assignmentsWithUserCompletions as unknown as CompetenceCertificateAssignment[],
false
);
}
}
const totalAverageGrade = computed(() => {
if (certificateData.value) {
let divisor = 0;
const assignmentAverageGrades = certificateData.value.assignments.map(
(assignment) => {
const relevantCompletions = (assignment.completions ?? []).filter(
(c) => c?.completion_status == "EVALUATION_SUBMITTED"
);
const averagePercent =
_.sumBy(relevantCompletions, (c) => c?.evaluation_percent ?? 0) /
relevantCompletions.length;
if (averagePercent > 0.0001) {
divisor += assignment.competence_certificate_weight ?? 1;
}
return averagePercent * (assignment.competence_certificate_weight ?? 1);
}
);
return percentToRoundedGrade(
_.sum(assignmentAverageGrades) / (divisor ?? 1),
false
);
}
return undefined;
});
onMounted(async () => {
log.debug("AgentAssignmentDetailPage mounted");
const personData = await fetchDashboardPersons("default");
participants.value = personData?.filter((p) => {
return p.course_sessions.find(
(cs) => cs.id === props.courseSessionId && cs.my_role === "BERUFSBILDNER"
);
});
const res = await graphqlClient.query(COMPETENCE_NAVI_CERTIFICATE_QUERY, {
courseSlug: props.courseSlug,
courseSessionId: props.courseSessionId,
userIds: participantUserIds.value,
});
// @ts-ignore
certificateData.value =
res.data?.competence_certificate_list?.competence_certificates.find(
// @ts-ignore
(cc) => cc.id === props.competenceCertificateId
);
loading.value = false;
});
</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="`/statistic/${props.agentRole}/${props.courseSlug}/competence-grade`"
>
<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>
<pre>{{ totalAverageGrade }}</pre>
<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="person in participants"
:key="person.user_id"
data-cy="person"
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/2">
<div class="flex items-center space-x-2">
<img
class="inline-block h-11 w-11 rounded-full"
:src="
person.avatar_url_small ||
'/static/avatars/myvbv-default-avatar.png'
"
:alt="`${person.first_name} ${person.last_name}`"
/>
<div>
<div class="text-bold">
{{ person.first_name }}
{{ person.last_name }}
</div>
<div class="text-gray-900">{{ person.email }}</div>
</div>
</div>
</div>
<div class="flex w-full flex-auto items-start md:w-1/4">
<div class="flex">
<div>{{ $t("a.Note") }}:</div>
<div class="w-16 text-center">{{ userGrade(person.user_id) }}</div>
</div>
</div>
<div class="w-full flex-auto items-end md:w-1/4 md:text-end">
<router-link
:to="{
name: 'profileLearningPath',
params: {
userId: person.user_id,
courseSlug: props.courseSlug,
},
query: { courseSessionId: props.courseSessionId },
}"
data-cy="person-learning-path-link"
class="link w-full lg:text-right"
>
{{ $t("a.Profil anzeigen") }}
</router-link>
</div>
</div>
</div>
</div>
</div>
</div>
</template>