From 20c6ccfac4447b06bc49bf194d13db056430aa69 Mon Sep 17 00:00:00 2001 From: Alexander Vogt Date: Thu, 19 Sep 2024 20:09:20 +0200 Subject: [PATCH 1/3] add filtering --- website/src/assets/filter-solid.svg | 1 + website/src/assets/question-solid.svg | 1 + website/src/components/FachDisplay.vue | 31 +++- website/src/components/FilterComponent.vue | 175 ++++++++++++++++++ website/src/components/ModulleList.vue | 62 ++++++- website/src/components/WahlbereichDisplay.vue | 7 +- website/src/components/WahlbereichList.vue | 7 + website/src/model/ui/FilterState.ts | 11 ++ 8 files changed, 288 insertions(+), 7 deletions(-) create mode 100644 website/src/assets/filter-solid.svg create mode 100644 website/src/assets/question-solid.svg create mode 100644 website/src/components/FilterComponent.vue create mode 100644 website/src/model/ui/FilterState.ts diff --git a/website/src/assets/filter-solid.svg b/website/src/assets/filter-solid.svg new file mode 100644 index 0000000..7ddb60f --- /dev/null +++ b/website/src/assets/filter-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/assets/question-solid.svg b/website/src/assets/question-solid.svg new file mode 100644 index 0000000..1bd2883 --- /dev/null +++ b/website/src/assets/question-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/components/FachDisplay.vue b/website/src/components/FachDisplay.vue index 345cadb..d905917 100644 --- a/website/src/components/FachDisplay.vue +++ b/website/src/components/FachDisplay.vue @@ -1,23 +1,32 @@ \ No newline at end of file diff --git a/website/src/components/FilterComponent.vue b/website/src/components/FilterComponent.vue new file mode 100644 index 0000000..6732575 --- /dev/null +++ b/website/src/components/FilterComponent.vue @@ -0,0 +1,175 @@ + + + + + diff --git a/website/src/components/ModulleList.vue b/website/src/components/ModulleList.vue index 1c13192..287658f 100644 --- a/website/src/components/ModulleList.vue +++ b/website/src/components/ModulleList.vue @@ -13,14 +13,14 @@
, + required: true, + }, }); const pflichtbereichListe = computed(() => { @@ -101,9 +107,15 @@ const chosenModules = computed(() => const chosenInOtherModules = computed(() => chosenInOtherModulesIds.value.map((id) => state().getModulById(id)) ); +const filteredChosenInOtherModules = computed(() => + chosenInOtherModules.value.filter(applyFilter) +); const chosableModules = computed(() => chosableIds.value.map((id) => state().getModulById(id)) ); +const filteredChosableModules = computed(() => + chosableModules.value.filter(applyFilter) +); function exedsLimit(modul: Modul) { return !canAcceptChoice( @@ -117,4 +129,48 @@ function exedsLimit(modul: Modul) { function addModul(modul: Modul) { state().addModul(props.slot, modul.id, props.wahlbereichIndex); } + +function applyFilter(modul: Modul) { + if (props.filter.minEcts > modul.lp || props.filter.maxEcts < modul.lp) { + return false; + } + if (props.filter.stammmoduleOnly && !Stammmodule.includes(modul.name.trim())) { + return false; + } + + // semesterfilter + const isSoSe = modul.turnus.toLocaleLowerCase().includes("sose") || modul.turnus.toLocaleLowerCase().includes("ss") || modul.turnus.toLocaleLowerCase().includes("sommersemester"); + const isWiSe = modul.turnus.toLocaleLowerCase().includes("wise") || modul.turnus.toLocaleLowerCase().includes("ws") || modul.turnus.toLocaleLowerCase().includes("wintersemester"); + if (isSoSe && !props.filter.semester.includes("SoSe")) { + return false; + } + if (isWiSe && !props.filter.semester.includes("WiSe")) { + return false; + } + if (!isSoSe && !isWiSe && !props.filter.semester.includes("unknown")) { + return false; + } + + // languagefilter + const isGerman = modul.sprache.toLocaleLowerCase().includes("german") || modul.sprache.toLocaleLowerCase().includes("deutsch"); + const isEnglish = modul.sprache.toLocaleLowerCase().includes("englisch") || modul.sprache.toLocaleLowerCase().includes("english"); + if (isGerman && !props.filter.language.includes("De")) { + return false; + } + if (isEnglish && !props.filter.language.includes("Eng")) { + return false; + } + if (!isGerman && !isEnglish && !props.filter.language.includes("unknown")) { + return false; + } + + if (props.filter.searchString == "") { + return true; + } + const searchParts = props.filter.searchString.toLocaleLowerCase().split(" "); + const nameParts = modul.name.toLocaleLowerCase().split(" "); + return searchParts.some((searchPart) => { + return nameParts.some(n => n.includes(searchPart)); + }); +} diff --git a/website/src/components/WahlbereichDisplay.vue b/website/src/components/WahlbereichDisplay.vue index 32f0473..523eabf 100644 --- a/website/src/components/WahlbereichDisplay.vue +++ b/website/src/components/WahlbereichDisplay.vue @@ -2,7 +2,7 @@

{{name}}

{{getRestrictionString(wahlbereich, lpList)}}

- +
@@ -13,6 +13,7 @@ import getRestrictionString from '../utils/choiceRestrictionStringBuilder'; import ModulleList from './ModulleList.vue'; import FachSlotNames from '../model/FachSlotNames'; import state from '../store/store'; +import { FilterState } from '../model/ui/FilterState'; const props = defineProps({ wahlbereichIndex: { @@ -22,6 +23,10 @@ const props = defineProps({ slot: { type: String as PropType, required: true + }, + filter: { + type: Object as PropType, + required: true, } }) diff --git a/website/src/components/WahlbereichList.vue b/website/src/components/WahlbereichList.vue index f62c2e6..8efd88e 100644 --- a/website/src/components/WahlbereichList.vue +++ b/website/src/components/WahlbereichList.vue @@ -4,12 +4,14 @@ :wahlbereich-index="0" :slot="slot" :remaining-lp="remainingLp" + :filter="filter" />
@@ -20,12 +22,17 @@ import ModulleList from "./ModulleList.vue"; import WahlbereichDisplay from "./WahlbereichDisplay.vue"; import FachSlotNames from "../model/FachSlotNames"; import state from "../store/store"; +import { FilterState } from "../model/ui/FilterState"; const props = defineProps({ slot: { type: String as PropType, required: true, }, + filter: { + type: Object as PropType, + required: true, + } }); const wahlbereicheCount = computed( diff --git a/website/src/model/ui/FilterState.ts b/website/src/model/ui/FilterState.ts new file mode 100644 index 0000000..5cb0ab5 --- /dev/null +++ b/website/src/model/ui/FilterState.ts @@ -0,0 +1,11 @@ +export interface FilterState { + searchString: string + minEcts: number + maxEcts: number + stammmoduleOnly: boolean + semester: Semester[] + language: Language[] +} + +export type Semester = 'SoSe'|'WiSe'|'unknown' +export type Language = 'De'|'Eng'|'unknown' \ No newline at end of file From 91a94604beb3b2ed7837fd144a05d7cee9d99330 Mon Sep 17 00:00:00 2001 From: Alex | Kronox Date: Fri, 20 Sep 2024 10:27:05 +0200 Subject: [PATCH 2/3] sorting --- website/src/assets/arrow-down-1-9-solid.svg | 1 + website/src/assets/arrow-up-9-1-solid.svg | 1 + website/src/components/FachDisplay.vue | 10 ++- website/src/components/FilterComponent.vue | 81 +++++++++++++++---- website/src/components/ModulleList.vue | 30 ++++++- website/src/components/WahlbereichDisplay.vue | 7 +- website/src/components/WahlbereichList.vue | 7 ++ website/src/model/ui/SortingState.ts | 12 +++ 8 files changed, 127 insertions(+), 22 deletions(-) create mode 100644 website/src/assets/arrow-down-1-9-solid.svg create mode 100644 website/src/assets/arrow-up-9-1-solid.svg create mode 100644 website/src/model/ui/SortingState.ts diff --git a/website/src/assets/arrow-down-1-9-solid.svg b/website/src/assets/arrow-down-1-9-solid.svg new file mode 100644 index 0000000..3485b40 --- /dev/null +++ b/website/src/assets/arrow-down-1-9-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/assets/arrow-up-9-1-solid.svg b/website/src/assets/arrow-up-9-1-solid.svg new file mode 100644 index 0000000..393cacc --- /dev/null +++ b/website/src/assets/arrow-up-9-1-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/components/FachDisplay.vue b/website/src/components/FachDisplay.vue index d905917..3f078ed 100644 --- a/website/src/components/FachDisplay.vue +++ b/website/src/components/FachDisplay.vue @@ -5,7 +5,7 @@

{{ slot }}

- +
{{getRestrictionString(fach ?? {}, lpListForFach)}}
@@ -13,7 +13,7 @@
- +
@@ -27,6 +27,7 @@ import getRestrictionString from '../utils/choiceRestrictionStringBuilder'; import filterSVG from '../assets/filter-solid.svg'; import FilterComponent from './FilterComponent.vue'; import { FilterState } from '../model/ui/FilterState'; +import { SortingOptions, SortingState } from '../model/ui/SortingState'; const props = defineProps({ slot: { @@ -53,6 +54,11 @@ const filterState: Ref = ref({ language: ['De', 'Eng', 'unknown'] }) +const sortingState: Ref = ref({ + sortBy: SortingOptions.NAME, + direction: 1 as 1|-1 +}) + const windowWidth = computed(() => window.innerWidth) const filterElement: Ref = ref(null) const filterPosition = computed(() => filterElement.value?.getBoundingClientRect().x ?? 0) diff --git a/website/src/components/FilterComponent.vue b/website/src/components/FilterComponent.vue index 6732575..46b1392 100644 --- a/website/src/components/FilterComponent.vue +++ b/website/src/components/FilterComponent.vue @@ -77,74 +77,92 @@ @click="changeLanguage('unknown')" /> -
-
+
+ + + +
diff --git a/website/src/components/ModulleList.vue b/website/src/components/ModulleList.vue index 287658f..c66312f 100644 --- a/website/src/components/ModulleList.vue +++ b/website/src/components/ModulleList.vue @@ -49,6 +49,7 @@ import Modul from "../../../model/Module"; import { canAcceptChoice } from "../utils/choiceManagement"; import { FilterState } from "../model/ui/FilterState"; import Stammmodule from "../model/Stammmodule"; +import { SortingOptions, SortingState } from "../model/ui/SortingState"; const props = defineProps({ slot: { @@ -68,6 +69,10 @@ const props = defineProps({ type: Object as PropType, required: true, }, + sorting: { + type: Object as PropType, + required: true, + }, }); const pflichtbereichListe = computed(() => { @@ -108,13 +113,17 @@ const chosenInOtherModules = computed(() => chosenInOtherModulesIds.value.map((id) => state().getModulById(id)) ); const filteredChosenInOtherModules = computed(() => - chosenInOtherModules.value.filter(applyFilter) + chosenInOtherModules.value.filter(applyFilter).sort((a, b) => + sort(a, b, props.sorting.sortBy) * props.sorting.direction + ) ); const chosableModules = computed(() => chosableIds.value.map((id) => state().getModulById(id)) ); const filteredChosableModules = computed(() => - chosableModules.value.filter(applyFilter) + chosableModules.value.filter(applyFilter).sort((a, b) => + sort(a, b, props.sorting.sortBy) * props.sorting.direction + ) ); function exedsLimit(modul: Modul) { @@ -173,4 +182,21 @@ function applyFilter(modul: Modul) { return nameParts.some(n => n.includes(searchPart)); }); } + +function sort(a: Modul, b: Modul, sorting: SortingOptions) { + switch (sorting) { + case SortingOptions.NAME: + return a.name.localeCompare(b.name); + case SortingOptions.ECTS: + return a.lp - b.lp; + case SortingOptions.DOZENT: + return a.verantwortlicher.localeCompare(b.verantwortlicher); + case SortingOptions.SEMSTER: + return b.turnus.localeCompare(a.turnus); + case SortingOptions.SPRACHE: + return b.sprache.localeCompare(a.sprache); + default: + return 0; + } +} diff --git a/website/src/components/WahlbereichDisplay.vue b/website/src/components/WahlbereichDisplay.vue index 523eabf..371f5e7 100644 --- a/website/src/components/WahlbereichDisplay.vue +++ b/website/src/components/WahlbereichDisplay.vue @@ -2,7 +2,7 @@

{{name}}

{{getRestrictionString(wahlbereich, lpList)}}

- +
@@ -14,6 +14,7 @@ import ModulleList from './ModulleList.vue'; import FachSlotNames from '../model/FachSlotNames'; import state from '../store/store'; import { FilterState } from '../model/ui/FilterState'; +import { SortingState } from '../model/ui/SortingState'; const props = defineProps({ wahlbereichIndex: { @@ -27,6 +28,10 @@ const props = defineProps({ filter: { type: Object as PropType, required: true, + }, + sorting: { + type: Object as PropType, + required: true, } }) diff --git a/website/src/components/WahlbereichList.vue b/website/src/components/WahlbereichList.vue index 8efd88e..203119a 100644 --- a/website/src/components/WahlbereichList.vue +++ b/website/src/components/WahlbereichList.vue @@ -5,6 +5,7 @@ :slot="slot" :remaining-lp="remainingLp" :filter="filter" + :sorting="sorting" />
@@ -23,6 +25,7 @@ import WahlbereichDisplay from "./WahlbereichDisplay.vue"; import FachSlotNames from "../model/FachSlotNames"; import state from "../store/store"; import { FilterState } from "../model/ui/FilterState"; +import { SortingState } from "../model/ui/SortingState"; const props = defineProps({ slot: { @@ -32,6 +35,10 @@ const props = defineProps({ filter: { type: Object as PropType, required: true, + }, + sorting: { + type: Object as PropType, + required: true, } }); diff --git a/website/src/model/ui/SortingState.ts b/website/src/model/ui/SortingState.ts new file mode 100644 index 0000000..6897f13 --- /dev/null +++ b/website/src/model/ui/SortingState.ts @@ -0,0 +1,12 @@ +export enum SortingOptions { + NAME = "Alphabetisch", + DOZENT = "Dozent", + ECTS = "ECTS", + SEMSTER = "Semester", + SPRACHE = "Sprache", +} + +export interface SortingState { + sortBy: SortingOptions + direction: 1|-1 +} \ No newline at end of file From a0e763e49fe20219c1ffaff6307a687b591057f2 Mon Sep 17 00:00:00 2001 From: Alex | Kronox Date: Fri, 20 Sep 2024 11:21:09 +0200 Subject: [PATCH 3/3] cursor pointer on all clickabel objects --- website/src/components/FachDisplay.vue | 2 +- website/src/components/FilterComponent.vue | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/website/src/components/FachDisplay.vue b/website/src/components/FachDisplay.vue index 3f078ed..2b2416b 100644 --- a/website/src/components/FachDisplay.vue +++ b/website/src/components/FachDisplay.vue @@ -4,7 +4,7 @@

{{ slot }}

- +
diff --git a/website/src/components/FilterComponent.vue b/website/src/components/FilterComponent.vue index 46b1392..ec551d6 100644 --- a/website/src/components/FilterComponent.vue +++ b/website/src/components/FilterComponent.vue @@ -1,6 +1,6 @@