216 lines
7.2 KiB
Vue
216 lines
7.2 KiB
Vue
<script setup lang="ts">
|
|
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
|
import type { StatusCount } from "@/components/ui/ItProgress.vue";
|
|
import type { GradedUser } from "@/services/assignmentService";
|
|
import { loadAssignmentCompletionStatusData } from "@/services/assignmentService";
|
|
import type {
|
|
CourseSession,
|
|
CourseSessionUser,
|
|
LearningContentAssignment,
|
|
LearningContentEdoniqTest,
|
|
} from "@/types";
|
|
import log from "loglevel";
|
|
import { computed, onMounted, reactive } from "vue";
|
|
import AssignmentSubmissionProgress from "@/components/assignment/AssignmentSubmissionProgress.vue";
|
|
import { useCourseSessionDetailQuery } from "@/composables";
|
|
import { formatDueDate } from "../../../components/dueDates/dueDatesUtils";
|
|
import { stringifyParse } from "@/utils/utils";
|
|
import { useTranslation } from "i18next-vue";
|
|
|
|
const { t } = useTranslation();
|
|
|
|
export interface Props {
|
|
courseSession: CourseSession;
|
|
learningContent: LearningContentAssignment | LearningContentEdoniqTest;
|
|
userSelectionIds?: string[];
|
|
linkToResults?: boolean;
|
|
}
|
|
|
|
const props = defineProps<Props>();
|
|
|
|
log.debug("AssignmentDetails created", stringifyParse(props));
|
|
|
|
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
|
|
|
const state = reactive({
|
|
progressStatusCount: {} as StatusCount,
|
|
gradedUsers: [] as GradedUser[],
|
|
assignmentSubmittedUsers: [] as CourseSessionUser[],
|
|
});
|
|
|
|
const assignmentDetail = computed(() => {
|
|
return courseSessionDetailResult.findAssignment(props.learningContent.id);
|
|
});
|
|
|
|
const isPraxisAssignment = computed(() => {
|
|
return (
|
|
props.learningContent.content_assignment.assignment_type === "PRAXIS_ASSIGNMENT"
|
|
);
|
|
});
|
|
|
|
onMounted(async () => {
|
|
log.debug("AssignmentDetails mounted", props.learningContent, props.userSelectionIds);
|
|
const { gradedUsers, assignmentSubmittedUsers } =
|
|
await loadAssignmentCompletionStatusData(
|
|
props.learningContent.content_assignment.id,
|
|
props.courseSession.id,
|
|
props.learningContent.id,
|
|
props.userSelectionIds ?? []
|
|
);
|
|
state.gradedUsers = gradedUsers;
|
|
state.assignmentSubmittedUsers = assignmentSubmittedUsers;
|
|
});
|
|
|
|
function findGradedUser(userId: string) {
|
|
return state.gradedUsers.find((gu) => gu.user.user_id === userId);
|
|
}
|
|
|
|
function findUserPointsHtml(userId: string) {
|
|
let result = "";
|
|
const gradedUser = findGradedUser(userId);
|
|
if (gradedUser) {
|
|
result = `${gradedUser.points} ${t("assignment.von x Punkten", {
|
|
x: gradedUser.maxPoints,
|
|
})}`;
|
|
|
|
result +=
|
|
" (" +
|
|
(((gradedUser.points ?? 0) / (gradedUser.maxPoints ?? 1)) * 100).toFixed(0) +
|
|
"%)";
|
|
|
|
if (!gradedUser.passed) {
|
|
result += ` <span class="my-2 rounded-md bg-error-red-200 px-2.5 py-0.5 inline-block leading-5">${t(
|
|
"a.Nicht bestanden"
|
|
)}</span>`;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function generateCertificatesLink(userId: string) {
|
|
const parts = props.learningContent.competence_certificate?.frontend_url?.split("/");
|
|
|
|
if (!parts) {
|
|
return "";
|
|
}
|
|
|
|
const certificatePart = parts[parts.length - 1];
|
|
return `/course/${props.courseSession.course.slug}/profile/${userId}/competence/certificates/${certificatePart}`;
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<h2 class="heading-2 font-bold">
|
|
{{ learningContent.title }}
|
|
</h2>
|
|
<div class="pt-1 underline">
|
|
{{ $t("a.Circle") }} «{{ learningContent.circle?.title }}»
|
|
</div>
|
|
<div v-if="assignmentDetail">
|
|
<span v-if="assignmentDetail.submission_deadline?.start">
|
|
{{ $t("Abgabetermin Ergebnisse:") }}
|
|
{{ formatDueDate(assignmentDetail.submission_deadline?.start) }}
|
|
</span>
|
|
<template v-if="assignmentDetail.evaluation_deadline?.start">
|
|
<br />
|
|
{{ $t("Freigabetermin Bewertungen:") }}
|
|
{{ formatDueDate(assignmentDetail.evaluation_deadline?.start) }}
|
|
</template>
|
|
</div>
|
|
<div v-else>
|
|
{{ $t("Keine Auftragsdetails verfügbar.") }}
|
|
</div>
|
|
|
|
<div class="mt-4">
|
|
<!-- how to determine assignment-type? how to get AssignmentLearningContent? -->
|
|
<AssignmentSubmissionProgress
|
|
:course-session="courseSession"
|
|
:learning-content="learningContent"
|
|
:show-title="false"
|
|
:user-selection-ids="props.userSelectionIds"
|
|
/>
|
|
</div>
|
|
|
|
<div v-if="courseSessionDetailResult.filterMembers().length" class="mt-6">
|
|
<ul>
|
|
<ItPersonRow
|
|
v-for="csu in courseSessionDetailResult.filterMembers(props.userSelectionIds)"
|
|
:key="csu.user_id"
|
|
:name="`${csu.first_name} ${csu.last_name}`"
|
|
:avatar-url="csu.avatar_url"
|
|
:data-cy="csu.last_name"
|
|
>
|
|
<template #center>
|
|
<section class="flex w-full flex-col justify-between lg:flex-row lg:gap-8">
|
|
<div
|
|
v-if="
|
|
state.gradedUsers.map((gradedUser) => gradedUser.user).includes(csu)
|
|
"
|
|
class="flex items-center"
|
|
>
|
|
<div
|
|
class="relative flex h-7 w-7 items-center justify-center rounded-full border border-green-500 bg-green-500"
|
|
>
|
|
<it-icon-check class="h-4/5 w-4/5"></it-icon-check>
|
|
</div>
|
|
<div class="ml-2">
|
|
{{
|
|
isPraxisAssignment
|
|
? $t("a.Feedback freigegeben")
|
|
: $t("a.Bewertung freigegeben")
|
|
}}
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-else-if="state.assignmentSubmittedUsers.includes(csu)"
|
|
class="flex items-center"
|
|
>
|
|
<div
|
|
class="relative flex h-7 w-7 items-center justify-center rounded-full border border-green-500"
|
|
>
|
|
<it-icon-check class="h-6 w-6"></it-icon-check>
|
|
</div>
|
|
<div class="ml-2">{{ $t("a.Ergebnisse abgegeben") }}</div>
|
|
</div>
|
|
|
|
<!-- eslint-disable vue/no-v-html -->
|
|
<p
|
|
v-if="findGradedUser(csu.user_id) && !isPraxisAssignment"
|
|
class="text-left md:text-right"
|
|
v-html="findUserPointsHtml(csu.user_id)"
|
|
></p>
|
|
</section>
|
|
</template>
|
|
<template #link>
|
|
<div class="lg:ml-4">
|
|
<router-link
|
|
v-if="
|
|
state.assignmentSubmittedUsers.includes(csu) &&
|
|
props.learningContent.content_type !==
|
|
'learnpath.LearningContentEdoniqTest'
|
|
"
|
|
:to="
|
|
props.linkToResults
|
|
? `/course/${props.courseSession.course.slug}/assignment-evaluation/${learningContent.content_assignment.id}/${csu.user_id}`
|
|
: generateCertificatesLink(csu.user_id)
|
|
"
|
|
class="link lg:w-full lg:text-right"
|
|
data-cy="show-results"
|
|
>
|
|
{{
|
|
props.linkToResults
|
|
? $t("a.Ergebnisse anschauen")
|
|
: $t("a.Profil anzeigen")
|
|
}}
|
|
</router-link>
|
|
</div>
|
|
</template>
|
|
</ItPersonRow>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped></style>
|