feat: leerpaden opzoeken en filteren in de create component werkt
This commit is contained in:
parent
aa33d32fa8
commit
9f55e62bcb
5 changed files with 150 additions and 26 deletions
|
@ -44,5 +44,8 @@
|
|||
"next": "nächste",
|
||||
"previous": "vorherige",
|
||||
"groups": "Gruppen",
|
||||
"learning-path": "Lernpfad"
|
||||
"learning-path": "Lernpfad",
|
||||
"choose-lp": "Einen lernpfad auswählen",
|
||||
"filter-themes": "Filter nach Themen",
|
||||
"search-lp": "Suche und Auswahl eines Lernpfads"
|
||||
}
|
||||
|
|
|
@ -44,5 +44,8 @@
|
|||
"next": "next",
|
||||
"previous": "previous",
|
||||
"groups": "Groups",
|
||||
"learning-path": "Learning path"
|
||||
"learning-path": "Learning path",
|
||||
"choose-lp": "Select a learning path",
|
||||
"filter-themes": "Filter by themes",
|
||||
"search-lp": "Search and select a learning path"
|
||||
}
|
||||
|
|
|
@ -44,5 +44,8 @@
|
|||
"next": "suivant",
|
||||
"previous": "précédent",
|
||||
"groups": "Groupes",
|
||||
"learning-path": "Parcours d'apprentissage"
|
||||
"learning-path": "Parcours d'apprentissage",
|
||||
"choose-lp": "Choisis un parcours d'apprentissage",
|
||||
"filter-themes": "Filtrer par thèmes",
|
||||
"search-lp": "Cherche et sélectionne un parcours d'apprentissage"
|
||||
}
|
||||
|
|
|
@ -44,5 +44,8 @@
|
|||
"next": "volgende",
|
||||
"previous": "vorige",
|
||||
"groups": "Groepen",
|
||||
"learning-path": "Leerpad"
|
||||
"learning-path": "Leerpad",
|
||||
"choose-lp": "Kies een leerpad",
|
||||
"filter-themes": "Filter op thema's",
|
||||
"search-lp": "Zoek en selecteer een leerpad"
|
||||
}
|
||||
|
|
|
@ -1,24 +1,129 @@
|
|||
<script setup lang="ts">
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {ref, shallowRef} from "vue";
|
||||
import {computed, onMounted, ref, shallowRef, watch} from "vue";
|
||||
import {THEMESITEMS} from "@/utils/constants.ts";
|
||||
|
||||
const {t} = useI18n();
|
||||
const {t, locale} = useI18n();
|
||||
|
||||
const step = ref(1);
|
||||
|
||||
const loading = ref(false)
|
||||
const language = ref(locale.value);
|
||||
|
||||
function onClick () {
|
||||
loading.value = true
|
||||
}
|
||||
// If this value is set to true, the search bar will display a "loading" animation
|
||||
const loading = ref(false);
|
||||
const searchQuery = ref("");
|
||||
|
||||
|
||||
|
||||
// Use a list with all themes so learning-paths can be filtered by theme
|
||||
// These lists store all available and selected themes
|
||||
const themeItems = ref(Object.keys(THEMESITEMS).slice(1));
|
||||
const value = shallowRef([]);
|
||||
const selectedThemes = shallowRef<string[]>([]);
|
||||
|
||||
// Store all learning paths
|
||||
const allLearningPaths = ref([]);
|
||||
|
||||
// Filtered learning paths that will be displayed in the search bar dropdown
|
||||
const filteredLearningPaths = ref([]);
|
||||
|
||||
// The hruid and title of the currently selected learning path(TODO: use for post req)
|
||||
const selectedLearningPath = ref(null);
|
||||
|
||||
|
||||
// Fetch all learning paths initially
|
||||
async function fetchAllLearningPaths() {
|
||||
//TODO: replace by function from controller
|
||||
try {
|
||||
const response = await fetch(`http://localhost:3000/api/learningPath?language=${language.value}`);
|
||||
|
||||
// Error
|
||||
if (!response.ok) throw new Error("Failed to fetch learning paths");
|
||||
|
||||
// Collect all the learning paths and store them in a list by hruid and title
|
||||
const data = await response.json();
|
||||
allLearningPaths.value = data.map((lp: { hruid: string; title: string }) => ({
|
||||
hruid: lp.hruid,
|
||||
title: lp.title
|
||||
}));
|
||||
|
||||
// Get all the learning paths in the filtered list
|
||||
filteredLearningPaths.value = [...allLearningPaths.value];
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => locale.value,
|
||||
(newLocale) => {
|
||||
// Check if the language is valid
|
||||
if (!["nl", "en"].includes(newLocale)) {
|
||||
language.value = "en";
|
||||
}
|
||||
fetchAllLearningPaths(); // Re-fetch the learning path data when language changes
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// Filter the learning paths based on selected themes
|
||||
async function filterLearningPathsByThemes() {
|
||||
if (selectedThemes.value.length === 0) {
|
||||
// Show all the learning paths if no themes are selected
|
||||
filteredLearningPaths.value = [...allLearningPaths.value];
|
||||
return;
|
||||
}
|
||||
|
||||
const learningPathHruids = new Set();
|
||||
|
||||
// Collect all themes categories that are selected
|
||||
const themeCategories = new Set();
|
||||
selectedThemes.value.forEach(theme => {
|
||||
THEMESITEMS[theme]?.forEach(category => themeCategories.add(category));
|
||||
});
|
||||
|
||||
//TODO: replace by function from controller
|
||||
try {
|
||||
// Fetch all theme data in parallel and wait for all to complete
|
||||
const responses = await Promise.all(
|
||||
Array.from(themeCategories).map(category =>
|
||||
fetch(`http://localhost:3000/api/theme/${category}?language=${language.value}`)
|
||||
.then(response => {
|
||||
if (!response.ok) throw new Error(`Error fetching ${category}`);
|
||||
return response.json();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
return []; // Return empty array on failure
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
// Combine all received hruids and add them in a set
|
||||
responses.forEach(data => {
|
||||
data.forEach((lp: string ) => learningPathHruids.add(lp));
|
||||
});
|
||||
|
||||
|
||||
// Update filteredLearningPaths only after all requests complete
|
||||
filteredLearningPaths.value = allLearningPaths.value.filter(lp =>
|
||||
learningPathHruids.has(lp.hruid)
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error fetching themes:", error);
|
||||
}
|
||||
}
|
||||
|
||||
const searchResults = computed(() => {
|
||||
return filteredLearningPaths.value.filter(lp =>
|
||||
lp.title.toLowerCase().includes(searchQuery.value.toLowerCase())
|
||||
);
|
||||
});
|
||||
|
||||
// Fetch all learning paths on mount
|
||||
onMounted(fetchAllLearningPaths);
|
||||
|
||||
// Watch for theme selection changes and filter lerning paths per theme
|
||||
watch(selectedThemes, filterLearningPathsByThemes);
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -28,14 +133,14 @@
|
|||
<v-stepper class="stepper-container" alt-labels :items="[t('learning-path'), t('classes'), t('groups')]"
|
||||
v-model="step" show-actions>
|
||||
<template v-slot:item.1>
|
||||
<v-card title="Select a learning path" flat>
|
||||
<v-card :title="t('choose-lp')" flat>
|
||||
<v-container class="step-container">
|
||||
<v-card-text>
|
||||
<v-select
|
||||
v-model="value"
|
||||
v-model="selectedThemes"
|
||||
:items="themeItems.map(theme => ({ title: t(`theme-options.${theme}`), value: theme }))"
|
||||
variant="solo"
|
||||
label="Filter by themes"
|
||||
:label="t('filter-themes')"
|
||||
chips
|
||||
multiple
|
||||
deletable-chips
|
||||
|
@ -44,17 +149,24 @@
|
|||
</v-card-text>
|
||||
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
<v-combobox
|
||||
v-model="selectedLearningPath"
|
||||
:items="searchResults"
|
||||
:label="t('search-lp')"
|
||||
variant="solo"
|
||||
clearable
|
||||
hide-details
|
||||
density="compact"
|
||||
:loading="loading"
|
||||
append-inner-icon="mdi-magnify"
|
||||
density="compact"
|
||||
label="Search"
|
||||
variant="solo"
|
||||
hide-details
|
||||
single-line
|
||||
@click:append-inner="onClick"
|
||||
></v-text-field>
|
||||
item-title="title"
|
||||
item-value="value"
|
||||
:filter="(item, query: string) => item.title.toLowerCase().includes(query.toLowerCase())"
|
||||
></v-combobox>
|
||||
</v-card-text>
|
||||
|
||||
|
||||
|
||||
</v-container>
|
||||
</v-card>
|
||||
</template>
|
||||
|
@ -99,7 +211,7 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 70%;
|
||||
padding: 1%;
|
||||
/*padding: 1%;*/
|
||||
}
|
||||
|
||||
.stepper-container {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue