| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- <template>
- <div class="flex gap-2">
- <select
- v-if="showType"
- v-model="ruleset.column"
- class="w-2/6 md:w-3/12"
- name="searchType"
- @change="filterTypeChanged"
- >
- <option
- :value="ClassSelectorColumn.Module"
- default
- >
- Modul
- </option>
- <option
- :value="ClassSelectorColumn.Degree"
- default
- >
- Studiengang
- </option>
- <option :value="ClassSelectorColumn.Room">
- Raum
- </option>
- <option :value="ClassSelectorColumn.Class">
- Klasse
- </option>
- <option :value="ClassSelectorColumn.Lecturer">
- Dozent
- </option>
- <option :value="ClassSelectorColumn.Time">
- Zeit
- </option>
- <option :value="ClassSelectorColumn.TeachingType">
- Art
- </option>
- </select>
- <div class="w-full justify-center">
- <div
- v-if="ruleset.column == ClassSelectorColumn.Time"
- class="w-full gap-2 grid grid-cols-1"
- >
- <div class="flex items-center">
- <span class="hidden md:inline w-12">Von:</span>
- <WeekdayTimePicker
- v-model="(ruleset.filterData as Record<string, number>).startTime"
- :disable-greater-than="disableUpper"
- class="w-full"
- />
- </div>
- <div class="flex items-center">
- <span class="hidden md:inline w-12">Bis:</span>
- <WeekdayTimePicker
- v-model="(ruleset.filterData as Record<string, number>).endTime"
- :disable-lower-than="disableLower"
- class="w-full"
- />
- </div>
- </div>
- <select
- v-else-if="ruleset.column == ClassSelectorColumn.Degree"
- id="degreeSelector"
- v-model="ruleset.filterData.degree"
- class="w-full"
- @change="
- () =>
- stateStore.updateLastSelectedDegreeProgram(
- ruleset.filterData.degree ?? '',
- )
- "
- >
- <option
- default
- value=""
- >
- Alle
- </option>
- <option
- v-for="name in classesStore.degreePrograms"
- :key="name"
- :value="name"
- >
- {{ name }}
- </option>
- </select>
- <select
- v-else-if="ruleset.column == ClassSelectorColumn.TeachingType"
- id="teachingTypeSelector"
- v-model="ruleset.filterData.teachingType"
- class="w-full capitalize"
- >
- <option
- default
- value=""
- >
- Alle
- </option>
- <option
- v-for="name in TeachingType"
- :key="name"
- :value="name"
- >
- {{ name }}
- </option>
- </select>
- <input
- v-else
- v-model="ruleset.filterData.term"
- class="w-full"
- name="search"
- type="text"
- :placeholder="searchPlaceholderText"
- autocomplete="off"
- >
- </div>
- <div
- v-if="showAddRemove"
- class="w-32 flex justify-center items-center"
- >
- <button
- class="action-button"
- title="Neuen Filter nach diesem einfügen"
- @click="$emit('addFilter', ruleset)"
- >
- <font-awesome-icon icon="fa-solid fa-plus" />
- </button>
- <button
- :disabled="isLastFilter"
- class="action-button"
- title="Diesen Filter entfernen"
- @click="$emit('removeFilter', ruleset)"
- >
- <font-awesome-icon icon="fa-solid fa-minus" />
- </button>
- <div
- title="Filtering ein/ausschalten"
- class="action-checkbox"
- @click="filterEnabledClick(false)"
- >
- <input
- v-model="ruleset.enabled"
- type="checkbox"
- @change="filterEnabledClick(true)"
- >
- </div>
- </div>
- </div>
- </template>
- <script lang="ts">
- import { PropType } from "vue";
- import { useClassesStore } from "../../stores/classes";
- import { useStateStore } from "../../stores/state";
- import { ClassSelectorColumn, FilterRule, TeachingType } from "../../types";
- import WeekdayTimePicker from "../general/WeekdayTimePicker.vue";
- export default {
- name: "ClassFilter",
- components: { WeekdayTimePicker },
- props: {
- modelValue: {
- required: true,
- type: Object as PropType<FilterRule>,
- },
- isLastFilter: {
- required: false,
- type: Boolean,
- default: true,
- },
- showType: {
- required: false,
- type: Boolean,
- default: true,
- },
- showAddRemove: {
- required: false,
- type: Boolean,
- default: true,
- },
- },
- emits: ["update:modelValue", "addFilter", "removeFilter"],
- setup() {
- const classesStore = useClassesStore();
- const stateStore = useStateStore();
- return {
- ClassSelectorColumn,
- classesStore,
- stateStore,
- TeachingType,
- };
- },
- data() {
- return {
- ruleset: this.modelValue,
- };
- },
- computed: {
- disableUpper(): number {
- return Math.floor(
- ((this.ruleset.filterData as Record<string, number>).endTime ??
- 86400 * 7) / 86400,
- );
- },
- disableLower(): number {
- return Math.floor(
- ((this.ruleset.filterData as Record<string, number>).startTime ?? 0) /
- 86400,
- );
- },
- searchPlaceholderText(): string {
- switch (this.ruleset.column) {
- case ClassSelectorColumn.Module:
- return "Suche nach Modulkürzel oder Name";
- case ClassSelectorColumn.Room:
- return "Suche nach Raumbezeichnung";
- case ClassSelectorColumn.Class:
- return "Suche nach Klassenbezeichnung";
- case ClassSelectorColumn.Lecturer:
- return "Suche nach Dozentenkürzel";
- case ClassSelectorColumn.Time:
- break;
- }
- return "";
- },
- },
- methods: {
- filterEnabledClick(direct: boolean) {
- if (!direct) {
- // Someone pressed the box around the checkbox.
- this.ruleset.enabled = !this.ruleset.enabled;
- } else {
- // Only notify changes when the value change is detected directly
- this.filterChanged();
- }
- },
- filterChanged() {
- this.$emit("update:modelValue", this.ruleset);
- },
- filterTypeChanged() {
- if (this.ruleset.column == ClassSelectorColumn.Degree) {
- if (!this.ruleset.filterData.degree)
- this.ruleset.filterData.degree = this.classesStore.degreePrograms[0];
- }
- if (this.ruleset.column == ClassSelectorColumn.TeachingType) {
- if (!this.ruleset.filterData.teachingType)
- this.ruleset.filterData.teachingType = "";
- }
- },
- },
- };
- </script>
- <style scoped>
- @reference "../../style.css";
- .action-button {
- @apply h-5
- text-xs
- md:h-7
- md:text-base
- mx-0.5
- md:mx-1
- block
- bg-gray-200
- hover:bg-gray-300
- active:bg-gray-400
- disabled:bg-gray-200
- disabled:text-gray-400
- dark:bg-gray-700
- dark:hover:bg-gray-600
- dark:active:bg-gray-700
- dark:disabled:bg-gray-800
- dark:disabled:text-gray-600
- disabled:pointer-events-none
- aspect-square
- rounded-sm
- transition-all
- duration-200;
- }
- .action-checkbox {
- @apply h-5
- text-xs
- m-2
- md:h-7
- md:text-base
- mx-0.5
- md:mx-1
- bg-gray-200
- hover:bg-gray-300
- active:bg-gray-400
- disabled:bg-gray-200
- disabled:text-gray-400
- dark:bg-gray-700
- dark:hover:bg-gray-600
- dark:active:bg-gray-700
- dark:disabled:bg-gray-800
- dark:disabled:text-gray-600
- disabled:pointer-events-none
- aspect-square
- rounded-sm
- transition-all
- duration-200
- items-center
- flex
- cursor-pointer;
- }
- .action-checkbox input {
- @apply cursor-pointer;
- }
- </style>
|