Merging origin/dev into feat/assignment-page correctie

This commit is contained in:
Joyelle Ndagijimana 2025-04-07 18:21:24 +02:00
commit baea0051e6
249 changed files with 6754 additions and 3612 deletions

View file

@ -1,9 +1,10 @@
<script setup lang="ts">
import ThemeCard from "@/components/ThemeCard.vue";
import { ref, watchEffect, computed } from "vue";
import { ref, watchEffect, computed, type Ref } from "vue";
import { useI18n } from "vue-i18n";
import { AGE_TO_THEMES, THEMESITEMS } from "@/utils/constants.ts";
import { useThemeQuery } from "@/queries/themes.ts";
import type { Theme } from "@/data-objects/theme.ts";
const props = defineProps({
selectedTheme: { type: String, required: true },
@ -15,11 +16,11 @@
const { data: allThemes, isLoading, error } = useThemeQuery(language);
const allCards = ref([]);
const cards = ref([]);
const allCards: Ref<Theme[]> = ref([]);
const cards: Ref<Theme[]> = ref([]);
watchEffect(() => {
const themes = allThemes.value ?? [];
const themes: Theme[] = allThemes.value ?? [];
allCards.value = themes;
if (props.selectedTheme) {

View file

@ -1,7 +0,0 @@
<script setup lang="ts"></script>
<template>
<main></main>
</template>
<style scoped></style>

View file

@ -0,0 +1,34 @@
<script setup lang="ts">
import { useI18n } from "vue-i18n";
import { useRoute, useRouter } from "vue-router";
import { computed, ref } from "vue";
const route = useRoute();
const router = useRouter();
const { t } = useI18n();
const SEARCH_PATH = "/learningPath/search";
const query = computed({
get: () => route.query.query as string | null,
set: async (newValue) => router.push({ path: SEARCH_PATH, query: { query: newValue } }),
});
const queryInput = ref(query.value);
function search(): void {
query.value = queryInput.value;
}
</script>
<template>
<v-text-field
class="search-field"
:label="t('search')"
append-inner-icon="mdi-magnify"
v-model="queryInput"
@keyup.enter="search()"
@click:append-inner="search()"
></v-text-field>
</template>
<style scoped></style>

View file

@ -0,0 +1,62 @@
<script setup lang="ts">
import { convertBase64ToImageSrc } from "@/utils/base64ToImage.ts";
import type { LearningPath } from "@/data-objects/learning-paths/learning-path.ts";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const props = defineProps<{ learningPaths: LearningPath[] }>();
</script>
<template>
<div
class="results-grid"
v-if="props.learningPaths.length > 0"
>
<v-card
class="learning-path-card"
link
:to="`/learningPath/${learningPath.hruid}/${learningPath.language}/${learningPath.startNode.learningobjectHruid}`"
:key="`${learningPath.hruid}/${learningPath.language}`"
v-for="learningPath in props.learningPaths"
>
<v-img
height="300px"
:src="convertBase64ToImageSrc(learningPath.image)"
cover
v-if="learningPath.image"
></v-img>
<v-card-title class="learning-path-title">{{ learningPath.title }}</v-card-title>
<v-card-subtitle>
<v-icon icon="mdi-human-male-boy"></v-icon>
<span>{{ learningPath.targetAges.min }} - {{ learningPath.targetAges.max }} {{ t("yearsAge") }}</span>
</v-card-subtitle>
<v-card-text>{{ learningPath.description }}</v-card-text>
</v-card>
</div>
<div
content="empty-state-container"
v-else
>
<v-empty-state
icon="mdi-emoticon-sad-outline"
:title="t('noLearningPathsFound')"
:text="t('noLearningPathsFoundDescription')"
></v-empty-state>
</div>
</template>
<style scoped>
.learning-path-card {
width: 300px;
}
.learning-path-title {
white-space: normal;
}
.results-grid {
margin: 20px;
display: flex;
align-items: stretch;
gap: 20px;
flex-wrap: wrap;
}
</style>

View file

@ -26,20 +26,19 @@
]);
// Logic to change the language of the website to the selected language
const changeLanguage = (langCode: string) => {
function changeLanguage(langCode: string): void {
locale.value = langCode;
localStorage.setItem("user-lang", langCode);
};
}
// Contains functionality to let the collapsed menu appear and disappear
// When the screen size varies
// Contains functionality to let the collapsed menu appear and disappear when the screen size varies
const drawer = ref(false);
// When the user wants to logout, a popup is shown to verify this
// If verified, the user should be logged out
const performLogout = () => {
auth.logout();
};
async function performLogout(): Promise<void> {
await auth.logout();
}
</script>
<template>

View file

@ -0,0 +1,45 @@
<script setup lang="ts" generic="T">
import { computed } from "vue";
import { useI18n } from "vue-i18n";
import type { UseQueryReturnType } from "@tanstack/vue-query";
const props = defineProps<{
queryResult: UseQueryReturnType<T, Error>;
}>();
const { isLoading, isError, isSuccess, data, error } = props.queryResult;
const { t } = useI18n();
const errorMessage = computed(() => {
const errorWithMessage = (error.value as { message: string }) || null;
return errorWithMessage?.message || JSON.stringify(errorWithMessage);
});
</script>
<template>
<div
class="loading-div"
v-if="isLoading"
>
<v-progress-circular indeterminate></v-progress-circular>
</div>
<div v-if="isError">
<v-empty-state
icon="mdi-alert-circle-outline"
:text="errorMessage"
:title="t('error_title')"
></v-empty-state>
</div>
<slot
v-if="isSuccess && data"
:data="data"
></slot>
</template>
<style scoped>
.loading-div {
padding: 20px;
text-align: center;
}
</style>