Merge remote-tracking branch 'origin/dev' into feat/pagina-om-leerpaden-te-bekijken-#41

# Conflicts:
#	frontend/src/components/MenuBar.vue
#	frontend/src/i18n/locale/de.json
#	frontend/src/i18n/locale/en.json
#	frontend/src/i18n/locale/fr.json
#	frontend/src/i18n/locale/nl.json
#	frontend/src/main.ts
#	frontend/src/router/index.ts
#	frontend/src/views/HomePage.vue
This commit is contained in:
Gerald Schmittinger 2025-03-25 08:55:40 +01:00
commit 7c55c3a081
27 changed files with 1718 additions and 170 deletions

View file

@ -2,27 +2,197 @@
import auth from "@/services/auth/auth-service.ts";
import apiClient from "@/services/api-client/api-client.ts";
import { ref } from "vue";
import dwengoLogo from "../../../assets/img/dwengo-groen-zwart.svg";
import { useI18n } from "vue-i18n";
const testResponse = ref(null);
const { t, locale } = useI18n();
async function testAuthenticated() {
testResponse.value = await apiClient.get("/auth/testAuthenticatedOnly");
}
const languages = ref([
{ name: "English", code: "en" },
{ name: "Nederlands", code: "nl" },
{ name: "Deutsch", code: "de" },
{ name: "français", code: "fr" },
]);
// Logic to change the language of the website to the selected language
const changeLanguage = (langCode: string) => {
locale.value = langCode;
localStorage.setItem("user-lang", langCode);
};
</script>
<template>
<main>
<!-- TODO Placeholder implementation to test the login - replace by a more beautiful page later -->
<b>Welcome to the dwengo homepage</b>
<div v-if="auth.isLoggedIn.value">
<p>Hello {{ auth.authState.user?.profile.name }}!</p>
<p>
Your access token for the backend is: <code>{{ auth.authState.user?.access_token }}</code>
</p>
<div class="layout">
<div class="container_left">
<img
:src="dwengoLogo"
style="align-self: center"
/>
<h> {{ t("homeTitle") }}</h>
<p class="info">
{{ t("homeIntroduction1") }}
</p>
<p class="info">{{ t("homeIntroduction2") }}</p>
<v-btn
size="large"
density="comfortable"
style="font-weight: bolder; color: white; align-self: center"
color="#88BD28"
to="/login"
>
{{ t("login") }}
<v-icon
end
size="x-large"
>
mdi-menu-right
</v-icon>
</v-btn>
</div>
<div class="container_middle">
<div class="img_small">
<v-img
height="125"
width="125"
src="/assets/home/innovative.png"
></v-img>
<h class="big">{{ t("innovative") }}</h>
</div>
<div class="img_small">
<v-img
height="125"
width="125"
src="/assets/home/research_based.png"
></v-img>
<h class="big">{{ t("researchBased") }}</h>
</div>
<div class="img_small">
<v-img
height="125"
width="125"
src="/assets/home/inclusive.png"
></v-img>
<h class="big">{{ t("sociallyRelevant") }}</h>
</div>
<div class="img_small">
<v-img
height="125"
width="125"
src="/assets/home/socially_relevant.png"
></v-img>
<h class="big">{{ t("inclusive") }}</h>
</div>
</div>
<div class="container_right">
<v-menu open-on-hover>
<template v-slot:activator="{ props }">
<v-btn
v-bind="props"
icon
variant="text"
>
{{ t("translate") }}
<v-icon
end
icon="mdi-translate"
size="small"
color="#0e6942"
></v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
v-for="(language, index) in languages"
:key="index"
@click="changeLanguage(language.code)"
>
<v-list-item-title>{{ language.name }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</div>
</div>
<v-btn @click="testAuthenticated">Send test request</v-btn>
<p v-if="testResponse">Response from the test request: {{ testResponse }}</p>
</main>
</template>
<style scoped></style>
<style scoped>
.layout {
display: flex;
width: 100vw;
height: 100vh;
position: relative;
flex-wrap: wrap;
}
.container_left {
width: 600px;
background-color: #f6faf2;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.container_middle {
flex-grow: 1;
display: flex;
flex-direction: column;
padding: 20px;
align-items: flex-start;
justify-content: center;
}
.container_right {
position: absolute;
top: 2%;
right: 100px;
}
.img_small {
display: flex;
align-items: center;
margin: 20px;
}
img {
width: 300px;
margin-bottom: 10px;
}
h {
font-size: large;
font-weight: bold;
align-self: center;
padding: 10px;
}
.big {
font-size: x-large;
}
.info {
text-align: center;
padding-left: 10px;
padding-right: 10px;
padding-bottom: 30px;
}
@media (max-width: 1024px) {
.container_left {
width: 100%;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
padding: 20px;
position: relative;
}
.container_right {
position: absolute;
top: 10px;
right: 80px;
}
}
</style>

View file

@ -70,6 +70,7 @@
You are currently logged in as {{ auth.authState.user!.profile.name }} ({{ auth.authState.activeRole }})
</p>
<v-btn @click="performLogout">Logout</v-btn>
<v-btn to="/user">home</v-btn>
</div>
</main>
</template>

View file

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

View file

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

View file

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

View file

@ -1,7 +1,125 @@
<script setup lang="ts"></script>
<script setup lang="ts">
import {ref, watch} from "vue";
import {useI18n} from "vue-i18n";
import {THEMESITEMS, AGE_TO_THEMES} from "@/utils/constants.ts";
import BrowseThemes from "@/components/BrowseThemes.vue";
const {t, locale} = useI18n();
const selectedThemeKey = ref<string>('all');
const selectedAgeKey = ref<string>('all');
const allThemes = ref(Object.keys(THEMESITEMS));
const availableThemes = ref([...allThemes.value]);
const allAges = ref(Object.keys(AGE_TO_THEMES));
const availableAges = ref([...allAges.value]);
// Reset selection when language changes
watch(locale, () => {
selectedThemeKey.value = 'all';
selectedAgeKey.value = 'all';
});
watch(selectedThemeKey, () => {
if (selectedThemeKey.value === "all") {
availableAges.value = [...allAges.value]; // Reset to all ages
} else {
const themes = THEMESITEMS[selectedThemeKey.value];
availableAges.value = allAges.value.filter(age =>
AGE_TO_THEMES[age]?.some(theme => themes.includes(theme))
);
}
});
watch(selectedAgeKey, () => {
if (selectedAgeKey.value === "all") {
availableThemes.value = [...allThemes.value]; // Reset to all themes
} else {
const themes = AGE_TO_THEMES[selectedAgeKey.value];
availableThemes.value = allThemes.value.filter(theme =>
THEMESITEMS[theme]?.some(theme => themes.includes(theme))
);
}
});
</script>
<template>
<main></main>
<div class="main-container">
<h1 class="title">{{ t("themes") }}</h1>
<v-container class="dropdowns">
<v-select class="v-select"
:label="t('choose-theme')"
:items="availableThemes.map(theme => ({ title: t(`theme-options.${theme}`), value: theme }))"
v-model="selectedThemeKey"
item-title="title"
item-value="value"
variant="outlined"
/>
<v-select
class="v-select"
:label="t('choose-age')"
:items="availableAges.map(age => ({ key: age, label: t(`age-options.${age}`), value: age }))"
v-model="selectedAgeKey"
item-title="label"
item-value="key"
variant="outlined"
></v-select>
</v-container>
<BrowseThemes :selectedTheme="selectedThemeKey ?? ''" :selectedAge="selectedAgeKey ?? ''"/>
</div>
</template>
<style scoped></style>
<style scoped>
.main-container {
min-height: 100vh;
min-width: 100vw;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
}
.title {
max-width: 50rem;
margin-left: 1rem;
margin-top: 1rem;
text-align: center;
display: flex;
justify-content: center;
}
.dropdowns {
display: flex;
justify-content: space-between;
gap: 5rem;
width: 80%;
}
.v-select {
flex: 1;
min-width: 100px;
}
@media (max-width: 768px) {
.main-container {
padding: 1rem;
}
}
@media (max-width: 700px) {
.dropdowns {
flex-direction: column;
gap: 1rem;
width: 80%;
}
}
</style>