vbv/client/src/pages/dashboard/DashboardDueDatesPage.vue

245 lines
6.3 KiB
Vue

<script setup lang="ts">
import LoadingSpinner from "@/components/ui/LoadingSpinner.vue";
import log from "loglevel";
import { useCourseData, useDashboardPersons } from "@/composables";
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
import { computed, ref, watch } from "vue";
import { useTranslation } from "i18next-vue";
import _ from "lodash";
import DueDatesList from "@/components/dueDates/DueDatesList.vue";
log.debug("DashboardPersonsPage created");
const UNFILTERED = Number.MAX_SAFE_INTEGER.toString();
type DropboxItem = {
id: string;
name: string;
};
type CourseItem = DropboxItem & {
slug: string;
};
const { t } = useTranslation();
const { loading, dashboardDueDates } = useDashboardPersons();
const courses = computed(() => {
return [
{
id: UNFILTERED,
name: t("a.Alle Lehrgänge"),
slug: "",
},
..._(dashboardDueDates.value)
.map((dueDate) => {
return {
name: dueDate.course_session.course_title,
id: dueDate.course_session.course_id,
slug: dueDate.course_session.course_slug,
};
})
.uniqBy("id")
.orderBy("name")
.value(),
];
});
const selectedCourse = ref<CourseItem>(courses.value[0]);
const courseSessions = computed(() => {
let sessions = _(dashboardDueDates.value)
.map((dueDate) => {
return Object.assign({}, dueDate.course_session, {
name: dueDate.course_session.session_title,
id: dueDate.course_session.id,
});
})
.uniqBy("id")
.orderBy("name")
.value();
// filter by selected course
if (selectedCourse.value.id !== UNFILTERED) {
sessions = sessions.filter((cs) => cs.course_id === selectedCourse.value.id);
}
return [
{
id: UNFILTERED,
name: t("a.AlleDurchführungen"),
},
...sessions,
];
});
const selectedSession = ref<DropboxItem>(courseSessions.value[0]);
const filteredDueDates = computed(() => {
return _.orderBy(
dashboardDueDates.value
.filter((dueDate) => {
if (selectedCourse.value.id === UNFILTERED) {
return true;
}
return dueDate.course_session.course_id === selectedCourse.value.id;
})
.filter((dueDate) => {
if (selectedSession.value.id === UNFILTERED) {
return true;
}
return dueDate.course_session.id === selectedSession.value.id;
})
.filter((dueDate) => {
if (selectedCircle.value.id === UNFILTERED) {
return true;
}
return dueDate.circle?.id === selectedCircle.value.id;
})
.filter((dueDate) => {
if (selectedType.value.id === UNFILTERED) {
return true;
}
return dueDate.translatedType === selectedType.value.id;
}),
["start"]
);
});
const filtersVisible = computed(() => {
return (
courses.value.length > 2 ||
courseSessions.value.length > 2 ||
circles.value.length > 2 ||
dueDateTypes.value.length > 2
);
});
const initialItemCircle: DropboxItem = {
id: UNFILTERED,
name: t("a.AlleCircle"),
};
const circles = ref<DropboxItem[]>([initialItemCircle]);
const selectedCircle = ref<DropboxItem>(circles.value[0]);
async function loadCircleValues() {
if (selectedCourse.value && selectedCourse.value.slug) {
const learningPathQuery = useCourseData(selectedCourse.value.slug);
await learningPathQuery.resultPromise;
circles.value = [
initialItemCircle,
...(learningPathQuery.circles.value ?? []).map((circle) => ({
id: circle.id,
name: circle.title,
})),
];
} else {
circles.value = [initialItemCircle];
}
selectedCircle.value = circles.value[0];
}
const dueDateTypes = computed(() => {
const types = _(dashboardDueDates.value)
.map((dueDate) => {
return {
name: dueDate.translatedType,
id: dueDate.translatedType,
};
})
.uniqBy("id")
.orderBy("name")
.value();
return [
{
id: UNFILTERED,
name: t("a.AlleTypen"),
},
...types,
];
});
const selectedType = ref<DropboxItem>(dueDateTypes.value[0]);
watch(selectedCourse, async () => {
selectedSession.value = courseSessions.value[0];
await loadCircleValues();
});
</script>
<template>
<div>
<div v-if="loading" class="m-8 flex justify-center">
<LoadingSpinner />
</div>
<div v-else class="bg-gray-200">
<div class="container-large">
<router-link
:to="`/`"
class="btn-text inline-flex items-center p-0"
data-cy="back-to-learning-path-button"
>
<it-icon-arrow-left class="-ml-1 mr-1 h-5 w-5"></it-icon-arrow-left>
<span class="inline">{{ $t("general.back") }}</span>
</router-link>
<h2 class="my-4">{{ $t("a.Termine") }}</h2>
<div class="bg-white px-4 py-2">
<section
v-if="filtersVisible"
class="flex flex-col space-x-0 border-b bg-white lg:flex-row lg:space-x-3"
>
<ItDropdownSelect
v-if="courses.length > 2"
v-model="selectedCourse"
data-cy="session-select"
:items="courses"
borderless
></ItDropdownSelect>
<ItDropdownSelect
v-if="courseSessions.length > 2"
v-model="selectedSession"
data-cy="session-select"
:items="courseSessions"
borderless
></ItDropdownSelect>
<ItDropdownSelect
v-if="circles.length > 2"
v-model="selectedCircle"
data-cy="appointments-circle-select"
:items="circles"
borderless
></ItDropdownSelect>
<ItDropdownSelect
v-if="dueDateTypes.length > 2"
v-model="selectedType"
data-cy="appointments-type-select"
:items="dueDateTypes"
borderless
></ItDropdownSelect>
</section>
<section>
<DueDatesList
:show-top-border="false"
:show-bottom-border="false"
:due-dates="filteredDueDates"
:show-all-due-dates-link="false"
:max-count="100"
data-cy="due-date-list"
:show-course-session="true"
/>
</section>
</div>
</div>
</div>
</div>
</template>