180 lines
5.7 KiB
Vue
180 lines
5.7 KiB
Vue
<script setup lang="ts">
|
|
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
|
|
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
|
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
|
import { useCurrentCourseSession } from "@/composables";
|
|
import type { AttendanceUserStatus } from "@/gql/graphql";
|
|
import { ATTENDANCE_CHECK_MUTATION } from "@/graphql/mutations";
|
|
import { ATTENDANCE_CHECK_QUERY } from "@/graphql/queries";
|
|
import { useCockpitStore } from "@/stores/cockpit";
|
|
import type { DropdownSelectable } from "@/types";
|
|
import { useMutation, useQuery } from "@urql/vue";
|
|
import dayjs from "dayjs";
|
|
import log from "loglevel";
|
|
import { computed, reactive, watch } from "vue";
|
|
import { useTranslation } from "i18next-vue";
|
|
|
|
const { t } = useTranslation();
|
|
const cockpitStore = useCockpitStore();
|
|
const courseSession = useCurrentCourseSession();
|
|
const attendanceMutation = useMutation(ATTENDANCE_CHECK_MUTATION);
|
|
|
|
const attendanceCourses = computed(() => {
|
|
return courseSession.value.attendance_courses;
|
|
});
|
|
|
|
const presenceCoursesDropdownOptions = computed(() => {
|
|
return attendanceCourses.value.map(
|
|
(attendanceCourse) =>
|
|
({
|
|
id: attendanceCourse.id,
|
|
name: `${t("Präsenzkurs")} ${dayjs(attendanceCourse.start).format(
|
|
"DD.MM.YYYY"
|
|
)}`,
|
|
} as DropdownSelectable)
|
|
);
|
|
});
|
|
|
|
const attendanceCourseSelected = computed(
|
|
() => state.attendanceCourseSelected.id != "-1"
|
|
);
|
|
|
|
const state = reactive({
|
|
userPresence: new Map<string, boolean>(),
|
|
attendanceCourseSelected: presenceCoursesDropdownOptions.value[0],
|
|
disclaimerConfirmed: false,
|
|
attendanceSaved: false,
|
|
});
|
|
|
|
const attendanceQuery = useQuery({
|
|
query: ATTENDANCE_CHECK_QUERY,
|
|
pause: true,
|
|
variables: {
|
|
courseSessionId: state.attendanceCourseSelected.id.toString(),
|
|
},
|
|
});
|
|
|
|
const onSubmit = async () => {
|
|
type UserPresence = {
|
|
user_id: string;
|
|
status: AttendanceUserStatus;
|
|
};
|
|
const attendanceUserList: UserPresence[] = Array.from(state.userPresence.keys()).map(
|
|
(key) => ({
|
|
user_id: key,
|
|
status: state.userPresence.get(key) ? "PRESENT" : "ABSENT",
|
|
})
|
|
);
|
|
const res = await attendanceMutation.executeMutation({
|
|
attendanceCourseId: state.attendanceCourseSelected.id.toString(),
|
|
attendanceUserList: attendanceUserList,
|
|
});
|
|
if (res.error) {
|
|
log.error("Could not submit attendance check: ", res.error);
|
|
return;
|
|
}
|
|
state.disclaimerConfirmed = false;
|
|
state.attendanceSaved = true;
|
|
log.info("Attendance check submitted: ", res);
|
|
};
|
|
|
|
const loadAttendanceData = async () => {
|
|
const res = await attendanceQuery.executeQuery();
|
|
const attendanceUserList =
|
|
res?.data?.value?.course_session_attendance_course?.attendance_user_list ?? [];
|
|
for (const user of attendanceUserList) {
|
|
if (!user) continue;
|
|
state.userPresence.set(user.user_id.toString(), user.status === "PRESENT");
|
|
}
|
|
if (attendanceUserList.length !== 0) {
|
|
state.attendanceSaved = true;
|
|
}
|
|
};
|
|
|
|
loadAttendanceData();
|
|
watch(state.attendanceCourseSelected, () => {
|
|
loadAttendanceData();
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="bg-gray-200">
|
|
<div class="container-large">
|
|
<nav class="py-4 pb-4">
|
|
<router-link
|
|
class="btn-text inline-flex items-center pl-0"
|
|
:to="`/course/${courseSession.course.slug}/cockpit`"
|
|
>
|
|
<it-icon-arrow-left />
|
|
<span>{{ $t("general.back") }}</span>
|
|
</router-link>
|
|
</nav>
|
|
<div class="pb-4 text-xl font-bold">{{ $t("Anwesenheit Präsenzkurse") }}</div>
|
|
<div class="flex flex-row justify-between bg-white p-6">
|
|
<ItDropdownSelect
|
|
v-model="state.attendanceCourseSelected"
|
|
:items="presenceCoursesDropdownOptions ?? []"
|
|
></ItDropdownSelect>
|
|
<div v-if="!state.attendanceSaved" class="flex flex-row items-center">
|
|
<ItCheckbox
|
|
:disabled="!attendanceCourseSelected"
|
|
:checkbox-item="{
|
|
value: true,
|
|
checked: state.disclaimerConfirmed,
|
|
}"
|
|
@toggle="state.disclaimerConfirmed = !state.disclaimerConfirmed"
|
|
></ItCheckbox>
|
|
<p class="w-64 pr-4 text-sm">
|
|
{{
|
|
$t(
|
|
"Ich will die Anwesenheit der untenstehenden Personen definitiv bestätigen."
|
|
)
|
|
}}
|
|
</p>
|
|
<button
|
|
class="btn-primary"
|
|
:disabled="!state.disclaimerConfirmed"
|
|
@click="onSubmit"
|
|
>
|
|
{{ $t("Anwesenheit bestätigen") }}
|
|
</button>
|
|
</div>
|
|
<div v-else class="self-center">
|
|
<p class="text-base">
|
|
{{ $t("Die Anwesenheit wurde definitiv bestätigt.") }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 flex flex-col bg-white p-6">
|
|
<div
|
|
v-for="(csu, index) in cockpitStore.courseSessionUsers"
|
|
:key="csu.user_id + csu.session_title"
|
|
>
|
|
<ItPersonRow
|
|
:name="`${csu.first_name} ${csu.last_name}`"
|
|
:avatar-url="csu.avatar_url"
|
|
:class="0 === index ? 'border-none' : ''"
|
|
>
|
|
<template #leading>
|
|
<ItCheckbox
|
|
:disabled="!attendanceCourseSelected || state.attendanceSaved"
|
|
:checkbox-item="{
|
|
value: true,
|
|
checked: state.userPresence.get(csu.user_id.toString()) as boolean,
|
|
}"
|
|
@toggle="
|
|
state.userPresence.set(
|
|
csu.user_id.toString(),
|
|
!state.userPresence.get(csu.user_id.toString())
|
|
)
|
|
"
|
|
></ItCheckbox>
|
|
</template>
|
|
</ItPersonRow>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|